- Timer: one per event, set from the control room (duration, presets, start/pause/resume/reset, show/hide, T shortcut). Rules are pure functions in src/lib/timer.ts; the server's clock sets the end time and each screen counts down locally, corrected for its own clock. Needs supabase/migrations/0002_timer.sql. - Sound effects on the scoreboard, synthesised with Web Audio (no files): drum-roll + crash per revealed team, fanfare for first place, a chime on game change, ticks for the last 10 seconds and a buzzer at zero. Triggers are pure functions comparing consecutive payloads. - 'Turn sound on' button on the scoreboard, since browsers block audio until a click; the choice is remembered across reloads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1.5 KiB
1.5 KiB
Data model
Full SQL in supabase/migrations/0001_init.sql.
| Table | Purpose | Key columns |
|---|---|---|
events |
A game night | owner_id, scoreboard_token, scoreboard_visibility, frozen_snapshot, current_game_id, reveal_active, reveal_count, timer_visible, timer_duration_ms, timer_remaining_ms, timer_ends_at |
teams |
Teams in an event | name, color (#RRGGBB), sort_order |
games |
Activities | scoring_mode, points_mode, multiplier, placement_points int[], status, admin_notes, judge_notes, open_token, open_link_enabled, judging_locked, spotlight_team_id |
criteria |
Scoring blocks per game | label, description, input_type, min_value, max_value, step, weight |
judges |
Judges per game | name, token, revoked, source (nominated/open_link) |
scores |
One value per (team, criterion, judge) | judge_id NULL = admin score (direct mode or override) |
adjustments |
Bonus/penalty | points (+/-), reason, optional game_id |
Notes
scoresunique on(team_id, criterion_id, judge_id)withNULLS NOT DISTINCT, so there's exactly one admin row per team+criterion → clean upserts.- In judged games, an admin row (
judge_id IS NULL) is an override for that cell. - Deleting a criterion/team/judge cascades its scores.
- Timer (
0002_timer.sql): running =timer_ends_atset; paused =timer_remaining_msset; reset = both null (fulltimer_duration_ms). frozen_snapshotholds theScoreboardPayloadcaptured at freeze time.