Commit Graph

113 Commits

Author SHA1 Message Date
cottongin
a2164c8242 fix: pass missing poll state setters to SessionInfo WebSocket handler
setPollEndingAt and setShowEndPollOptions were referenced in
SessionInfo's WS handler but never passed as props, causing a
ReferenceError that prevented setPollResult from executing on
delayed poll ends. Bumps version to 0.7.12.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 02:03:57 -04:00
cottongin
1d7395e121 fix: clear stale pollEndingAt state when starting a new poll
After a countdown-based poll end, pollEndingAt could remain set as a
stale value during the optimistic update in handleStartPolling, causing
the new poll to briefly render in the "Poll Ending" state with 0:00.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:05:59 -04:00
cottongin
26ce643351 chore: bump version to 0.7.11
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:40:00 -04:00
cottongin
59db8f6ed7 feat: poll countdown timer, game-selection sync, source tracking, and multi-admin fixes
Work spanning May 7-10 across multiple sessions:

Poll winner detection + source column (May 7):
- Fix race condition in handleEndPolling where WS voting.ended cleared
  leadingGame before the setTimeout could capture the winner
- Add pollActiveRef guard to prevent late poll.leading messages from
  re-activating an ended poll
- Add 'source' column to session_games (dice/manual/poll) with backward-
  compatible fallback from manually_added flag
- Show indigo "Poll" badge in game lists (Picker, Home, SessionDetail)
- Include source in session export (JSON and text formats)

Multi-admin poll state sync (May 9):
- Enrich poll.start broadcast with pollStartedAt timestamp so all admin
  clients can start their timers from the correct time
- Enrich voting.ended broadcast with winnerGameId/Label/Votes so all
  admins see the winner prompt, not just the one who clicked End Poll
- Add poll.start WS handler in SessionInfo so Admin B sees polls started
  by Admin A without refreshing
- Make handleStartPolling optimistic with rollback on failure

WebSocket keepalive + auto-reconnect (May 9):
- Add 30s ping interval to SessionInfo WS connection (matching server's
  60s timeout) to prevent silent disconnects
- Add auto-reconnect on close with 3s delay
- Proper cleanup of ping interval, reconnect timeout, and onclose handler

Sync selected game across admin clients (May 10):
- New POST/DELETE /sessions/:id/game-selection endpoints with DB
  persistence (pending_game_id, pending_game_source columns)
- Broadcast game.picked/game.dismissed WS events to session subscribers
- handleDismissGame replaces inline setSelectedGame(null) calls
- Restore pending game selection on page load for late-joining admins
- Clear pending selection when game is formally added to session

Poll ending countdown timer (May 10):
- POST /:id/voting/end now accepts optional { delay } (0-300 seconds)
- New POST /:id/voting/cancel-end to abort a scheduled end
- New poll.ending and poll.ending.cancelled WS events
- poll_ending_at column on sessions table for crash recovery
- rescheduleEndingPolls() called on server startup to resume countdowns
- End Poll button opens popover with End Now / 5s / 10s / 30s / custom
- Red "Poll Ending" card with countdown display and Cancel button
- Document new WS events in docs/api/websocket.md

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:33:00 -04:00
cottongin
a1078e0cc7 feat: add alarm sounds and sound controls to countdown timer widget
- Add four synthesized alarm sounds (Digital Beep, Gentle Chime, Urgent
  Alarm, Bell) using Web Audio API oscillators
- Add sound enable/mute toggle button and sound selector dropdown
- Add preview button to test selected alarm before countdown
- Play selected alarm sound when countdown expires (if enabled)
- Default widget mode to 'timer' instead of 'stopwatch'
- Extract shared inputClass constant for timer input styling
- Hide native number input spinners via Tailwind utility classes

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 14:37:00 -04:00
cottongin
4bbc1856f5 chore: bump version to 0.7.7 - Pokémon-Go-To-The-Polls Edition
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 20:44:30 -04:00
cottongin
4be520476c feat: add draggable stopwatch widget with lap counter and countdown timer
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>
2026-05-07 20:44:18 -04:00
cottongin
10c34557c5 feat: add poll control UI to Picker with start/end toggle, leading game indicator, and timer
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>
2026-05-07 20:44:04 -04:00
cottongin
9cd601bab2 feat: add poll start/end endpoints, poll.leading WS handler, and poll state persistence
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>
2026-05-07 20:43:39 -04:00
cottongin
1c9f0ef280 docs: add game-status-by-session guide and external downstream clients reference
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 20:43:10 -04:00
cottongin
195448644a feat: add Jackbox API Logger CLI tool
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>
2026-05-03 00:49:48 -04:00
cottongin
c5ffe23404 fix: detect game start for Pack 7+ titles that don't use state: "Gameplay"
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>
2026-05-03 00:23:32 -04:00
cottongin
2964cee291 chore: README: add AI warning 2026-04-05 06:07:31 -04:00
cottongin
91b7de3bb7 style: remove footer top margin, match presence bar bottom padding to 1rem, stack sections vertically
Made-with: Cursor
2026-04-05 05:24:17 -04:00
cottongin
ea23b66cbf feat: move presence bar to sticky bottom-right widget
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
2026-04-05 04:49:17 -04:00
cottongin
ea6e8db90b feat: ticker symbol voting for live votes
- 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
2026-04-05 04:47:06 -04:00
cottongin
b2bb2989e9 feat: role-aware presence bar, WebSocket logging fixes
- 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
2026-04-05 04:46:56 -04:00
cottongin
52e9a7af42 fix: handle unreadable admins.json in Docker and exclude from image
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
2026-04-05 01:17:22 -04:00
cottongin
0a59da8ee9 chore: add gitea templates 2026-03-23 12:18:39 -04:00
cottongin
a71ad7ae68 chore: add MIT license 2026-03-23 12:08:21 -04:00
cottongin
850fed5a87 chore: update README.md with new features and changes, version bump. 2026-03-23 12:04:03 -04:00
cottongin
0833cf6167 feat: add Prev/Next pagination bar to session history
Made-with: Cursor
2026-03-23 11:35:42 -04:00
cottongin
bfabf390b4 feat: render sessions grouped by day with styled header bars
Made-with: Cursor
2026-03-23 11:34:41 -04:00
cottongin
ad8efc0fbf feat: add pagination state and offset to session API calls
Made-with: Cursor
2026-03-23 11:32:59 -04:00
cottongin
db369a807e feat: add getLocalDateKey, formatDayHeader, formatTimeOnly date helpers
Made-with: Cursor
2026-03-23 11:31:35 -04:00
cottongin
d49601c54e feat: add offset pagination and X-Prev-Last-Date header to GET /sessions
Made-with: Cursor
2026-03-23 11:30:48 -04:00
cottongin
de1a02b9bb docs: pagination and day grouping implementation plan
Made-with: Cursor
2026-03-23 11:26:37 -04:00
cottongin
07858f973b docs: address spec review feedback (offset validation, header format, Tailwind class, polling)
Made-with: Cursor
2026-03-23 11:18:28 -04:00
cottongin
57ab3cf7ba docs: pagination and day grouping design spec
Made-with: Cursor
2026-03-23 11:16:33 -04:00
cottongin
c25db19008 chore: add superpowers to gitignore 2026-03-23 10:42:48 -04:00
cottongin
85c06ff258 fix: session count label distinguishes visible vs total
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
2026-03-23 10:41:38 -04:00
cottongin
3b18034d11 tweak: language for admin presence bar 2026-03-23 10:21:03 -04:00
cottongin
3da97a39ad chore: version bump 2026-03-23 10:03:24 -04:00
cottongin
04f66a32cc feat: docker-compose supports optional ADMIN_CONFIG_PATH
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
2026-03-23 10:00:46 -04:00
cottongin
95e7402d81 feat: PresenceBar component shows who is watching each page
Made-with: Cursor
2026-03-23 09:57:31 -04:00
cottongin
f0b614e28a feat: usePresence hook for WebSocket-based page presence
Made-with: Cursor
2026-03-23 09:57:22 -04:00
cottongin
242150d54c feat: WebSocket presence tracking with page_focus and presence_update
Made-with: Cursor
2026-03-23 09:55:56 -04:00
cottongin
a4d74baf51 feat: per-admin localStorage namespacing with migration
Made-with: Cursor
2026-03-23 09:42:50 -04:00
cottongin
9f60c6983d feat: auth route uses named admin lookup, embeds name in JWT
- 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
2026-03-23 09:38:35 -04:00
cottongin
fd72c0d7ee feat: add admin config loader with multi-key support
Made-with: Cursor
2026-03-23 03:46:09 -04:00
cottongin
ac26ac2ac5 Add named admins implementation plan
9 tasks covering config loader, auth changes, frontend identity,
preference namespacing, WebSocket presence, PresenceBar UI, and Docker config.

Made-with: Cursor
2026-03-23 03:41:55 -04:00
cottongin
0e5c66b98f Address spec review feedback for named admins design
Clarify WS auth rejection for stale tokens, enumerate all
migrated localStorage keys, and add theme exception note to overview.

Made-with: Cursor
2026-03-23 03:25:15 -04:00
cottongin
86725b6f40 Add named admins design spec
Covers multi-key admin config, per-admin localStorage preferences,
and real-time presence badges via WebSocket.

Made-with: Cursor
2026-03-23 03:19:03 -04:00
cottongin
512b36da51 fix: long-press select deselection bug, swap sun emoji for dice, bump version to 0.6.2
Made-with: Cursor
2026-03-23 02:48:56 -04:00
cottongin
d613d4e507 feat: rewrite History page with controls bar, multi-select, Sunday badge, and update SessionDetail with archive support
Made-with: Cursor
2026-03-23 02:21:37 -04:00
cottongin
bbd2e51567 feat: add POST /sessions/bulk endpoint for bulk archive, unarchive, and delete
Made-with: Cursor
2026-03-23 02:19:41 -04:00
cottongin
b40176033f feat: add POST archive and unarchive endpoints for sessions
Made-with: Cursor
2026-03-23 01:45:36 -04:00
cottongin
68045afbbc feat: add filter, limit, and X-Total-Count to session list endpoint
Made-with: Cursor
2026-03-23 01:42:51 -04:00
cottongin
35474e5df4 feat: add archived column to sessions table and isSunday helper
Made-with: Cursor
2026-03-23 01:40:07 -04:00
cottongin
4da2c15d56 docs: add session archive, multi-select, Sunday badge, and pagination implementation plan
Made-with: Cursor
2026-03-23 01:36:45 -04:00