- /login sends a Supabase magic link (admin emails only); /auth/confirm completes sign-in; proxy.ts guards /admin and every server action re-checks with requireAdmin(), since actions are plain POST endpoints. - /admin lists, creates, duplicates and deletes events. - /admin/events/[eventId] edits teams (colour, order) and games with criteria, presets and notes. All input goes through zod schemas that mirror the database constraints so errors read as plain sentences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.0 KiB
4.0 KiB
Build plan
Work one phase at a time. At the end of each phase: run lint + tests, commit, and give the human a short "how to test this manually" checklist. Don't start the next phase until told.
Phase 0 — Scaffold
- Next.js + TS strict + Tailwind + ESLint + Vitest.
src/layout per ARCHITECTURE.md. - Fonts: Big Shoulders Display + Atkinson Hyperlegible via
next/font/google. Tokens from UI.md as CSS variables + Tailwind theme. - Supabase clients (
browser,server,adminwithserver-only). .env.localloading; fail fast with a clear error if vars are missing. Done when:npm run devshows a placeholder home;npm run testruns a dummy test.
Phase 1 — Database + types
- Apply
supabase/migrations/0001_init.sql. Generate TS types intosrc/lib/database.types.ts. src/lib/tokens.tszod schemas (32-char hex). Done when: tables visible in Supabase; anon key cannotselectfrom any table (write a quick script/test proving it).
Phase 2 — Scoring engine (TDD)
- Implement SCORING.md in
src/lib/scoring/as pure functions. - All listed test cases + edge cases. Done when: tests green, 100% branch coverage on the scoring module.
Phase 3 — Admin auth + setup screens
/loginmagic link;proxy.tsguards/admin/*withADMIN_EMAILS.- Events list + create/duplicate/delete.
- Event setup: teams CRUD (colour picker, reorder), games builder with criteria + presets, notes. Done when: I can build a "Worship Game Night" with 4 teams and a Karaoke game with 5 criteria (1–5) and a Guess the Lyric game with 1 number criterion.
Phase 4 — Scoreboard + realtime
src/lib/realtime.tsnotify()(server broadcast) +useRefreshChannel(channel, refetch)hook (debounce, reconnect, 10s poll, refetch on focus).GET /api/public/scoreboard/[token]building the payload via the scoring engine./s/[token]page per UI.md: FLIP rank animation, count-up totals, reduced motion, fullscreen, cursor hide, connection dot. Done when: changing anything in the DB via admin (or SQL + a manual notify) updates an open scoreboard tab in < 1s.
Phase 5 — Control room (direct scoring)
/admin/events/[id]/live: game list, prev/next, set current (→ live), mark done.- Scoring grid with block + number inputs, autosave, optimistic UI.
- Bonus/penalty panel with quick buttons, custom, reason, undo.
- Keyboard shortcuts. Done when: I run a full direct-scored game and the scoreboard tracks every change.
Phase 6 — Visibility + reveal
- Visible / Frozen / Hidden toggle. Freeze stores snapshot server-side. Hidden strips scores in the API.
- Reveal mode: start, reveal next (bottom-up), finish → visible. Done when: in Hidden mode, the network tab on the scoreboard contains NO totals. Reveal works end-to-end.
Phase 7 — Judges
- Nominate judges, copy link, QR codes (use a small QR lib), revoke.
- Open link toggle +
/jo/[token]name flow + localStorage. /j/[token]mobile page: team cards, spotlight pinned, block rows, autosave status, read-only states.PUT /api/judge/[token]/scoreswith all checks from ARCHITECTURE.md + rate limit. Clearing = DELETE orvalue: null.- Control room in judged mode: averages, judge progress matrix, per-judge breakdown, override cells, spotlight select, lock toggle. Done when: 2 phones judging Karaoke at once, admin sees progress live, scoreboard updates with averages, override works, lock makes judges read-only.
Phase 8 — Polish + deploy
- Share panel (all links + QR in one place, "copy all judge links for this game" as text for WhatsApp).
- Empty states + error copy per UI.md.
- Accessibility pass (focus, contrast, tap targets).
- Deploy to Vercel; set env vars; set Supabase auth redirect URLs to the Vercel domain. Done when: full dry run on the deployed URL: laptop admin + projector scoreboard + 2 phone judges.
Stretch (only if asked)
Participants within teams · co-host admins · countdown timer on scoreboard · sound effects on reveal · CSV export of results.