felt/.planning/phases/01-tournament-engine/01-CONTEXT.md
Mikkel Georgsen 21ff95068e docs(01): create Phase 1 plans (A-N) with research and feedback
14 plans in 6 waves covering all 68 requirements for the Tournament
Engine phase. Includes research (go-libsql, NATS JetStream, Svelte 5
runes, ICM complexity), plan verification (2 iterations), and user
feedback (hand-for-hand UX, SEAT-06 reword, re-entry semantics,
integration test, DKK defaults, JWT 7-day expiry, clock tap safety).

Wave structure:
  1: A (scaffold), B (schema)
  2: C (auth/audit), D (clock), E (templates), J (frontend scaffold)
  3: F (financial), H (seating), M (layout shell)
  4: G (player management)
  5: I (tournament lifecycle)
  6: K (overview/financials), L (players), N (tables/more)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:58:22 +01:00

9.1 KiB
Raw Permalink Blame History

Phase 1: Tournament Engine - Context

Gathered: 2026-03-01 Status: Ready for planning

## Phase Boundary

A complete tournament runs from start to finish in an x86 LXC container with a working touch-friendly operator (TD) UI — demoable at a venue by pointing any device at the container. Go backend with embedded LibSQL, NATS JetStream, WebSocket hub. SvelteKit frontend embedded via go:embed. Covers: clock, blinds, financials, players, tables, seating, multi-tournament, and the full TD interface.

Note: The operator throughout this system is the Tournament Director (TD) — use this term consistently.

## Implementation Decisions

Tournament Setup Flow

  • Template-first creation — TD picks from saved tournament templates, everything pre-fills, tweak what's needed for tonight, hit Start
  • Templates are compositions of reusable building blocks — a template is NOT a monolithic config. It references:
    • Chip set (denominations, colors, values — venue-level)
    • Blind structure (level progression, antes, breaks)
    • Payout structure (tiered by entry count — see Payout Structure below)
    • Buy-in config (entry cost, rake splits, rebuy/add-on rules)
    • Points formula (league scoring — venue-level, reused across seasons)
  • Local changes by default — when creating a tournament from a template, the TD gets a copy. Edits only affect that tournament. To change the actual reusable block, go to template management
  • Dedicated template management area — create from scratch, duplicate/edit existing, save tournament config as new template
  • Built-in starter templates ship with the app (Turbo, Standard, Deep Stack, WSOP-style) so day one has something to pick from
  • Structure wizard lives in template management — input player count, starting chips, desired duration, denominations → generates a blind structure to save as a block
  • Minimum player threshold — configured in tournament metadata (typically 8-9), Start button unavailable until met
  • Chip bonuses — configurable per tournament:
    • Early signup bonus: bonus chips awarded to the first X players who buy in (configurable cutoff count)
    • Punctuality bonus: bonus chips awarded to players who complete buy-in before the tournament starts (status transitions from 'registering' to 'running') — deterministic, automatic, no TD judgment call
  • Late registration soft lock with admin override — when cutoff hits, registration locks but admin can push through a late entry (logged in audit trail). Some tournaments have no late reg at all (registration closes at start)

Payout Structure

  • Entry-count brackets with tiered prizes — standalone reusable building block, example:
    • 820 entries → 3 prizes (50% / 30% / 20%)
    • 2130 entries → 4 prizes (45% / 26% / 17% / 12%)
    • 3140 entries → 5 prizes (42% / 26% / 16% / 11% / 5%)
    • 4150 entries → 6 prizes (40% / 24% / 14% / 10% / 7% / 5%)
  • Entry count = unique entries only — not rebuys or add-ons
  • Prize rounding — all prizes round down to nearest venue-configured denomination (e.g. 50 DKK in Denmark, €5 elsewhere). No coins, no awkward change
  • Bubble prize — happens in ~70% of tournaments. When remaining players exceed paid positions (e.g. 8 left, 7 paid), all remaining players can unanimously agree to create a bubble prize:
    • Typically around the buy-in amount
    • Funded by shaving from top prizes (mostly 1st3rd, sometimes 4th5th)
    • TD flow: "Add bubble prize" → set amount → system shows redistribution across top prizes → confirm
    • Must be fast and intuitive — not buried in menus, this happens constantly

TD Workflow During Play

  • Overview tab priority (top to bottom):
    1. Clock & current level (biggest element)
    2. Time to next break
    3. Player count (registered / remaining / busted)
    4. Table balance status (are tables even or needs attention)
    5. Financial summary (prize pool, entries, rebuys)
    6. Recent activity feed (last few actions)
  • Bust-out flow: tap Bust → pick table → pick seat → system shows player name for verification → confirm → select hitman (mandatory in PKO tournaments, optional otherwise) → done
  • PKO (Progressive Knockout): when template defines PKO, bounty transfer is part of the bust flow (half to hitman, half added to their own bounty, chain tracked)
  • Buy-in flow: search/select player → auto-seat suggests optimal seat → TD can override (accessibility needs, keep-apart situations like couples) → confirm → receipt
  • Multi-tournament switching: TD chooses tabs at top OR split view — phone likely tabs, tablet landscape could do split view
  • Undo is critical — bust-outs, rebuys, add-ons, buy-ins can all be undone with full re-ranking. Miscommunication between TD and dealers happens often

Seating & Balancing

  • Oval table view (default) — top-down view with numbered seats, player names in seats, empty seats visible. Switchable to list view for density (10+ table tournaments)
  • Balancing is TD-driven, system-assisted:
    1. System alerts: tables are unbalanced
    2. TD requests suggestion: system says "move 1 from Table 1 to Table 4"
    3. TD announces to the floor, assistant facilitates
    4. Assistant reports back: "Seat 3 to Seat 5" — TD taps two seat numbers, done (minimal touches)
    5. Suggestion is live and adaptive — if Table 1 loses a player before the move happens (e.g. bust during ongoing hand), system recalculates or cancels
  • Break Table is fully automatic — system knows all open seats, distributes players evenly, TD just sees the result ("Player X → Table 1 Seat 4")
  • No drag-and-drop in Phase 1 — tap-tap flow for all moves

Hand-for-Hand Mode

  • Activated by TD when tournament reaches bubble (remaining players = paid positions + 1)
  • Clock pauses, each table plays one hand at a time
  • TD view: table grid showing completion status per table (completed / in progress)
  • TD taps "Hand Complete" per table as dealers report
  • When all tables complete: next hand starts automatically, or if someone busted the bubble is resolved
  • If bust during hand-for-hand: check if bubble burst, if yes exit hand-for-hand mode and resume clock
  • Hand-for-hand should be prominent (visible mode indicator on all clients) because players watch this closely

End-Game & Payouts

  • Flexible chop/deal support — all remaining players participate in a deal, nobody leaves while others play on. Supported scenarios:
    • ICM calculation (TD inputs chip stacks, system calculates each player's share)
    • Custom split (players agree on % or fixed amount)
    • Partial chop (split some money, play on for remaining + league points)
    • Any number of players (not just heads-up — 4-way deals after 12 hours are real)
  • Prize money and league positions are independent — money can be chopped but positions still determined by play for points
  • Tournament auto-closes when one player remains — no manual "end tournament" button
  • Receipts configurable per venue: off / digital / print / both. Player and venue can always see tournament participation in the system regardless of receipt setting

Claude's Discretion

  • Loading skeleton and animation design
  • Exact spacing, typography, and component sizing
  • Error state handling and messaging
  • Toast notification behavior and timing
  • Activity feed formatting
  • Thermal printer receipt layout
  • Internal data structures and state management patterns
## Specific Ideas
  • The bust-out flow must be as few taps as possible — TD is under time pressure during a running tournament
  • Balancing recording should be two taps (source seat, destination seat) after the system suggests table-to-table
  • Bubble prize creation needs to be fast and prominent — it happens in 70% of tournaments
  • "Add bubble prize" should be easily accessible, not buried in settings
  • Template building blocks should feel like LEGO — pick chip set, pick blind structure, pick payout table, name it, done
  • The system should adapt to the chaos of live poker — hands in progress during balancing, players busting mid-move, deals negotiated at 2am after 12 hours of play

<code_context>

Existing Code Insights

Reusable Assets

  • No existing code — greenfield project

Established Patterns

  • No established patterns yet — Phase 1 sets the foundation

Integration Points

  • Go binary serves SvelteKit via go:embed
  • WebSocket hub for real-time state to all connected clients
  • LibSQL for local persistence
  • NATS JetStream for event durability
  • Catppuccin Mocha dark theme (UI-05)

</code_context>

## Deferred Ideas
  • Drag-and-drop seat moves — UI polish, add after core tap-tap flow works (future Phase 1 enhancement or later)
  • PWA seat move notifications — when a player is moved (balancing or table break), notify them in the PWA with new table/seat — Phase 2
  • "Keep apart" player marking — TD marks players who shouldn't be at the same table (couples, etc.), auto-seating respects it — evaluate for Phase 1 or later

Phase: 01-tournament-engine Context gathered: 2026-03-01