Captures all brainstormed decisions: - Pluggable game cartridge platform (GameDriver interface) - Celery + Redis timer-driven phase transitions - Session owner play/pause/exit controls (no skip) - Escalating scoring per round, incremental reveal scoring - Emoji reactions during guess phase → post-game awards - Relational per-user config presets with game-specific models - Ephemeral game state (no persistence after exit/finish) - Full WebSocket event reference and data lifecycle Also: updated TODO.md (WebSocket done, persisted answers done), created CLAUDE.md, and PROMPT.md for ralph-loop. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
72 lines
3.3 KiB
Markdown
72 lines
3.3 KiB
Markdown
# Ralph Loop: Implement WebSocket push for Weirsøe Party Protocol
|
|
|
|
## Context
|
|
- Project: /home/agw/projects/weirsoe-party-protocol
|
|
- Backend: Django 6.0.2 + Django Channels + Redis
|
|
- The full game REST flow is already implemented in lobby/views.py
|
|
(create_session, join_session, start_round, show_question, submit_lie,
|
|
mix_answers, submit_guess, calculate_scores, reveal_scoreboard, finish_game)
|
|
- realtime/ app exists but is a stub (no consumers.py, no routing)
|
|
- partyhub/settings.py has channels in INSTALLED_APPS but no CHANNEL_LAYERS or routing
|
|
- PO hard requirement: WebSocket push is mandatory in MVP (no polling)
|
|
|
|
## What to build
|
|
|
|
### 1. realtime/consumers.py — GameConsumer
|
|
- AsyncJsonWebsocketConsumer
|
|
- Connects to group game_{session_code} on connect (session_code from URL)
|
|
- Player auth: session_token query param validated against Player model
|
|
- Host auth: query param role=host, no token required for MVP
|
|
- On disconnect: clean leave from group
|
|
- Handles incoming message type "ping" -> replies with {"type": "pong"}
|
|
- Forwards broadcast group events to WebSocket client
|
|
|
|
### 2. partyhub/settings.py — CHANNEL_LAYERS
|
|
Add CHANNEL_LAYERS using channels_redis.core.RedisChannelLayer.
|
|
Read CHANNEL_REDIS_HOST (default 127.0.0.1) and CHANNEL_REDIS_PORT (default 6379) from env.
|
|
|
|
### 3. partyhub/asgi.py — ASGI routing
|
|
Wire URLRouter so ws/game/<session_code>/ routes to GameConsumer.
|
|
Keep existing HTTP routing intact.
|
|
|
|
### 4. realtime/routing.py
|
|
Define websocket_urlpatterns list.
|
|
|
|
### 5. realtime/broadcast.py — broadcast helper
|
|
- async def broadcast_phase_event(session_code, event_type, payload)
|
|
Sends to group game_{session_code} via channel layer.
|
|
- def sync_broadcast_phase_event(session_code, event_type, payload)
|
|
Sync wrapper using async_to_sync for calling from sync REST views.
|
|
|
|
### 6. lobby/views.py — hook broadcasts into phase transitions
|
|
After each phase transition, call sync_broadcast_phase_event:
|
|
- start_round -> phase.lie_started (question prompt + time limit)
|
|
- show_question -> phase.question_shown (question text)
|
|
- mix_answers -> phase.guess_started (shuffled answers + time limit)
|
|
- calculate_scores -> phase.scores_calculated (per-player score delta)
|
|
- reveal_scoreboard -> phase.scoreboard (ranked player list)
|
|
- finish_game -> phase.game_over (final rankings)
|
|
|
|
### 7. realtime/tests.py — basic tests
|
|
- Connect/disconnect test using channels.testing.WebsocketCommunicator
|
|
- Verify a broadcast reaches a connected client
|
|
|
|
## Constraints
|
|
- Keep auth simple: session_token query param for players, unauthenticated host in MVP
|
|
- Use async_to_sync wrapper for sync REST views calling async broadcast
|
|
- Do not break existing REST tests (python manage.py test lobby must still pass)
|
|
- After each file written, run: python manage.py check
|
|
- Follow existing code style in lobby/views.py
|
|
|
|
## Completion criteria
|
|
Output the exact text: WEBSOCKET COMPLETE
|
|
|
|
...when ALL of the following are true:
|
|
- realtime/consumers.py exists and handles connect/disconnect/ping
|
|
- realtime/broadcast.py exists with sync_broadcast_phase_event
|
|
- partyhub/settings.py has CHANNEL_LAYERS configured
|
|
- partyhub/asgi.py routes ws/game/<code>/ to GameConsumer
|
|
- All 6 phase transitions in lobby/views.py call sync_broadcast_phase_event
|
|
- python manage.py check passes with no errors
|
|
- python manage.py test lobby passes (existing tests not broken)
|