New general-purpose floating stopwatch accessible from a clock icon in
the nav bar. Supports two modes: stopwatch (count up with laps) and
countdown timer (presets + custom input, red flash on expiry). Desktop
renders as a compact draggable card; mobile docks to the bottom as a
fixed sheet. Timer persists while hidden.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds a three-state poll control card (Start Poll / End Poll / Poll Result)
with an LED-style stopwatch on the End Poll button. Shows the current poll
leader from downstream poll.leading WebSocket messages. On poll end, prompts
the admin to use the winner as the next game choice or ignore it. Restores
poll state from the session on page load for continuity across reloads.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds POST /:id/voting/start and POST /:id/voting/end endpoints that
broadcast poll lifecycle events and persist poll state to the sessions
table. The poll.leading WebSocket message is now handled server-side
(rebroadcast + DB persist) with self-healing for polls started before
the persistence columns existed.
Co-authored-by: Cursor <cursoragent@cursor.com>
Standalone tool that connects to a Jackbox room by code, captures all
websocket events, and logs summarized output to console + full JSON to
a JSONL file. Consolidates scattered scripts/ws-probe.js,
ws-lifecycle-test.js, and get-jackbox-player-count.js into one
cohesive debugging tool.
Co-authored-by: Cursor <cursoragent@cursor.com>
Pack 7 games (Quiplash 3, Blather Round) transition room state from
"Lobby" to "Logo" instead of "Gameplay". Even newer titles (Doominate,
Big Survey) have no room entity at all — the only signals are room/lock
and room/exit opcodes.
- parseRoomEntity: detect game started as any non-Lobby state
- handleMessage: add room/lock and room/exit opcode handling
- handleRoomLock: emit game.started as fallback for room-entity-less games
- handleRoomExit: emit game.ended on explicit room close
- Tests: 6 new tests covering Logo state, room/lock, room/exit
Verified against live rooms: quiplash3, blanky-blank, you-ruined-it,
bigsurvey.
Co-authored-by: Cursor <cursoragent@cursor.com>
Reposition the presence bar from above main content to a sticky
bottom-right indicator that docks above the footer on scroll.
Sized to fit content rather than spanning full width.
Made-with: Cursor
- Add ticker column to games table with migration
- Bootstrap tickers from tickers.json config on startup
- POST /api/votes/live accepts optional ticker field for direct game
lookup (bypasses timestamp-interval matching)
- Ticker votes work for any game, not just session games
- Update API docs and add e2e tests for ticker voting
- Version bump to 0.6.5
Made-with: Cursor
- findAdminByKey returns role from admins.json (defaults to 'admin')
- JWT includes config-defined role instead of hardcoded 'admin'
- PresenceBar split into "who's here?" (page admins) and "connected"
(bot/utility services with icon+color badges)
- Bot/utility roles appear in presence on all pages when connected
- usePresence hook uses refs to avoid WS reconnect on navigation
- WS auth log prints admin name instead of generic 'admin'
- WS connection log reads X-Forwarded-For for real client IP
- AuthContext stores adminRole from login response
- Uncomment admins.json Docker volume mount, add SELinux :z flags
Made-with: Cursor
Use fs.accessSync to check read permissions before reading the config
file. If the file exists but isn't readable, log a warning and fall
through to the ADMIN_KEY fallback. Also add config/admins.json to
backend/.dockerignore to prevent it from being copied into the image.
Made-with: Cursor
Show "X visible (Y total)" when the history list is filtered or limited,
and "X sessions total" only when every session is actually displayed.
Made-with: Cursor
ADMIN_KEY is now optional (falls back handled by load-admins.js).
Added ADMIN_CONFIG_PATH env var and commented volume mount example.
Made-with: Cursor
- Login/verify use findAdminByKey; JWT and response include admin name
- Verify returns 403 when token lacks name (legacy tokens)
- Test tokens include name for getAuthToken()
- Set Content-Type on supertest JSON bodies (superagent/mime resolution)
Made-with: Cursor