The operational app for running badminton sessions end to end — planning, scheduling, live scoring, tournaments, and social export.
- Configure courts, time slots, player count, and game duration
- Define fixed-match constraints with time & court pinning
- Generate balanced doubles schedules with quality analysis
- Retry generation for optimal partner/opponent distribution
- Publish sessions and share via URL
- Mark games played, enter/revise scores
- Swap players, teams, and game slots
- Change individual players in specific games
- Mark players absent (excluded from leaderboard)
- Lock session to prevent further edits
- Browse historical sessions
- Per-player career stats (W/L, points, partners, opponents)
- Real-time leaderboard with on-the-fly computation
- 16 pairs → 4 groups → round-robin → knockout bracket
- Automatic bracket propagation
- Match PIC assignment
- Scoreboard overlay
- Instagram-style post & story graphics (1080×1350 / 1080×1920)
- Leaderboard export (absent players filtered)
- Tournament bracket & standings visuals
| Layer | Technology |
|---|---|
| Framework | React 19 + TypeScript 6 |
| Build | Vite 8 |
| Styling | Tailwind CSS v4 |
| State | Zustand (local) + TanStack React Query (server) |
| Routing | React Router v7 |
| Backend | Supabase (PostgreSQL + PostgREST RPC) |
| PWA | vite-plugin-pwa |
| DnD | @dnd-kit/core |
npm cicp .env.local.example .env.local
# Fill in VITE_SUPABASE_URL and VITE_SUPABASE_KEYApply the SQL migrations from supabase/migrations/ to your Supabase project.
npm run dev# Static checks (types + lint + tailwind + regression)
npm run check
# Supabase smoke tests
source .env.local && npm run check:smokesrc/
├── components/ # Shared UI components (SummaryModal, ShareButton, etc.)
├── config/ # Instagram template configs
├── generator/ # Schedule generation algorithm (pure TS)
├── hooks/ # Custom React hooks
├── pages/ # Route pages (Setup, Players, Generate, etc.)
├── queries/ # React Query hooks + Supabase RPC endpoints
├── store/ # Zustand stores (session, tournament)
└── utils/ # Utility functions (swap, standings, canvas, etc.)
| RPC | Access | Notes |
|---|---|---|
publish_session |
anon | Rejects writes when status ≠ 'draft' |
get_session |
anon | Read-only |
list_sessions |
anon | Returns lock status |
delete_session |
anon | Rejects deletion of locked sessions |
unlock_session |
service_role | Admin-only, not in UI |
register_player |
anon | Idempotent with TOCTOU fix |
- Handbook — Start here
- Current Status — Latest state
- Architecture — System design
- Data Model — Schema & types
- Features & Routes — Feature map
- Roadmap — What's next
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Local State │ ←→ │ Domain Logic │ ←→ │ Remote State │
│ (Zustand) │ │ (Generator/Utils)│ │ (Supabase) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
↓ ↓ ↓
localStorage Pure Functions PostgREST RPC
| App | Role |
|---|---|
| Majadu App | Operations — session planning, live control, tournaments |
| MDEF | Analytics — canonical players, match history, ratings |
Private project.