Skip to main content

TeeTime Tournament Management Admin UI — Product Spec

Status: Draft · Owners: TeeTime Eng · Last Updated: 2025-12-10 Implementation snapshot: Core lifecycle, draw, scoring, leaderboard, matchplay, side comps, prizes, series, appeals, notifications, and handicap posting are implemented in teetime-admin. Remaining UX polish: richer create wizard (association mapping/CSS templates), division templates/assignment modes, and projector/shotgun visuals (partially delivered).

Comprehensive admin workspace for tournament operations: create competitions, manage entries, generate draws, live scoring, and results management.


Quick Orientation

  • Purpose: Give club administrators full control over tournament lifecycle—from creation through finalization.
  • Audience: Tournament directors, club ops, scorers, and handicap committees.
  • Backend Status: Comprehensive tournament services already implemented in @digiwedge/tee-time-services/tournaments. This spec defines the Admin UI layer.
DocumentDescription
Tournament Backend DocsService documentation with API reference
Tee Sheet ManagementIntegration with tee sheet grid
Tournament WireframesUI wireframes for tournament screens

Experience Principles

  • Guided creation: Wizard-style competition setup with sensible defaults and format-specific configuration.
  • Live leaderboard: Real-time scoring updates with position changes highlighted.
  • Draw flexibility: Multiple draw methods with manual override capability.
  • WHS compliance: Automatic handicap capture, CSS/PCC calculation, and association posting.
  • Audit confidence: Complete scoring history with attestation workflow.

Personas & Core Jobs

PersonaKey JobsSuccess Signal
Tournament DirectorCreate competitions, configure rules, finalize resultsSmooth setup, no scoring disputes
Club AdminManage entries, generate draws, assign tee timesFull field, balanced groups
ScorerEnter hole-by-hole scores, attest scorecardsFast entry, no data loss
Handicap CommitteeReview results, resolve appeals, post to associationCompliant posting, resolved appeals

Primary Navigation

Tournaments (main nav)
├── Calendar View (upcoming/past)
├── Active Competitions
├── Series / Order of Merit
└── Prize Templates

Competition Detail Surfaces

SurfacePurposeStates
Competition OverviewSummary, status, quick actionsDraft, Open, In Progress, Completed
Entries ListPlayer entries, divisions, team membersEntered, Withdrawn
Draw & PairingsGenerated draw, manual adjustmentsNot Generated, Generated, Locked
Live LeaderboardReal-time positions, scores, thruIn Progress, Final
Scoring ConsoleHole-by-hole entry, scorecard viewPending, In Progress, Attested, Locked
Results & PrizesFinal positions, prize allocation, exportDraft, Finalized
Matchplay BracketBracket visualization, match scoringSeeded, In Progress, Complete

Scope

In Scope

AreaDescription
Competition CRUDCreate, edit, delete competitions with all configuration
10 Competition FormatsStableford, Stroke, Matchplay, 4BBB, Foursomes, Greensome, Scramble, Texas Scramble, Ambrose, Par/Bogey
Entry ManagementPlayer entries, divisions, team events, withdrawals
Handicap IntegrationSnapshot capture, WHS compliance, association posting
Draw GenerationRandom, handicap order, seeded, tee-time order draws
Shotgun StartsMulti-hole simultaneous starts
Live ScoringHole-by-hole entry, real-time leaderboard
Scorecard WorkflowEntry → Attestation → Lock → Post
Countback ResolutionAutomatic tie-breaking per WHS rules
Matchplay BracketsKnockout tournaments, seeding, hole-by-hole match scoring
Side CompetitionsNearest pin, longest drive, 2's club
Series/OoMOrder of Merit across multiple events
Prize ManagementTemplates, allocation, prize pools
Appeals WorkflowOpen, review, resolve scoring disputes
CSV/PDF ExportLeaderboards, draws, starter sheets
Tee Sheet IntegrationLink rounds to tee sheets, sync bookings to entries

Out of Scope

  • Player-facing scoring app (separate mobile app)
  • Payment processing for entry fees
  • Real-time GPS tracking during rounds
  • External tournament systems integration (USGA GHIN, etc.)

Fees scope alignment: entryFee and entryFee9Holes are collected for display/export only. No payment, invoicing, or wallet settlement flows are covered here; collection occurs offline or via separate billing modules.


Competition Lifecycle

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ CREATE │───▶│ ENTRIES │───▶│ DRAW │───▶│ SCORING │
│ (Draft) │ │ (Open) │ │ (Generated) │ │(In Progress)│
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

┌─────────────┐ ┌─────────────┐ │
│ COMPLETED │◀───│ FINALIZE │◀─────────┘
│ (Posted) │ │ (Results) │
└─────────────┘ └─────────────┘

Status Definitions

StatusDescriptionAllowed Actions
DRAFTCompetition created, not open for entriesEdit all settings, Delete
OPENAccepting entriesAdd/edit entries, Generate draw
IN_PROGRESSScoring underwayScore entry, View leaderboard
COMPLETEDResults finalized, handicaps postedExport, View results, Appeals
CANCELLEDCompetition cancelledArchive

Capability Highlights

Competition Formats

FormatTypeScoringPlayers
StablefordIndividualPoints (higher better)1
Stroke/MedalIndividualNet strokes (lower better)1
Par/BogeyIndividual+/- vs par1
MatchplayIndividualHoles won/lost1v1
Four-Ball Better BallTeamBetter ball points2
FoursomesTeamAlternate shot2
GreensomeTeamBest drive + alternate2
ScrambleTeamBest shot2-4
Texas ScrambleTeamBest shot + min drives4
AmbroseTeamScramble + team handicap2-4

Division System

Automatic or manual division assignment based on:

  • Handicap index range (e.g., 0-12, 13-24, 25+)
  • Gender (Men, Ladies)
  • Age (Juniors, Seniors, Super Seniors)
  • Tee set (Championship, Medal, Forward)

Draw Types

TypeUse CaseAlgorithm
RandomSocial eventsShuffle entries
Handicap OrderClub compsSort by HCP, group
SeededChampionshipsManual seed positions
Tee Time OrderPre-bookedUse existing bookings

Start Types

TypeDescription
Tee TimesSequential from 1st tee
ShotgunAll groups start simultaneously
Two-TeeGroups from 1st and 10th
MixedCombination shotgun + tee times

Key Workflows

1. Create Competition

Competition Wizard:
├── Step 1: Basics (name, format, dates, course)
├── Step 2: Handicap Settings (qualifying, allowance, CSS)
├── Step 3: Divisions (add/edit division rules)
├── Step 4: Entry Settings (fees, limits, windows)
├── Step 5: Rounds (multi-round configuration)
└── Step 6: Review & Publish

2. Entry Management

Entries Panel:
├── Add Entry (search player, select division)
├── Team Entry (captain + team members)
├── Guest Entry (manual handicap override)
├── Linked Entry (from tee time booking)
├── Bulk Import (CSV upload)
└── Withdraw Entry (reason tracking)

3. Draw Generation

Draw Panel:
├── Select Draw Type
├── Configure (group size, start time, interval)
├── Preview Draw
├── Generate
├── Manual Adjustments (swap, move, add late entry)
└── Lock Draw

4. Live Scoring

Scoring Console:
├── Select Round
├── Scorecard Grid (all players)
├── Individual Scorecard Entry
├── Bulk Score Entry (per group)
├── Attest Scorecard
└── Lock Round

5. Results & Finalization

Results Panel:
├── Live Leaderboard (refreshes every 30s)
├── Division Standings
├── Countback Details (for ties)
├── Assign Prizes (from templates)
├── Finalize Results
├── Post to Association (GolfRSA/DotGolf)
└── Export (CSV, PDF)

6. Matchplay Flow

Matchplay Panel:
├── Create Bracket (size: 8/16/32/64)
├── Seed Bracket (auto or manual)
├── View Bracket (interactive visualization)
├── Record Match (hole-by-hole or result only)
├── Advance Bracket
└── Final Result

Admin API Endpoints

Status Legend

TagMeaning
✅ AvailableImplemented in backend
🧭 RequiredAdmin UI adapter needed
🔒 AdminImplemented and protected by teetime-admin audience

Competition Management

StatusMethodPathDescription
GET/api/competitionsList competitions
POST/api/competitionsCreate competition
GET/api/competitions/:idGet competition detail
PUT/api/competitions/:idUpdate competition
DELETE/api/competitions/:idDelete competition
🔒POST/api/competitions/:id/publishOpen for entries
🔒POST/api/competitions/:id/cancelCancel competition

Entry Management

StatusMethodPathDescription
GET/api/competitions/:id/entriesList entries
POST/api/competitions/:id/entriesCreate entry
🔒POST/api/competitions/:id/entries/bulkBulk import entries
GET/api/competitions/entries/:entryIdGet entry detail
POST/api/competitions/entries/:entryId/withdrawWithdraw entry
🔒POST/api/competitions/admin/rounds/:id/sync-tee-sheetAdmin sync from tee sheet

Draw & Pairings

StatusMethodPathDescription
🔒POST/api/competitions/rounds/:roundId/drawGenerate draw
GET/api/competitions/rounds/:roundId/drawGet draw
🔒DELETE/api/competitions/rounds/:roundId/drawClear draw
🔒POST/api/competitions/rounds/:roundId/draw/swapSwap players
🔒POST/api/competitions/rounds/:roundId/draw/moveMove player
🔒POST/api/competitions/rounds/:roundId/draw/lockLock draw

Scoring

StatusMethodPathDescription
GET/api/competitions/rounds/:roundId/scorecardsList scorecards
GET/api/competitions/scorecards/:idGet scorecard
PUT/api/competitions/scorecards/:idUpdate scores
POST/api/competitions/scorecards/:id/attestAttest scorecard
🔒POST/api/competitions/scorecards/:id/lockLock scorecard
🔒POST/api/competitions/scorecards/:id/unlockUnlock (admin)

Scorecard update (hole payload)

PUT /api/competitions/scorecards/:id
{
"holes": [
{ "holeNumber": 1, "grossStrokes": 4, "putts": 2 },
{ "holeNumber": 2, "grossStrokes": 5, "isNoReturn": false }
]
}

Scorecard attestation

POST /api/competitions/scorecards/:id/attest
{
"markerId": "player-456",
"confirmation": "ATTESTED",
"disputeReason": null
}

Leaderboard & Results

StatusMethodPathDescription
GET/api/competitions/:id/leaderboardGet leaderboard
GET/api/competitions/:id/leaderboard.csvExport CSV
🔒POST/api/competitions/:id/finalizeFinalize results
GET/api/competitions/:id/statsCompetition stats
🔒POST/api/competitions/:id/results/recalculateRecalculate

Payload reference

Finalize results

POST /api/competitions/:id/finalize
{
"applyCountback": true,
"assignPrizes": false
}
  • Applies countback ordering before persisting competitionResult.
  • Optionally triggers prize auto-allocation when a prize pool/template exists.

Competition stats (response)

GET /api/competitions/:id/stats
{
"competitionId": "comp-123",
"entriesTotal": 120,
"entriesWithdrawn": 3,
"entriesCompleted": 118,
"averageGross": 82.4,
"averageNet": 70.8,
"averageStableford": 33.1,
"lowestGross": 71,
"lowestNet": 66,
"highestStableford": 41,
"css": 71,
"pcc": 1,
"pccByRound": [
{ "roundId": "r1", "pcc": 1, "source": "MANUAL" }
]
}

Matchplay

StatusMethodPathDescription
POST/api/competitions/:id/matchplay/bracketsCreate bracket
POST/api/competitions/:id/matchplay/brackets/seedSeed bracket
GET/api/competitions/:id/matchplay/brackets/:bracketIdGet bracket
POST/api/competitions/:id/matchplay/matches/:matchId/holesRecord holes
POST/api/competitions/:id/matchplay/brackets/:bracketId/advanceAdvance bracket

Side Competitions

StatusMethodPathDescription
GET/api/competitions/:id/nearest-pinGet NTP results
POST/api/competitions/:id/nearest-pinRecord NTP
GET/api/competitions/:id/longest-driveGet LD results
POST/api/competitions/:id/longest-driveRecord LD
GET/api/competitions/:id/twos-clubGet 2's club

Prizes & Appeals

StatusMethodPathDescription
POST/api/competitions/:id/prizesAssign prizes
GET/api/competitions/clubs/:clubId/prize-templatesList templates
POST/api/competitions/:id/prize-pool/apply-templateApply template
POST/api/competitions/:id/appealsOpen appeal
GET/api/competitions/:id/appealsList appeals
POST/api/competitions/appeals/:appealIdUpdate appeal

Series (Order of Merit)

StatusMethodPathDescription
POST/api/competitions/seriesCreate series
GET/api/competitions/series/:seriesIdGet series
GET/api/competitions/series/:seriesId/standingsGet standings
POST/api/competitions/series/:seriesId/linkLink competition
POST/api/competitions/series/:seriesId/recalculateRecalculate

Access Control & Audit

ActionRole RequirementAudit Notes
Create/Edit/Delete competitionTournament Director or Club AdminLog user and timestamp
Publish/Cancel competitionTournament DirectorCapture status change + reason
Generate/Lock/Unlock drawTournament DirectorInclude before/after pairing snapshot hash
Add/Withdraw entriesClub AdminCapture withdraw reason where provided
Score entry/attest scorecardScorer (scoring role)Log hole updates and attestation user
Lock/Unlock scorecardTournament DirectorUnlock requires reason
Finalize resultsTournament Director + Handicap Committee confirmationRecord countback applied + prize assignment flag
Post handicapsHandicap CommitteeStore provider + submission id
Appeals create/updateTournament Director or Handicap CommitteeRecord resolution outcome

All admin endpoints tagged 🔒 require the teetime-admin audience plus the mapped role above. Audit events should be emitted to the existing admin audit stream.


Data Models

Competition

interface Competition {
id: string;
clubId: string;
name: string;
description?: string;
format: CompetitionFormat;
status: 'DRAFT' | 'OPEN' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';

// Handicap settings
isHandicapQualifying: boolean;
handicapAllowance: number; // 0-100 percentage
handicapPostingMode: 'AUTO' | 'MANUAL' | 'NONE';

// Team settings
isTeamEvent: boolean;
teamSize?: number;

// Entry settings
maxEntries?: number;
entryFee?: number; // In cents
entryFee9Holes?: number;
entryOpens?: Date;
entryCloses?: Date;

// Relations
rounds: CompetitionRound[];
divisions: CompetitionDivision[];
eligibility?: EligibilityConfig;
localRules?: LocalRule[];

// Metadata
seasonId?: string;
seriesIds?: string[];
createdAt: Date;
updatedAt: Date;
}

type CompetitionFormat =
| 'STABLEFORD'
| 'STROKE'
| 'PAR_BOGEY'
| 'MATCHPLAY'
| 'FOUR_BALL_BETTER_BALL'
| 'FOURSOMES'
| 'GREENSOME'
| 'SCRAMBLE'
| 'TEXAS_SCRAMBLE'
| 'AMBROSE';

CompetitionRound

interface CompetitionRound {
id: string;
competitionId: string;
roundNumber: number;
date: Date;
courseId: string;
courseName?: string;

// Start configuration
startType: 'TEE_TIMES' | 'SHOTGUN' | 'TWO_TEE' | 'MIXED';
shotgunTime?: Date;
startingHoles?: number[];

// Draw settings
drawType?: 'RANDOM' | 'HANDICAP_ORDER' | 'SEEDED' | 'TEE_TIME_ORDER';
groupSize?: number;
intervalMinutes?: number;
drawLocked: boolean;

// Tee sheet link
teeSheetId?: string;

// 9-hole support
isNineHole: boolean;
holesInPlay: number;
}

CompetitionEntry

interface CompetitionEntry {
id: string;
competitionId: string;
playerId: string;
playerName: string;
divisionId?: string;

// Status
enteredAt: Date;
withdrawnAt?: Date;
withdrawalReason?: string;

// Handicap
handicapSnapshot: HandicapSnapshot;
handicapIndexOverride?: number;

// Team
teamName?: string; // Optional custom name for team events
teamMembers?: TeamMember[];

// Tee sheet link
teeTimeSlotId?: string;

// Pairing (after draw)
pairingNumber?: number;
teeTime?: Date;
startingHole?: number;
}

Scorecard

interface Scorecard {
id: string;
entryId: string;
roundId: string;
status: 'PENDING' | 'IN_PROGRESS' | 'ATTESTED' | 'LOCKED';

// Totals
grossTotal?: number;
netTotal?: number;
stablefordPoints?: number;

// Handicap applied
courseHandicap: number;
playingHandicap: number;

// Scores
holes: HoleScore[];
countback?: CountbackScores;

// Attestation
attestedAt?: Date;
attestedBy?: string;
lockedAt?: Date;
}

interface HoleScore {
holeNumber: number;
par: number;
strokeIndex: number;
grossStrokes?: number;
netStrokes?: number;
stablefordPoints?: number;
isNoReturn: boolean;
}

MatchplayBracket

interface MatchplayBracket {
id: string;
competitionId: string;
name: string;
size: 4 | 8 | 16 | 32 | 64;
currentRound: number;
status: 'PENDING' | 'SEEDED' | 'IN_PROGRESS' | 'COMPLETED';
matches: MatchplayMatch[];
}

interface MatchplayMatch {
id: string;
bracketId: string;
round: number;
position: number;
entry1Id?: string;
entry2Id?: string;
winnerId?: string;
status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED';
result?: string; // "3&2", "1 up", "19th"
holes: MatchplayHole[];
}

Prize Templates & Allocation

interface PrizeTemplate {
id: string;
clubId: string;
name: string;
currency: string;
lines: PrizeTemplateLine[];
}

interface PrizeTemplateLine {
positionFrom: number;
positionTo: number;
amount: number; // minor units
divisionId?: string;
sideCompetition?: 'NEAREST_PIN' | 'LONGEST_DRIVE' | 'TWOS';
}

interface PrizeAllocation {
competitionId: string;
entryId: string;
prizeName: string;
amount: number; // minor units
currency: string;
position: number;
divisionId?: string;
sourceTemplateId?: string;
}

Side Competitions

interface SideCompetitionResult {
id: string;
competitionId: string;
type: 'NEAREST_PIN' | 'LONGEST_DRIVE' | 'TWOS';
roundId: string;
holeNumber: number;
entryId: string;
distanceFeet?: number; // NTP
driveYards?: number; // LD
recordedAt: Date;
}

Appeals

interface Appeal {
id: string;
competitionId: string;
scorecardId?: string;
entryId?: string;
status: 'OPEN' | 'UNDER_REVIEW' | 'RESOLVED' | 'REJECTED';
reason: string;
resolution?: string;
createdBy: string;
createdAt: Date;
updatedAt: Date;
}

Series (Order of Merit)

interface Series {
id: string;
clubId: string;
name: string;
seasonId?: string;
scoringRule: 'POINTS' | 'AVERAGE_POSITION';
competitions: SeriesLink[];
}

interface SeriesLink {
competitionId: string;
weight: number; // multiplier for points
}

interface SeriesStanding {
seriesId: string;
entryId: string;
playerId: string;
points: number;
eventsPlayed: number;
position: number;
}

UI Components

Component Library

Use existing Ant Design components from teetime-admin:

ComponentUsage
TableEntries list, leaderboard, pairings
DrawerEntry form, scorecard entry
ModalConfirmations, prize assignment
FormCompetition wizard, entry forms
StepsCompetition creation wizard
TabsCompetition detail sections
CardCompetition summary, round cards
TagStatus badges, division chips
TreeBracket visualization
CalendarCompetition calendar view
StatisticCompetition stats display
ProgressScoring progress indicators
BadgeLive indicator, update count

Custom Components Needed

ComponentPurpose
BracketVizInteractive bracket visualization
ScorecardGridHole-by-hole score entry grid
LeaderboardRowPosition, player, scores, thru
DrawPreviewVisual draw preview before generation
DivisionAssignerAuto-assign entries to divisions
HandicapBadgeHandicap index with snapshot indicator

Telemetry

Events to Track

EventProperties
tournament.createclubId, format, isTeamEvent
tournament.publishcompetitionId, entryCount
tournament.entry.addcompetitionId, divisionId
tournament.entry.withdrawcompetitionId, reason
tournament.draw.generatecompetitionId, drawType, groupCount
tournament.draw.manual_editcompetitionId, editType
tournament.score.entercompetitionId, roundId, entryId
tournament.scorecard.attestcompetitionId, scorecardId
tournament.results.finalizecompetitionId, entryCount
tournament.handicap.postcompetitionId, provider, count
tournament.matchplay.recordcompetitionId, matchId, result
tournament.appeal.opencompetitionId, reason

Metrics

  • Competition creation → completion rate
  • Average entries per competition
  • Draw generation time
  • Scoring completion rate
  • Time from last score to finalization
  • Handicap posting success rate
  • Appeal resolution time

Decisions & Defaults

  • Live scoring transport: WebSocket channel for score updates and leaderboard deltas; fall back to 30s polling if the socket is unavailable.
  • Multi-round/multi-course: Each CompetitionRound owns its date and courseId; rounds across different days or courses are supported. startingHoles maps shotgun/two-tee layouts.
  • Handicap freshness: Block new entries and tee-sheet sync when the latest handicap snapshot is older than 30 days; prompt admins to refresh.
  • Prize handling: Prize pools and allocations are informational only; no wallet/ledger crediting. Exports and admin audit logs are the source of record.
  • Results communication: On finalize, trigger the existing tournament_results_finalized notification template (email/push/SMS per tenant config); allow per-competition opt-out.
  • Scoring devices: Scoring console must be tablet-friendly (>=1024px) with responsive touch layouts; desktop parity retained.
  • Team naming: Team events may include a teamName; include in entries, leaderboards, and prize exports when present.
  • Season rollover/archive: Competitions auto-archive at season end (read-only, hidden from entry/draw actions) but remain available in history/export views.

Testing

Unit Tests

describe('CompetitionWizard', () => {
it('validates required fields per step');
it('shows format-specific options');
it('calculates entry window defaults');
});

describe('DrawGenerator', () => {
it('generates correct group sizes');
it('respects handicap ordering');
it('handles odd numbers correctly');
});

describe('LeaderboardCalculator', () => {
it('applies countback correctly');
it('handles tied positions');
it('updates positions on new scores');
});

describe('ScorecardEntry', () => {
it('calculates stableford points');
it('validates against NDB');
it('tracks attestation state');
});

E2E Tests (Playwright)

test('create stableford competition', async ({ page }) => {
// Navigate to tournaments
// Complete wizard steps
// Verify competition created
});

test('generate draw and view pairings', async ({ page }) => {
// Open competition
// Generate random draw
// Verify pairings displayed
});

test('enter scores and view leaderboard', async ({ page }) => {
// Open scoring console
// Enter hole-by-hole scores
// Verify leaderboard updates
});

test('matchplay bracket flow', async ({ page }) => {
// Create bracket
// Seed from qualifying
// Record match results
// Verify bracket advances
});

Implementation Phases

Phase 1: Core Competition Management (P0)

  • Competition list view (calendar + table)
  • Competition creation wizard
  • Basic CRUD operations
  • Entry management (add, withdraw, list)
  • Division configuration

Phase 2: Draw & Pairings (P0)

  • Draw type selection
  • Draw generation
  • Pairings view
  • Manual adjustments (swap, move)
  • Draw export (PDF)

Phase 3: Scoring Console (P1)

  • Scorecard grid view
  • Hole-by-hole entry
  • Stableford/stroke calculation
  • Attestation workflow
  • Lock/unlock controls

Phase 4: Leaderboard & Results (P1)

  • Live leaderboard with refresh
  • Division filtering
  • Countback display
  • Finalization workflow
  • CSV/PDF export

Phase 5: Matchplay (P1)

  • Bracket creation
  • Seeding methods
  • Interactive bracket visualization
  • Match scoring (hole-by-hole)
  • Bracket advancement

Phase 6: Prizes & Side Competitions (P2)

  • Prize templates
  • Prize assignment
  • Nearest pin/longest drive entry
  • 2's club tracking
  • Results integration

Phase 7: Series & Appeals (P2)

  • Series management
  • Order of Merit standings
  • Competition linking
  • Appeals workflow
  • Appeal resolution

Phase 8: Integration & Polish (P2)

  • Tee sheet integration
  • Handicap posting (GolfRSA/DotGolf)
  • Notifications
  • Mobile-responsive views
  • Performance optimization

Tee Sheet Integration

Competition Round → Tee Sheet
│ │
└── teeSheetId ────┘

[Sync Tee Sheet Bookings]


Competition Entries

Sync Behavior

  1. Round configured with teeSheetId
  2. Admin triggers "Sync from Tee Sheet"
  3. For each booked slot with a player:
    • Create entry if not exists
    • Link entry to teeTimeSlotId
    • Capture handicap snapshot
  4. Draw inherits tee time order

Visual Indicators

On tee sheet grid, competition-linked slots show:

  • Competition badge on tile
  • Entry status (entered, withdrawn)
  • Link to competition detail

Open Questions

None at this time.


Revision History

DateAuthorChanges
2025-12-09Rudi HaarhoffInitial specification