felt/.planning/ROADMAP.md
Mikkel Georgsen 66d7894c24 docs(01-08): complete Table & Seating Engine plan
- SUMMARY.md with balance engine, break table, and API route details
- STATE.md updated with position (plan 10/14), decisions, metrics
- ROADMAP.md progress updated to 9/14 plans complete
- REQUIREMENTS.md: SEAT-01 through SEAT-09 all marked complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 04:26:57 +01:00

15 KiB

Roadmap: Felt

Overview

Felt is built in 7 phases, all scoped to Development Phase 1 (Live Tournament Management). The build order follows two principles: vertical slices (backend + frontend together so every phase is demoable) and software first, hardware later (ARM64, LUKS, Netbird, Pi Zero kiosk are all Phase 7 packaging concerns).

All development and testing happens in an x86 LXC container on Proxmox. The Go binary running there is functionally identical to the Virtual Leaf that runs the free tier in production on Hetzner. Hardware Leaf is a later deployment target for the Offline/Pro tier.

Development environment: x86_64 LXC container (Debian/Ubuntu), Go binary + LibSQL + NATS JetStream + SvelteKit. No Docker, no ARM cross-compilation, no Netbird. Display views are browser windows pointed at the container. Player phones connect on the local network.

Phases

Phase Numbering:

  • Integer phases (1, 2, 3): Planned milestone work
  • Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)

Decimal phases appear between their surrounding integers in numeric order.

  • Phase 1: Tournament Engine - Go binary in LXC, full vertical slice: clock, blinds, financials, players, tables, seating, operator UI — everything to run a complete tournament
  • Phase 2: Display Views + Player PWA - Browser-based display views, player mobile PWA, export formats — the full venue experience
  • Phase 3: Core Sync + Platform Identity - PostgreSQL on Core, NATS sync, platform-level player profiles, Virtual Leaf, GDPR compliance
  • Phase 4: Digital Signage + Events Engine - WYSIWYG content editor, AI generation, scheduling, visual rule builder, automation triggers
  • Phase 5: Leagues, Seasons + Regional Tournaments - Point formulas, standings, cross-venue tournaments, finals management
  • Phase 6: TDD Migration - Full TDD XML import, player database migration, tournament history, wizard, zero data loss
  • Phase 7: Hardware Leaf (ARM64 + Offline Hardening) - ARM64 cross-compilation, LUKS encryption, Pi Zero display nodes, Netbird mesh, provisioning, chaos testing

Phase Details

Phase 1: Tournament Engine

Goal: A complete tournament runs from start to finish in an x86 LXC container with a working touch-friendly operator UI — demoable at a venue by pointing any device at the container Depends on: Nothing (first phase) Requirements: ARCH-01, ARCH-03, ARCH-04, ARCH-05, ARCH-06, ARCH-07, ARCH-08, AUTH-01, AUTH-03, CLOCK-01, CLOCK-02, CLOCK-03, CLOCK-04, CLOCK-05, CLOCK-06, CLOCK-07, CLOCK-08, CLOCK-09, BLIND-01, BLIND-02, BLIND-03, BLIND-04, BLIND-05, BLIND-06, CHIP-01, CHIP-02, CHIP-03, CHIP-04, FIN-01, FIN-02, FIN-03, FIN-04, FIN-05, FIN-06, FIN-07, FIN-08, FIN-09, FIN-10, FIN-11, FIN-12, FIN-13, FIN-14, PLYR-01, PLYR-02, PLYR-03, PLYR-04, PLYR-05, PLYR-06, PLYR-07, SEAT-01, SEAT-02, SEAT-03, SEAT-04, SEAT-05, SEAT-06, SEAT-07, SEAT-08, SEAT-09, MULTI-01, MULTI-02, UI-01, UI-02, UI-03, UI-04, UI-05, UI-06, UI-07, UI-08 Note: Basic sound infrastructure (play_sound action for level change, break start, bubble) ships with the clock engine here. The full visual rule builder (EVENT-01 through EVENT-04) remains in Phase 4. Success Criteria (what must be TRUE):

  1. A Go binary starts in the LXC container, serves HTTP, embeds NATS JetStream and LibSQL, and WebSocket-connected clients receive state changes within 100ms
  2. The clock counts down each level, transitions automatically, emits configurable warnings; an operator can pause, resume, jump to any level; two tournaments run simultaneously with independent state
  3. A blind structure with mixed-game rotation, big-blind antes, and chip-up breaks can be saved as a template; the structure wizard produces a playable structure from inputs
  4. A complete buy-in, rebuy, add-on, and bounty flow produces a transaction log; a CI gate test verifies sum of payouts always equals prize pool (int64 cents, zero floating-point deviation)
  5. An operator can search by name with typeahead, process a buy-in with auto-seating, bust a player with hitman selection and auto-balancing — all from a mobile-first touch UI with FAB, persistent header, Catppuccin Mocha dark theme, and 48px touch targets
  6. Every state-changing action writes an append-only audit trail entry; any financial transaction or bust-out can be undone with full re-ranking Plans (12 plans, 5 waves):
  • Wave 1: A (Project Scaffold + Infrastructure), B (Database Schema + Migrations)
  • Wave 2: C (Auth + Audit Trail + Undo), D (Clock Engine), E (Blind Structure + Templates), J (SvelteKit Frontend Scaffold)
  • Wave 3: F (Financial Engine), G (Player Management), H (Table & Seating Engine)
  • Wave 4: I (Tournament Lifecycle + Multi-Tournament + Chop/Deal)
  • Wave 5: K (Frontend — Overview + Clock + Financials), L (Frontend — Players + Tables + More)

Phase 2: Display Views + Player PWA

Goal: The full venue experience — operator UI on phone, TV browsers showing tournament data fullscreen, players scanning QR codes on their phones — all connecting to the LXC container Depends on: Phase 1 Requirements: DISP-01, DISP-02, DISP-03, DISP-04, DISP-05, DISP-06, DISP-07, DISP-08, DISP-09, DISP-10, PWA-01, PWA-02, PWA-03, PWA-04, PWA-05, PWA-06, PWA-07, PWA-08, PWA-09, PWA-10, AUTH-05, EXPORT-01, EXPORT-02, EXPORT-03, EXPORT-04 Success Criteria (what must be TRUE):

  1. All tournament views (Clock, Rankings, Seating Chart, Blind Schedule, Final Table, Prize Pool, Lobby) render in browser windows connected via WebSocket and are readable from 10+ feet with auto font-scaling
  2. Screen cycling with configurable rotation runs automatically; the operator can assign views, override, or lock any screen from the operator UI
  3. A player scans a QR code and sees live clock, current blinds, and next level within 3 seconds — no account required; the PWA prompts "Add to Home Screen" on iOS and Android
  4. A player can claim personal status (seat, points) by entering a 6-digit PIN; WebSocket updates arrive within 100ms with auto-reconnect and polling fallback
  5. A completed tournament exports to CSV, JSON, and HTML with correct data and venue branding; a player can request a JSON export of their personal data (GDPR portability) Plans: TBD

Phase 3: Core Sync + Platform Identity

Goal: Players are platform-level entities with cross-venue portable profiles, Leaf-to-Core sync works with guaranteed delivery, Virtual Leaf provides free-tier access, and Core Admin is secured with MFA Depends on: Phase 1 Requirements: ARCH-02, PLAT-01, PLAT-02, PLAT-03, PLAT-04, PLAT-05, PLAT-06, SYNC-01, SYNC-02, SYNC-03, SYNC-04, AUTH-04, AUTH-06, AUTH-08, AUTH-09 Success Criteria (what must be TRUE):

  1. A player created on one Leaf appears on Core with the same UUID and profile data after reconnect, with no duplicates
  2. Tournament events published on Leaf while offline queue in NATS JetStream and replay to Core in order when connectivity is restored; Core never overwrites Leaf data for a running tournament
  3. Reverse sync delivers player profiles, league config, tournament templates, and branding from Core to Leaf
  4. A Virtual Leaf instance starts on Core infrastructure, runs the same tournament logic as a physical Leaf, and syncs data to Core PostgreSQL
  5. Core Admin authenticates via OIDC with mandatory MFA; NATS subjects are namespaced by venue ID with PostgreSQL RLS multi-tenant isolation; Leaf-Core sync uses mTLS + API key per venue
  6. Player data export (GDPR portability) and deletion (anonymize tournament entries, remove PII, propagate via NATS) work correctly Plans: TBD

Phase 4: Digital Signage + Events Engine

Goal: Venue screens show scheduled content between tournaments and the events engine automates visual and audio responses to tournament moments — all configured via the operator UI without code Depends on: Phase 2 Requirements: SIGN-01, SIGN-02, SIGN-03, SIGN-04, SIGN-05, SIGN-06, SIGN-07, SIGN-08, SIGN-09, SIGN-10, EVENT-01, EVENT-02, EVENT-03, EVENT-04 Success Criteria (what must be TRUE):

  1. An operator creates a promo card with the WYSIWYG editor, uses AI text generation to produce content, schedules it to run on specific screens at specific times, and it appears without manual intervention
  2. Screens automatically switch to tournament clock view when a tournament starts and revert to the signage playlist when it ends — without operator action
  3. An event rule triggers a sound and a display message when the final table is reached; the operator created the rule via the visual builder without writing code
  4. Different screens show different content simultaneously (e.g., screen 1 shows sponsor ad, screen 2 shows league table)
  5. All signage content bundles are stored as static HTML/CSS/JS and render in any browser without internet Security Requirements (deferred from Phase 1 security review):
  • EVENT-02 run_command action: sandbox execution (allowlist of commands, no shell=true, no arbitrary binary execution, timeout enforcement)
  • EVENT-02 webhook action: URL allowlist (operator-configured permitted domains), no SSRF to internal services, timeout on outbound requests
  • Signage content: sanitize user-authored HTML/CSS (no script injection in WYSIWYG output), CSP headers on display views Plans: TBD

Phase 5: Leagues, Seasons + Regional Tournaments

Goal: Venues run structured leagues with configurable point formulas and season standings, and anyone can create cross-venue tournaments using the free-tier regional organizer Depends on: Phase 3 Requirements: LEAGUE-01, LEAGUE-02, LEAGUE-03, LEAGUE-04, LEAGUE-05, LEAGUE-06, REGION-01, REGION-02, REGION-03, REGION-04, REGION-05 Success Criteria (what must be TRUE):

  1. An operator configures a league with a custom point formula, tests it against sample placements with the formula tester, and sees the distribution graph before saving
  2. Season standings update automatically after each tournament result; the operator can configure best-N-of-M counting and minimum attendance requirements
  3. League standings display as a dedicated view, updating live as tournament results arrive
  4. A regional organizer (free-tier user) creates a cross-venue tournament, adds qualifying events at participating venues, and the unified leaderboard updates automatically from each venue's results
  5. A finals event is managed through the platform with aggregated qualifying results feeding directly into the finals seeding Plans: TBD

Phase 6: TDD Migration

Goal: Any venue running The Tournament Director can import their complete history and start using Felt on day one with zero data loss Depends on: Phase 5 Requirements: TDD-01, TDD-02, TDD-03, TDD-04, TDD-05, TDD-06, TDD-07 Success Criteria (what must be TRUE):

  1. An operator drops a TDD XML export file into the import wizard and sees a preview of all detected blind structures, players, tournaments, and leagues before committing
  2. All blind structures and payout tables import with exact value preservation — no rounding, no data loss
  3. The player database imports with name matching that detects likely duplicates and prompts the operator to confirm merges before writing
  4. Complete tournament history (results, payouts, bust-out order) appears in Felt as if it were run there — full search, export, and league calculation work on imported data
  5. A venue that has used TDD for 5 years can import their full history and see complete league standings with accurate historical point calculations on day one Plans: TBD

Phase 7: Hardware Leaf (ARM64 + Offline Hardening)

Goal: A pre-configured ARM64 Leaf node boots, connects to Core via Netbird, serves everything wirelessly, survives power failures, and runs completely offline — this is the Offline/Pro tier product Depends on: Phase 3 Requirements: ARCH-09, ARCH-10, AUTH-02, AUTH-07, NET-01, NET-02, NET-03, NET-04, NET-05, NET-06, NET-07, DISP-11 Success Criteria (what must be TRUE):

  1. A single Go binary (cmd/leaf) builds for ARM64 via CI with CGO enabled and LibSQL linked, with zero manual steps
  2. The Leaf binary starts on an Orange Pi 5 Plus with LUKS full-disk encryption on NVMe, serves HTTP, and connects to Core via Netbird WireGuard mesh
  3. An operator can authenticate via OIDC through Authentik when the Leaf has internet; display nodes and player browsers reach the Leaf from outside the local network via HTTPS through the Netbird reverse proxy
  4. Pi Zero 2W display nodes run Chromium kiosk with systemd watchdog, zram, and memory limits; all display views stay under 350MB RSS for 4+ hours (soak tested on actual hardware)
  5. The Leaf survives 10 hard power cycles without data loss (WAL checkpoint on shutdown, verified by chaos testing); automated daily backup to USB or cloud with documented recovery
  6. Custom domain support works (venue CNAME → felt subdomain); lazy connections scale to 500+ venues; Netbird DNS, SSH, and firewall policies are enforced Security Requirements (deferred from Phase 1 security review):
  • Migrate JWT storage from localStorage to HttpOnly secure cookies (Leaf becomes publicly accessible via Netbird reverse proxy — XSS can steal localStorage tokens)
  • JWT signing key rotation with kid header support Plans: TBD

Key Principles

  1. Build software first, package for hardware later. Every feature is developed and tested in an x86 LXC container. ARM64 is a deployment target, not a development concern.
  2. Vertical slices, not horizontal layers. Each phase delivers something visible and demoable. No headless engine phases followed by a monolithic UI phase.
  3. The LXC container IS the product. The binary running in the dev container is functionally the same as the Virtual Leaf that runs the free tier in production. Hardware Leaf is a later packaging step for paid tiers.
  4. Revenue-gated complexity. Netbird, LUKS, ARM cross-compilation, Pi Zero kiosk — all Offline/Pro tier. Don't build until venues pay for it.
  5. Demo-driven development. After Phase 1, demo a full tournament at the venue. After Phase 2, the full experience with displays and player phones. Every phase adds visible value.

Progress

Execution Order: Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7

Phase Plans Complete Status Completed
1. Tournament Engine 9/14 Executing -
2. Display Views + Player PWA 0/TBD Not started -
3. Core Sync + Platform Identity 0/TBD Not started -
4. Digital Signage + Events Engine 0/TBD Not started -
5. Leagues, Seasons + Regional Tournaments 0/TBD Not started -
6. TDD Migration 0/TBD Not started -
7. Hardware Leaf (ARM64 + Offline Hardening) 0/TBD Not started -