Real-time fantasy sports backend
REST APIs, MongoDB, external sports feeds, and Socket.IO provide live fantasy and gaming functions.
Context
Problem
Fantasy and gaming products needed shared lobby state, sports-data ingestion, and user-facing game flows that changed as live data changed.
Constraints
- A five-player lobby had to keep membership and player selection consistent for every connected client.
- Public and private lobbies had to support joins, departures, and roster updates.
- Teams, scores, and fixtures depended on external basketball and sports APIs.
System
Architecture
- 01
External sports APIs
- 02
REST services
- 03
MongoDB game state
- 04
Socket.IO lobby state
- 05
Fantasy and prediction clients
My role
Owned API design, MongoDB schemas, WebSocket state flows, sports-data integrations, debugging, and documentation.
Decisions
- Used explicit REST contracts for persistent workflows and Socket.IO for shared lobby state.
- Documented public APIs with OpenAPI and added validation and error handling.
Validation
What failed
- Socket.IO was attached to the HTTP server, but Express initially used app.listen. Socket events did not reach clients until the service used server.listen.
- Lobby updates initially used one shared event name. A later change used the lobby ID as the event name so each client could subscribe to its own lobby updates.
Tests and checks
- Squad creation rejected a captain who already belonged to another squad.
- Squad updates rejected duplicate membership and refused additions after five users.
- Lobby creation required a complete five-user squad before player choices could be stored.
- Each choice was written to the player's position in the lobby and emitted under the lobby-specific event name.
Outcome
Result
The APIs supported public and private five-player lobbies, roster changes, player selection, shared game state, teams, scores, fixtures, and predictions.
Limits
Squad joins checked membership and capacity before saving the updated document. Concurrent joins were not protected by a transaction or a conditional database update.
What I would change today
Use one conditional database update for squad joins and authenticated Socket.IO rooms for lobby broadcasts.