Backend2025

Mon5MajeurNBA Fantasy Basketball Backend

A Django backend for an NBA fantasy basketball platform with budget-based player selection, private, public, and global competitions, scheduled GoalServe data ingestion, and league-scoped WebSocket events.

Primary technologies

  • Django REST Framework
  • Django Channels
  • Celery
  • Redis
  • PostgreSQL
  • Docker
  • AWS
Mon5Majeur marketing site: an NBA fantasy hero with the mobile app shown in hand

What this project is

Mon5Majeur supports NBA fantasy competitions where users build teams of up to five players within a league budget and compete across private, public, or automatically enrolled global leagues.

Engineering problem

The backend must combine user-managed fantasy competitions with changing external NBA schedules, rosters, injury reports, prices, and box scores while keeping repeated third-party API requests under control.

Success criteria

Provide authenticated APIs for the complete fantasy workflow, ingest current NBA data reliably, calculate match results, and expose standings and daily, weekly, or monthly global rankings.

The repository implements the platform with Django REST Framework, GoalServe integration, layered Redis caching, scheduled Celery tasks, PostgreSQL persistence in production, and Django Channels for league membership and start events.

What I designed, built, and shipped

The areas I owned end to end as Backend Engineer.

  1. Designed REST APIs for authentication, player selection, leagues, matches, standings, and leaderboards

  2. Implemented GoalServe-powered schedules, rosters, injuries, player pricing, and score ingestion with Redis caching and Celery

  3. Containerized the ASGI application and automated Docker Hub delivery and AWS EC2 deployment with GitHub Actions

How the system is structured

  1. Layer 01

    Domain-oriented REST API

    Separate Django apps own accounts, players, league types, match scheduling, scoring, team statistics, and configurable content, with Swagger documentation generated through drf-yasg.

  2. Layer 02

    Cached NBA data pipeline

    GoalServe schedules, rosters, injuries, season statistics, and box scores are normalized into frontend-facing responses and cached in Redis at workload-specific intervals.

  3. Layer 03

    Persistent competition state

    Django models store league membership, daily selections, round-robin pairings, seasons, match scores, playoff qualification, and aggregate global ranking metadata.

Key technical decisions

League types modeled separately

Private leagues use invitation codes, public leagues are joinable by identifier, and a singleton global league automatically enrolls every newly created user profile.

Server-enforced selection rules

Selection serializers cap rosters at five players and validate submitted prices against configurable private, public, or global league budgets before persisting picks.

Scheduled cache warming

Celery tasks refresh the NBA schedule and player pool hourly and populate the current day's score cache every five minutes to reduce request-time work and external API traffic.

Technology stack

Backend

  • Python 3.12
  • Django 5
  • Django REST Framework

Authentication and real time

  • Simple JWT
  • Django Channels
  • Channels Redis

Data and background processing

  • PostgreSQL
  • Redis
  • Celery

Delivery and operations

  • Docker Compose
  • GitHub Actions
  • AWS EC2 · S3
  • Gunicorn · Uvicorn

What the system does

Fantasy player market

Builds the available player pool from the day's NBA games, includes injury status, and derives prices between 5M and 25M from weighted season performance.

Three competition modes

Supports invitation-code private leagues, open public leagues, and a global daily competition with automatic account enrollment.

Matches and rankings

Provides round-robin pairing, match-day selections, standings, playoff qualifiers, winners, and daily, weekly, or monthly global leaderboards.

League event channels

JWT-aware WebSocket routes broadcast join, leave, kick, and league-start events only to the affected private or public league group.

Challenges & solutions

Challenge 01

Normalizing inconsistent sports feeds

Problem

GoalServe responses can represent the same collection as either a single object or a list and expose player statistics through several field aliases.

Solution

Dedicated utility functions normalize collection shapes, dates, player identifiers, stat aliases, roster locations, and missing values before returning stable API data.

Challenge 02

Coordinating fantasy competition state

Problem

League membership, scheduled NBA game days, player-selection deadlines, head-to-head pairings, and final rankings must remain aligned.

Solution

Service-layer scheduling generates round-robin match days and playoff qualification records, while match statuses prevent selection changes after play becomes active.

What was delivered

  1. Delivered a modular API spanning authentication, fantasy rosters, three league modes, match scheduling, scoring, and rankings.

  2. Reduced repeated GoalServe requests through Redis caching, request retries, negative caching, and scheduled background refreshes.

  3. Established a production path that builds and publishes Docker images, deploys them to AWS EC2, restarts Nginx, and stores production static and media assets in S3.

What I took away

  1. External sports feeds require defensive normalization because dates, collection shapes, and statistic names are not always consistent.

  2. Separating durable match state, scheduled data ingestion, cached live data, and scoped league events keeps the fantasy workflow easier to operate and extend.

Next step

Building something that needs this kind of backend?

I take on backend, API, and DevOps work — from data modelling and REST design through containerization and production deployment.

A project case study by Md Fahad MirBackend & DevOps Engineer, Dhaka, Bangladesh.