A full-stack TypeScript application for managing and analyzing basketball player prop markets, backed by a MySQL database and exposed via a REST API.
Player Market Stats is a monorepo containing:
- A Node.js + Express backend (TypeScript)
- A React + Vite frontend (TypeScript)
- A MySQL database (Dockerized)
The system models player statistics markets (e.g., points, assists, rebounds) and provides filtering, querying, and suspension controls for betting-style market lines.
- π Player prop market management
- π Advanced filtering (position, stat type, suspension status, search)
- π Manual suspension toggling for markets
- π Alternate lines with odds
- ποΈ Strong relational schema (MySQL)
- π³ Dockerized database setup
- β‘ Full TypeScript stack
- π§ͺ Unit & integration testing (Jest)
playermarketstats/
β
βββ client/ # React frontend (Vite + TS)
β βββ src/
β βββ package.json
β
βββ server/ # Express backend (TypeScript)
β βββ src/
β β βββ index.ts # Server entry point
β β βββ routes/ # Express route handlers
β β βββ services/ # Business logic (MarketService)
β β βββ scripts/ # migrate.ts, seed.ts
β βββ dist/ # Compiled output
β βββ package.json
β
βββ docker-compose.yml # MySQL container config
βββ init.sql # Database schema + seed data
β
βββ package.json # Root scripts
βββ README.md
- Node.js
- TypeScript
- Express
- MySQL (mysql2)
- React 18
- TypeScript
- Vite
- Axios
- React Router
- MySQL (Dockerized)
- Jest
players (1) ββββββββ< (β) markets >ββββββββ (1) stat_types
β β
β βββββββββββββββ< alternates (β)
β
βββββββββββββββββββββ< alternates (β)
- A player has many markets
- A stat_type applies to many players
- A market is uniquely identified by
(player_id, stat_type_id) - A player has many alternate lines
- Alternates extend the primary market with odds
- Player metadata (team, position, etc.)
- points, assists, rebounds, steals
- Primary betting line
- Includes suspension flags
- Unique per
(player_id, stat_type_id)
-
Alternate lines with:
under_oddsover_oddspush_odds
-
Seed Data
- Players and stat types initialized
-
Market Creation
- One base line per player/stat type
-
Filtering Layer
-
Markets filtered by:
- Position
- Stat type
- Suspension status
- Text search
-
-
Suspension Logic
market_suspendedβ automaticmanual_suspensionβ override flag
-
Aggregation
- Markets joined with player + stat metadata
- Returned as
MarketWithDetails
Base URL: /api/markets
Returns available filter values derived from market data.
{
"success": true,
"data": {
"positions": ["G", "F", "C"],
"statTypes": ["points", "assists"],
"suspensionStatuses": ["suspended", "active"]
}
}Fetch markets with filtering.
| Param | Type | Description |
|---|---|---|
| position | string | Filter by player position |
| statType | string | Filter by stat type |
| suspensionStatus | string | "active" or "suspended" |
| search | string | Search player name |
/api/markets?position=G&statType=points&search=lebron
{
"success": true,
"data": [...],
"count": 25
}Update manual suspension status.
{
"suspended": true
}- Calls:
marketService.updateManualSuspension - Currently marked as candidate task / partially implemented
- Returns
501if not implemented
git clone https://github.com/mpokumt/playermarketstats.git
cd playermarketstats
npm run setupnpm run devcd server && npm run dev
cd client && npm run devnpm run migrate
npm run seednpm run docker:up
npm run docker:down
npm run docker:verifyThe app will be available at:
- Frontend: http://localhost:3000
- Backend API: http://localhost:3001
- Health check: http://localhost:3001/health
[ React Client ] ---> [ Express API ] ---> [ MySQL ]
β β
β βββ MarketService (business logic)
βββ Axios requests
npm testServer:
cd server && npm run testClient:
cd client && npm run testOpen an issue on GitHub for questions or suggestions.
Port Requirements:
- Ports
3000,3001, and3306must be available - If you have MySQL running locally, stop it first:
brew services stop mysql(macOS) or stop the MySQL service (Windows)
- "Docker not found": Ensure Docker Desktop is installed and running
- "Port 3306 already in use": Stop local MySQL:
- macOS:
brew services stop mysql - Windows: Stop MySQL service in Services app
- Linux:
sudo systemctl stop mysql
- macOS:
- "Cannot connect to Docker daemon": Start Docker Desktop application
- Container fails to start: Try
npm run docker:downthennpm run docker:up
- "Connection refused": MySQL container is still initializing (setup script waits automatically up to 30 seconds)
- "Seeding failed": Ensure
props.jsonandalternates.jsonexist indatabase/folder - "Migration failed": Try
npm run docker:down && npm run docker:upto reset database
- Frontend (3000) conflict: Change port in
client/vite.config.ts - Backend (3001) conflict: Set
PORT=3002in.envfile - MySQL (3306) conflict: Update
DB_PORTin.envanddocker-compose.yml
- "Module not found": Run
npm run install:allto install dependencies - TypeScript errors: Check Node.js version (must be 16+)
- Blank page: Check browser console and network tab for errors
- API not working: Verify backend is running at http://localhost:3001/health
- Try a clean restart:
npm run docker:down && npm run setup && npm start - Check all prerequisites are installed and running
- Verify no other services are using ports 3000, 3001, 3306