Next.js 16 App Router with strict TypeScript, Tailwind 4 theme tokens from docs/UI.md, Vitest, and the three Supabase clients. Env vars are validated with zod in next.config.ts so dev and build fail fast with a readable error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
6.0 KiB
Markdown
102 lines
6.0 KiB
Markdown
# PRD — Game Night Live
|
||
|
||
## 1. Goal
|
||
Run a youth game night (e.g. "Worship Game Night") from one admin tab while a projector tab shows a
|
||
live scoreboard, and judges score from their phones via links. Versatile enough for any game format.
|
||
|
||
## 2. Roles
|
||
| Role | Access | How they get in |
|
||
|---|---|---|
|
||
| **Admin** | Everything | Logs in (magic link). Email must be in `ADMIN_EMAILS`. |
|
||
| **Scoreboard viewer** | Read-only scoreboard for ONE event | Public link `/s/{scoreboardToken}` |
|
||
| **Judge** | Score ONE game | Personal link `/j/{judgeToken}` OR open game link `/jo/{openToken}` (enters name first) |
|
||
|
||
## 3. Core concepts
|
||
- **Event** — one game night. Has teams, games, one scoreboard link, visibility state.
|
||
- **Team** — name + colour. Belongs to an event.
|
||
- **Game** — one activity. Ordered. Has a scoring mode:
|
||
- `judged` — judges submit scores via links; admin can see progress & override.
|
||
- `direct` — admin enters scores directly.
|
||
- **Criterion ("block")** — one thing being scored in a game. A game has 1..N criteria.
|
||
- e.g. Karaoke: Pitch, Energy, Lyrics accuracy, Stage presence, Crowd reaction (each 1–5).
|
||
- e.g. Guess the Lyric: one criterion "Correct answers" (number input, 0–20).
|
||
- Input type: `blocks` (tap a number in a row of buttons) or `number` (free numeric input / +/- stepper).
|
||
- Has min, max, step, weight, and a description (shown to whoever scores it).
|
||
- **Points mode** per game (how a game's result becomes leaderboard points):
|
||
- `raw` — game points = criteria total × multiplier.
|
||
- `placement` — teams ranked by criteria total, then awarded placement points (default 10/7/5/3).
|
||
- **Adjustment** — bonus or penalty points with a reason, optionally tied to a game.
|
||
- **Notes** — `admin_notes` (only admin sees) and `judge_notes` (judges see) per game.
|
||
|
||
## 4. Features
|
||
|
||
### 4.1 Admin — Setup (`/admin/events/[id]`)
|
||
- Create/edit/delete events; duplicate an event (copies teams, games, criteria — not scores).
|
||
- Teams: add, rename, recolour, reorder, delete.
|
||
- Games builder: add, reorder (drag or up/down), duplicate, delete.
|
||
- Title, description, scoring mode, points mode, multiplier, placement points.
|
||
- Criteria list: add/remove/reorder; label, description, input type, min/max/step, weight.
|
||
- Quick presets: "Karaoke (5 × 1–5)", "Single score (0–10)", "Points (number)", "Win/Lose (0–1)".
|
||
- Admin notes + judge notes (multiline).
|
||
- Judges (judged games only):
|
||
- Nominate judges by name → each gets a personal link (copy button + QR code).
|
||
- Toggle the open link on/off; anyone opening it types their name and becomes a judge.
|
||
- Revoke a judge (link stops working, their scores excluded).
|
||
- Share panel: scoreboard link + QR, all judge links per game.
|
||
|
||
### 4.2 Admin — Control room (`/admin/events/[id]/live`)
|
||
This is the screen used during the night. Must be fast and hard to mess up.
|
||
- Game switcher: Prev / Next buttons + list of all games with status (upcoming / live / done).
|
||
Setting a game as current marks it `live` and shows it on the scoreboard.
|
||
- Current game panel:
|
||
- Scoring grid: rows = teams, columns = criteria, using the same block/number inputs.
|
||
- Direct mode: admin types/taps here. Autosaves.
|
||
- Judged mode: shows per-team average per criterion, a judge-progress matrix
|
||
(✓ per judge per team), and per-judge breakdown on expand. Admin can override a cell
|
||
(override wins over judge average; clearly marked; can be cleared).
|
||
- Spotlight: pick "now performing" team — judges see it highlighted.
|
||
- Lock judging toggle (judges become read-only).
|
||
- Mark game done.
|
||
- Admin notes visible.
|
||
- Bonus/penalty: per team quick buttons (+1, +5, +10, −5) and custom amount + reason.
|
||
Recent adjustments list with undo.
|
||
- Scoreboard visibility: **Visible / Frozen / Hidden** (see 4.3). Big obvious toggle.
|
||
- "Open scoreboard" button (new tab) + "Reveal mode" button (see 4.3).
|
||
- Keyboard shortcuts: `N` next game, `P` prev game, `H` cycle visibility, `?` help.
|
||
|
||
### 4.3 Scoreboard (`/s/[token]`)
|
||
- Projector-first, 16:9, readable from the back of a hall.
|
||
- Shows: event name, current game title, team standings (rank, name, colour, total points),
|
||
optionally per-game points columns for completed games.
|
||
- Updates live (< 1s) when admin changes anything. Rank changes animate.
|
||
- **Visible** — live totals.
|
||
- **Frozen** — shows totals as they were the moment it was frozen, with a subtle "scores frozen" note.
|
||
Server stores the snapshot; live scores are not sent.
|
||
- **Hidden** — no scores sent at all. Shows team names (no order implied — alphabetical) and the current game, with a "scores are hidden" state.
|
||
- **Reveal mode** (admin-triggered): scoreboard reveals final standings last place → first,
|
||
one team per admin click ("Reveal next"), then sets visibility to Visible.
|
||
- Auto-reconnects; also polls every 10s as a fallback. Shows a small offline dot if disconnected.
|
||
- Fullscreen button; hides cursor after inactivity.
|
||
|
||
### 4.4 Judge (`/j/[token]`)
|
||
- Mobile-first. Shows game title, judge notes, and their own name.
|
||
- One card per team (spotlighted team pinned on top + highlighted).
|
||
- Each card: one block row per criterion (e.g. 1 2 3 4 5 big tap targets) with the criterion
|
||
label + description; number criteria get a stepper.
|
||
- Autosaves on every tap; shows saved ✓ / saving / error per card.
|
||
- Judges see only their own scores — never other judges' or totals.
|
||
- If judging locked or game done: read-only with a message. If revoked: "This link is no longer active."
|
||
- Open link (`/jo/[token]`): enter name → creates judge → redirects to personal link and stores it
|
||
in localStorage so a refresh keeps them in.
|
||
|
||
## 5. Non-functional
|
||
- Live latency target < 1s on normal Wi-Fi.
|
||
- Works with ~10 teams, ~20 games, ~10 judges per game without lag.
|
||
- No data loss on refresh; all state server-side.
|
||
- Accessible: visible focus, sufficient contrast, tap targets ≥ 44px.
|
||
|
||
## 6. Out of scope (v1)
|
||
- Individual contestants within teams (stretch: `participants` per team).
|
||
- Multiple admins / co-hosts (stretch).
|
||
- Timers/buzzers (stretch).
|