Commit graph

7 commits

Author SHA1 Message Date
lila
f2eb6ce17f feat(web): add multiplayer lobby, game, and score screen routes
- lobby.$code.tsx: waiting room with live player list via lobby:state,
  copyable lobby code, host Start Game button (disabled until 2+ players),
  sends lobby:join on connect, lobby:leave on unmount
- game.$code.tsx: in-game view, sends game:ready on mount to get current
  question, handles game:question/answer_result/finished messages,
  reuses QuestionCard component, shows round results after each answer
- MultiplayerScoreScreen: final score screen sorted by score, highlights
  winner(s) with crown, handles ties via winnerIds array, Play Again
  navigates back to lobby, Leave goes to multiplayer landing
- GameRouteSearchSchema added to shared for typed lobbyId search param
  without requiring Zod in apps/web
2026-04-18 10:33:48 +02:00
lila
6975384751 feat(api): add game:ready message for client state sync
- WsGameReadySchema added to shared schemas and WsClientMessageSchema
- handleGameReady sends current game:question directly to requesting
  client socket (not broadcast) — foundation for reconnection slice
- router dispatches game:ready to handleGameReady handler
2026-04-18 09:54:31 +02:00
lila
745c5c4e3a feat(api): add WebSocket foundation and multiplayer game store
- Add ws/ directory: server setup, auth, router, connections map
- WebSocket auth rejects upgrade with 401 if no Better Auth session
- Router parses WsClientMessageSchema, dispatches to handlers,
  two-layer error handling (AppError -> WsErrorSchema, unknown -> 500)
- connections.ts: in-memory Map<lobbyId, Map<userId, WebSocket>>
  with addConnection, removeConnection, broadcastToLobby
- LobbyGameStore interface + InMemoryLobbyGameStore implementation
  following existing GameSessionStore pattern
- multiplayerGameService: generateMultiplayerQuestions() decoupled
  from single-player flow, hardcoded defaults en->it nouns easy 3 rounds
- handleLobbyJoin and handleLobbyLeave implemented
- WsErrorSchema added to shared schemas
- server.ts switched to createServer + setupWebSocket
2026-04-17 09:36:16 +02:00
lila
cf56399a5e feat(db): add lobbies and lobby_players tables + model
- Add lobbies and lobby_players tables with camelCase TS aliases
- Add LOBBY_STATUSES constant in shared
- Add lobbyModel with atomic addPlayer and transactional finishGame
- Enable Drizzle relational query API via { schema } option
2026-04-16 19:08:53 +02:00
lila
47a68c0315 feat(db): add lobbies and lobby_players tables + model 2026-04-16 14:45:45 +02:00
lila
ea33b7fcc8 feat(web): add minimal playable quiz at /play
- Add Vite proxy for /api → localhost:3000 (no CORS needed in dev)
- Create /play route with hardcoded game settings (en→it, nouns, easy)
- Three-phase state machine: loading → playing → finished
- Show prompt, optional gloss, and 4 answer buttons per question
- Submit answers to /api/v1/game/answer, show correct/wrong feedback
- Manual Next button to advance after answering
- Score screen on completion
- Add selectedOptionId to AnswerResult schema (discovered during
  frontend work that the result needs to be self-contained for
  rendering feedback without separate client state)

Intentionally unstyled — component extraction and polish come next.
2026-04-11 12:56:03 +02:00
lila
ce6dc4fa32 feat(shared): add quiz session Zod schemas
Add the shared schemas for the quiz request/response cycle, defining
the contract between the API and the frontend.

- Reorganise packages/shared: move schemas into a schemas/ subdirectory
  grouped by domain. Delete the old flat schema.ts.
- Add AnswerOption, GameQuestion, GameSession, AnswerSubmission, and
  AnswerResult alongside the existing GameRequest.
- optionId is an integer 0-3 (positional, shuffled at session-build
  time so position carries no information).
- questionId and sessionId are UUIDs (globally unique, opaque, natural
  keys for Valkey storage later).
- gloss is  rather than optional, for a predictable
  shape on the frontend.
- options array enforced to exactly 4 elements at the schema level.
2026-04-10 21:43:53 +02:00