Files
weirsoe-party-protocol/PROMPT.md
Asger Geel Weirsøe d2dbd8c802
Some checks failed
CI / test-and-quality (push) Has been cancelled
CI / test-and-quality (pull_request) Successful in 2m43s
docs: design doc for fup og fakta game engine + platform architecture
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>
2026-03-09 07:35:55 +01:00

3.3 KiB

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// 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)