felt/.planning/STATE.md
Mikkel Georgsen a3083ce548 docs(01-14): complete Frontend Tables Tab + More Tab plan
- SUMMARY.md with task commits, decisions, and deviations
- STATE.md updated to Phase 1 Complete (14/14 plans)
- ROADMAP.md progress updated

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 08:30:16 +01:00

8.1 KiB

gsd_state_version milestone milestone_name status last_updated progress
1.0 v1.0 milestone unknown 2026-03-01T07:29:08.718Z
total_phases completed_phases total_plans completed_plans
1 1 14 14

Project State

Project Reference

See: .planning/PROJECT.md (updated 2026-02-28)

Core value: A venue can run a complete tournament offline on a €100 device with wireless displays and player mobile access — and it just works, on any network, with zero IT involvement. Current focus: Phase 1 — Foundation

Current Position

Phase: 1 of 7 (Tournament Engine) Plan: 14 of 14 in current phase (COMPLETE) Status: Phase 1 Complete Last activity: 2026-03-01 — Completed Plan 14 (Frontend Tables Tab + More Tab)

Progress: [██████████] 100%

Performance Metrics

Velocity:

  • Total plans completed: 13
  • Average duration: 9min
  • Total execution time: 2.01 hours

By Phase:

Phase Plans Total Avg/Plan
01-tournament-engine 13 121min 9min

Recent Trend:

  • Last 5 plans: 01-11 (8min), 01-12 (8min), 01-13 (5min), 01-06 (9min), 01-08 (6min)
  • Trend: steady

Updated after each plan completion | Phase 01 P14 | 11 | 2 tasks | 8 files |

Accumulated Context

Decisions

Decisions are logged in PROJECT.md Key Decisions table. Recent decisions affecting current work:

  • [Init]: Go monorepo, shared internal/, cmd/leaf and cmd/core are the only divergence points
  • [Init]: NATS sync_interval: always required before first deploy (December 2025 Jepsen finding)
  • [Init]: All monetary values int64 cents — never float64 (CI gate test required)
  • [Init]: go-libsql has no tagged releases — pin to commit hash in go.mod
  • [Init]: Netbird reverse proxy is beta — validate player PWA access in Phase 1 before depending on it in Phase 8
  • [01-01]: NATS server v2.12.4 requires Go 1.24+ — auto-upgraded from Go 1.23
  • [01-01]: WebSocket JWT via query parameter (browser WS API limitation)
  • [01-01]: JWT signing key ephemeral per startup — will persist in auth plan
  • [01-02]: go-libsql requires single-statement Exec — migration runner splits SQL files into individual statements
  • [01-02]: go-libsql PRAGMA handling is inconsistent — use QueryRow for journal_mode, execPragma helper for others
  • [01-02]: Force single DB connection during migrations (SetMaxOpenConns(1)) for table visibility
  • [01-10]: ESM type:module required in package.json for SvelteKit/Vite compatibility
  • [01-10]: frontend/build/ tracked in git (not gitignored) for go:embed
  • [01-10]: Catppuccin colors defined as CSS custom properties rather than @catppuccin/palette JS package
  • [01-04]: Clock ticker uses 100ms resolution with broadcast gating (not two separate tickers)
  • [01-04]: Crash recovery always restores clock as paused (operator must explicitly resume)
  • [01-04]: Overtime mode defaults to repeat (last level repeats indefinitely)
  • [01-04]: State change callback is async to avoid holding clock mutex during DB writes
  • [01-05]: Seed data uses INSERT OR IGNORE with explicit IDs for idempotent migration re-runs
  • [01-05]: Wizard generates preview-only levels (not auto-saved) for TD review before saving
  • [01-05]: BB ante used in WSOP-style template (separate from standard ante field)
  • [01-05]: Payout bracket validation enforces contiguous entry count ranges with no gaps
  • [01-03]: JWT HS256 enforcement via WithValidMethods prevents algorithm confusion attacks
  • [01-03]: Rate limiting keyed by global sentinel (_global) since PINs scan all operators
  • [01-03]: AuditRecorder callback breaks import cycle between auth and audit packages
  • [01-03]: NATS publish best-effort (logged, not fatal) to avoid audit blocking mutations
  • [01-03]: Undo creates reversal entry, only marks undone_by on original (never deletes)
  • [01-13]: div with role=tablist (not nav) for bottom tabs to avoid Svelte a11y conflict
  • [01-13]: FAB actions dispatched via callback prop for centralized routing in layout
  • [01-13]: Multi-tournament state is a separate store from singleton tournament state
  • [01-13]: DataTable uses Record<string,unknown> with render functions (not generics) for Svelte compat
  • [01-06]: PKO bounty half-split uses integer division (cashPortion = bountyValue/2, bountyPortion = remainder)
  • [01-06]: Unique entry count for bracket selection uses COUNT(DISTINCT player_id) on non-undone buyin tx only
  • [01-06]: Late reg checks level AND time cutoffs independently (either exceeded closes registration)
  • [01-06]: Rebuy/addon rake splits proportionally scaled from buyin rake splits (last gets remainder)
  • [01-06]: CI gate: CalculatePayoutsFromPool is pure function tested with 10,000+ random inputs, zero deviation
  • [01-08]: Balance suggestions use clockwise distance from dealer button for move fairness
  • [01-08]: Stale suggestion re-validation requires fromCount - toCount >= 2 before accepting
  • [01-08]: Break table is fully automatic (applies immediately, result is informational per CONTEXT.md)
  • [01-08]: Blueprint routes are venue-level (not tournament-scoped); admin role required for mutations
  • [01-07]: Rankings derived from bust_out_at timestamps via RecalculateAllRankings (never stored independently)
  • [01-07]: FTS5 queries use quoted terms with * suffix for prefix matching
  • [01-07]: CSV formula injection neutralized with tab prefix on =, +, -, @ characters
  • [01-07]: Buy-in flow auto-registers player in tournament_players if not already present
  • [01-07]: QR code URL format: felt://player/{uuid} for future PWA self-check-in
  • [01-09]: ICM dispatcher: exact Malmuth-Harville for <=10 players, Monte Carlo (100K iterations) for 11+
  • [01-09]: Deal proposal/confirm workflow: ProposeDeal returns preview, ConfirmDeal applies payouts
  • [01-09]: Full chop sets all players to 'deal' status and completes tournament; partial chop continues play
  • [01-09]: Tournament auto-close: 1 remaining = EndTournament, 0 remaining = CancelTournament
  • [01-09]: Integration tests use file-based DB with WAL mode for clock ticker goroutine compatibility
  • [01-12]: Flow overlays use fixed full-screen z-index 100 positioning (modal-like, not route-based)
  • [01-12]: BustOutFlow uses grid table picker then seat tap for minimal taps under time pressure
  • [01-12]: RebuyFlow/AddOnFlow preselectedPlayer prop skips search step for direct launch from PlayerDetail
  • [01-12]: FAB actions in layout wired to actual flow overlays (replacing placeholder toasts)
  • [01-11]: ClockDisplay uses clamp(3rem, 12vw, 6rem) for responsive timer sizing across mobile/desktop
  • [01-11]: Unicode escapes in Svelte templates must use HTML entities (not JS escapes) to avoid parser confusion
  • [01-11]: BubblePrize is standalone prominent button (not buried in menus) per CONTEXT.md requirement
  • [01-11]: DealFlow uses multi-step wizard pattern (type > input > review > confirm) for all 5 deal types
  • [01-11]: Transaction undo uses window.confirm for simplicity in touch-first TD interface
  • [Phase 01]: Structure wizard uses geometric ratio for blind escalation with nice-number rounding
  • [Phase 01]: Blind structure editor uses move up/down buttons (no drag-and-drop in Phase 1)
  • [Phase 01]: Theme toggle writes data-theme attribute on documentElement for immediate CSS variable switch

Pending Todos

None yet.

Blockers/Concerns

  • [Phase 1]: go-libsql CGO ARM64 cross-compilation must be validated in CI before any downstream features depend on it
  • [Phase 1]: Netbird reverse proxy beta status — test the full QR code → HTTPS → WireGuard → Leaf flow early
  • [Phase 3]: NATS JetStream cross-domain stream mirroring (Leaf → Core) needs integration test before Phase 2 depends on it
  • [Phase 4]: Events engine security — run_command sandboxing, webhook URL allowlist, WYSIWYG HTML sanitization (deferred from Phase 1 security review)
  • [Phase 7]: JWT HttpOnly cookies + signing key rotation (deferred from Phase 1 security review — localStorage is acceptable while Leaf is local-network only)
  • [Phase 7]: Pi Zero 2W memory must be profiled on actual hardware with all display views before scaling signage

Session Continuity

Last session: 2026-03-01 Stopped at: Completed 01-14-PLAN.md (Frontend Tables Tab + More Tab) Resume file: None