Tournaments & Competitions
Overview
A comprehensive tournament management system supporting multiple formats, scoring types, series aggregation, and integrated tee sheet management.
Status: Feature Complete (Mobile + Web)
Backend services, admin UI, and end-user UI are production-ready. Mobile app ships full tournament experience: list/detail, entry/withdraw, leaderboard, draw view, and live scoring. Web has public leaderboard viewing. Only marker attestation on mobile remains admin-gated.
Recent Enhancements (Dec 2025)
- Security: Added JWT guards to entry/withdraw endpoints with scorecard ownership validation
- Leaderboard: Added live leaderboard tab in mobile TournamentView + dedicated TournamentLeaderboardView screen
- Draw View: Added player-facing draw tab showing tee times, starting holes, and playing groups
- Web Leaderboard: Added
/tournament?id=...page for public leaderboard viewing - Player Highlighting: Current player is highlighted in draw view with visual distinction
- Live Scoring: ScorecardView with hole-by-hole entry, NR/Pick Up toggles, save/submit workflow
Features
Competition Management
- Lifecycle: DRAFT → OPEN → CLOSED → IN_PROGRESS → COMPLETED → CANCELLED
- Formats:
- Stroke Play (Gross/Net)
- Stableford
- Matchplay (brackets)
- Fourball Better Ball
- Team Stableford
- Divisions: Handicap/gender/age restrictions
- Rounds: Multiple rounds per competition with course layout & PCC
Entry Management
- Player registration with handicap snapshot capture
- Entry fees configuration (minor units stored on competition with ISO-4217 currency code; defaults from club region when omitted)
- Division assignment
Draw Generation
- Multiple sorting strategies: handicap, random, entry order
- Tee time allocation with tee sheet sync
- Draw manipulation: swap, move, lock positions
- Group sizing configuration
Scoring
- Scorecard entry with hole-by-hole input
- Marker attestation workflow (review/dispute)
- Results calculation with countback ordering
- Leaderboard generation with live updates
- CSV export for results
Matchplay
- Bracket creation and seeding
- Match-by-match result entry
- Automatic advancement
Series (Order of Merit)
- Multiple aggregation types: total points, best N, average
- Series standings with recalculation
- Winter League support
- Cross-competition linking
Side Competitions
- Nearest pin tracking (distance + unit)
- Longest drive tracking
- 2's Club (gross 2 on par 3s)
Prize Management
- Prize templates
- Auto-allocation (percentage/fixed distribution)
- Prize pool configuration
- Multiple prize categories
Appeals
- Scoring disputes
- Rules violations
- Disqualification appeals
- Admin review workflow
Data Model
Core Tables
Competition
├── id, clubId, seasonId
├── name, description, status
├── format (STROKE_GROSS, STROKE_NET, STABLEFORD, MATCHPLAY, etc.)
├── maxEntries, entryFee, entryFee9Holes, currencyCode
├── entryOpens, entryCloses
└── settings (JSON)
Round
├── competitionId
├── roundNumber
├── date
├── courseLayoutId
└── pcc (Playing Conditions Calculation)
Division
├── competitionId
├── name
├── handicapMin, handicapMax
├── gender, ageMin, ageMax
└── maxEntries
Entry
├── competitionId, divisionId
├── playerId
├── handicapIndex, playingHandicap
├── status (REGISTERED, CONFIRMED, WITHDRAWN, DNS, DQ)
└── entryFeeStatus
Scorecard
├── entryId, roundId
├── status (DRAFT, SUBMITTED, ATTESTED, DISPUTED)
├── grossScore, netScore, points
└── holeScores (JSON array)
Result
├── competitionId, entryId
├── position, tied
├── totalGross, totalNet, totalPoints
└── countback (JSON)
Series Tables
Series
├── id, tenantId, clubId
├── name, aggregationType
├── startDate, endDate
└── settings
SeriesCompetition (junction)
├── seriesId, competitionId
├── pointsMultiplier
└── included
Matchplay Tables
MatchplayBracket
├── competitionId
├── bracketType (SINGLE_ELIM, DOUBLE_ELIM)
└── seeding
MatchplayMatch
├── bracketId
├── round, matchNumber
├── player1EntryId, player2EntryId
├── winnerId
└── holeByHoleResults (JSON)
API Endpoints
Competitions
| Method | Endpoint | Description |
|---|---|---|
| GET | /competitions?clubId=... | List competitions for a club |
| POST | /competitions | Create competition (admin) |
| GET | /competitions/:id | Get competition details |
| PUT | /competitions/:id | Update competition |
| POST | /competitions/:id/publish | Open for entries |
| POST | /competitions/:id/cancel | Cancel competition |
| POST | /competitions/:id/finalize | Finalize results |
| POST | /competitions/:id/results/recalculate | Recalculate standings |
Entries
| Method | Endpoint | Description |
|---|---|---|
| GET | /competitions/:id/entries | List entries |
| POST | /competitions/:id/entries | Register entry |
| GET | /competitions/entries/:entryId | Entry details |
| POST | /competitions/entries/:entryId/withdraw | Withdraw entry |
Draws
| Method | Endpoint | Description |
|---|---|---|
| GET | /competitions/:id/draw | Get competition draw (authenticated, player-scoped) |
| POST | /competitions/:id/draw | Generate draw |
| DELETE | /competitions/rounds/:id/draw | Delete draw |
| POST | /competitions/rounds/:id/draw/swap | Swap positions |
| POST | /competitions/rounds/:id/draw/move | Move player |
| POST | /competitions/rounds/:id/draw/lock | Lock position |
Scoring
| Method | Endpoint | Description |
|---|---|---|
| GET | /competitions/rounds/:roundId/scorecards | List scorecards |
| GET | /competitions/scorecards/:id | Scorecard detail |
| PUT | /competitions/scorecards/:id | Update scorecard |
| POST | /competitions/scorecards/:id/attest | Marker attestation |
| POST | /competitions/scorecards/:id/lock | Lock scorecard |
| POST | /competitions/scorecards/:id/unlock | Unlock scorecard |
| GET | /competitions/:id/leaderboard | Get leaderboard |
| GET | /competitions/:id/leaderboard.csv | Export leaderboard CSV |
| GET | /competitions/:id/stats | Competition stats |
Admin UI
Location: apps/teetime/teetime-admin/src/app/tournaments/
Components
TournamentList- Competition listing with filtersTournamentDetail- Create/edit competitionScoringConsole- Live scoring interfaceTournamentSeries- Series managementTournamentCalendar- Calendar view
Routes
/tournaments - List
/tournaments/new - Create
/tournaments/:id - View/Edit
/tournaments/:id/scoring - Scoring console
/tournaments/calendar - Calendar view
/tournaments/series/:id - Series management
End-User UI/UX Status
Mobile (TeeTime)
- TournamentView: list + detail + entry/withdraw + leaderboard tab + draw tab (
libs/ui/tee-time-ui-mobile/src/lib/screens/main-screens/TournamentView.tsx). - TournamentLeaderboardView: Dedicated full-screen leaderboard with format-aware scoring.
- Draw Tab: Shows round pairings with tee times, starting holes, player names, and handicaps. Current player is highlighted.
- ScorecardView: Hole-by-hole score entry with NR/Pick Up toggles, save/submit flow, and attestation display (
libs/ui/tee-time-ui-mobile/src/lib/screens/main-screens/ScorecardView.tsx). - Pending: Marker attestation flow on mobile (players can submit, but attestation still admin-only).
Web (TeeTime)
- TournamentLeaderboardPage: Public leaderboard viewing at
/tournament?id=...(libs/tee-time-ui/src/lib/pages/TournamentLeaderboardPage.tsx). - Pending: Tournament detail/entry page for web (players must use mobile app for entry/withdraw).
Integration Points
- Tee Sheet Sync: Competitions auto-create tee times
- Handicap Service: Snapshot capture at entry
- Association Providers: GolfRSA/DotGolf handicap lookup
- Notifications: Entry confirmations, draw notifications
Future Enhancements
- Online entry by players (mobile app - Dec 2025)
- Player-facing leaderboard (mobile + web - Dec 2025)
- Player-facing draw view (mobile - Dec 2025)
- Live scoring mobile app (ScorecardView - Dec 2025)
- Mobile marker attestation flow (currently admin-only)
- Broadcast integration (TV graphics)
- Handicap posting to external systems
- GPS-based distance display per hole (backend + admin import + mobile card wired; data coverage pending)
- Casual round scoring (non-competition rounds)