--- phase: 01-tournament-engine task: planning-feedback total_tasks: 14 plans (A-N) status: in_progress last_updated: 2026-03-01T02:16:50.435Z --- Phase 1 planning is complete (14 plans, 6 waves, 68/68 requirements covered). Currently applying security feedback — item 1 of 7 is done, items 2-7 remain. All plans are committed except the security hardening edits. ## Planning Pipeline (fully complete) - Research: 01-RESEARCH.md written (go-libsql, NATS JetStream, Svelte 5, ICM complexity) - Plans A-N created (14 plans, 6 waves) - Plan checker: 2 iterations, all blockers resolved (G dep on F, J/L scope splits → M/N) - Committed: `21ff950 docs(01): create Phase 1 plans (A-N) with research and feedback` ## User Feedback Round 1 (fully applied, committed) - Correction 1: CONTEXT.md — Added hand-for-hand decisions (per-table completion tracking) - Correction 2: Plan D/H — Fixed hand-for-hand (removed time deduction, added per-table handCompleted) - Correction 3: REQUIREMENTS.md — Reworded SEAT-06 to "tap-tap manual seat moves" - Correction 4: Plan C — Removed FIN-14 duplicate (Plan F is sole owner) - Correction 5: Plan B — Clarified re-entry clears bust fields - Gap 6: CONTEXT.md — Defined punctuality bonus concretely - Gap 7: Plan I — Added integration_test.go with full tournament lifecycle - Gap 8: Plan A — Health check verifies LibSQL + NATS + hub - Gap 9: Plan C — JWT expiry 24h → 7 days - Suggestion 10: Plan B — DKK defaults + Copenhagen chip set - Suggestion 12: Plan M — Multi-tournament state caching - Suggestion 13: Plan K — Removed clock tap-to-pause (FAB only) ## Security Feedback (partially applied) - Fix 1 DONE: Plan B — Removed default admin PIN seed, added first-run setup flow + dev-only seed migration - Fixes 2-7: NOT YET APPLIED (see remaining_work) ## Security Fixes (MUST APPLY — continue from fix 2) ### Fix 2: Plan A — Authenticated WebSocket connections - Require JWT as query param on /ws?token=... - Validate JWT before allowing subscription - Enforce tournament scope server-side - Validate Origin header, reject unknown origins - Edit Plan A task A2 WebSocket hub section ### Fix 3: Plan A — Harden HTTP server baseline - Set explicit timeouts: ReadHeaderTimeout(10s), ReadTimeout(30s), WriteTimeout(60s), IdleTimeout(120s), MaxHeaderBytes(1MB) - Apply http.MaxBytesReader on all request body reads (default 1MB, larger for CSV import) - Edit Plan A task A2 HTTP server section ### Fix 4: Plan B — Audit trail tamper protection triggers - SQLite trigger REJECT UPDATE on audit_entries (except undone_by) - SQLite trigger REJECT DELETE on audit_entries entirely - Add to Plan B task B1 schema migration ### Fix 5: Plan C — Fix JWT validation and PIN rate limiting - Enforce HS256 via jwt.WithValidMethods([]string{"HS256"}) - JWT TTL already 7 days (done in earlier feedback) - Persist failed login attempts in LibSQL (not in-memory) - Key rate limiting by operator ID (not IP) - Emit audit entries for 5+ consecutive failures - Defer key rotation to Phase 7 ### Fix 6: Plan C/A (NATS) — Validate subject construction - UUID validation helper before constructing NATS subjects - Apply in internal/nats/publisher.go (Plan A) ### Fix 7: Plan G + Plan F — CSV safety - Import limits: max 10,000 rows, 20 columns, 1,000 chars/field - Export: neutralize formula injection (prefix =, +, -, @ with tab) - Test cases for both ### Also Apply: - Keep-as-is item 8: Add TODO comment in Plan J auth store re: Phase 7 HttpOnly cookies - Acceptance criteria: Add security acceptance criteria to relevant plan verification sections ### After Security Fixes: - Commit all security edits - Phase 1 planning is DONE — ready for /gsd:execute-phase 1 - Plans split from 12→14: J split into J+M (layout shell), L split into L+N (tables+more) — checker blocker on file count - G moved to wave 4 (depends on F for financial engine calls) — checker blocker on missing dependency - I moved to wave 5, K/L/N moved to wave 6 — cascading from G wave change - Hand-for-hand is per-table completion tracking (not time deduction) — user correction - SEAT-06 reworded to tap-tap (not drag-and-drop) — user correction, matches CONTEXT.md locked decision - Clock tap-to-pause removed — accidental pause risk, FAB only - JWT 7 days not 24h — 12+ hour tournament sessions - DKK as default currency — Copenhagen demo venue - No default admin PIN in prod — first-run setup screen instead None — just need to finish applying security fixes 2-7 The user provided security feedback as a structured list (7 must-apply items, 2 keep-as-is items, acceptance criteria). Fix 1 (Plan B default admin) is applied. The remaining 6 fixes are straightforward edits to existing plan files. All the files have already been read in this session. After applying fixes 2-7, commit, and Phase 1 planning is complete. Next step after planning: /gsd:execute-phase 1. Start with: Apply security fix 2 (Plan A WebSocket auth) — edit the WebSocket hub section in 01-PLAN-A.md task A2 to require JWT token as query parameter, validate before subscription, enforce tournament scope, validate Origin header. Then continue with fixes 3-7 sequentially, add acceptance criteria to verification sections, commit all.