AyoubBenziza
d3ce52b60a
feat(admin): manual quiz back-office + rewrite README
...
Back-office (roadmap V1 step 7):
- server: token-protected HTTP API under /api/admin (ADMIN_TOKEN), Drizzle-backed
CRUD for manual questions — list, create (mcq/truefalse/free, category upsert,
dedup on prompt, validation), delete; 401/503 when unauthorized/unconfigured
- client: /admin page with token login + TanStack Query (list/create/delete),
format-aware form (QCM / vrai-faux / réponse libre)
- env: ADMIN_TOKEN
README: replace the shadcn template with a real NerdWare overview (stack,
structure, getting started, scripts, game modes, back-office).
Verified against real Postgres: auth (401), create (201), dedup (409),
validation (400), list, delete (200/404).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:43:19 +02:00
AyoubBenziza
a9eb6098f2
feat(blindtest): contributor-as-DJ scoring, 3-player gate, 16:9 player + seek
...
- DJ is now the track's contributor (controls their own song); their identity
is sent only to them so "who added" stays non-trivial. The contributor
doesn't vote and is excluded from the eligible-voters count.
- Scoring: the contributor earns nothing except in who_added/mixed, where they
get a misdirection bonus (50) per player who guesses the wrong adder.
- Blindtest (and mixed) require >= 3 connected players: lobby disables the
options with a hint, and game:start rejects with NEED_THREE.
- Player card is now 16:9 and full width — the video banner shows at reveal;
DJ gets a seek bar (current/duration) to jump anywhere, plus play/pause/restart.
- Mixed game order is shuffled (no predictable quiz/blindtest alternation).
Verified e2e (3 players): guard rejects at 2, DJ id hidden from others,
misdirection scoring correct. 23 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:30:47 +02:00
AyoubBenziza
98e06b8206
feat(blindtest): YouTube blindtest mode with neutral DJ + synced playback
...
Server:
- BlindtestRound (GameRound): neutral DJ pick (never the contributor),
per-mode scoring (title_artist fuzzy / who_added / mixed), reveal exposes
title/artist/submittedBy; contributor doesn't score on own track
- track submission: blindtest:submitTrack validates via YouTube oEmbed
(exists + embeddable) and captures title/artist; per-player quota; dedup
- DJ media relay: media:control (DJ only) → media:sync broadcast (engine)
- per-room shuffled track pool; submissions count in room snapshot
- shared: blindtest payloads, gameType/tracksPerPlayer in settings
- tests: DJ neutrality, scoring per mode, fuzzy match, youtube id extraction
Client:
- YouTube IFrame player (hidden behind a spinning disc — audio only, no
title leak), DJ transport (play/pause/restart), non-DJ follows media:sync
with latency compensation
- lobby: game-type switch (Quiz/Blindtest), blindtest config + per-player
track submission UI
- vote forms per mode; reveal card with title/artist/who-added
Roadmap V1 step 6 (highest technical risk). Server flow verified end-to-end
over the wire (submit→start→DJ relay→vote→reveal→score).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 13:02:28 +02:00
AyoubBenziza
29faa18731
feat(server,web): first real-time cycle — room create/join + lobby
...
Server (@nerdware/server):
- RoomManager: in-memory rooms (Map), code generation, create/join,
disconnect handling, public snapshot projection (no secrets)
- Socket.IO handlers: room:create / room:join with typed acks,
room:state broadcast on every change, lobby:updateSettings (host-only),
player:left on disconnect
Web (web):
- typed Socket.IO client + Zustand store mirroring room:state
- wouter routing: home (create/join) + minimal lobby (live player list)
- @nerdware/shared wired into the client
Roadmap V1 step 2. Verified end-to-end (create/join/broadcast/disconnect).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 15:16:26 +02:00