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>
4.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Weirsøe Party Protocol is a Danish party game web platform (Jackbox-style) where games display on a primary screen and players participate via mobile. The MVP game is "Fup og Fakta" (a Fibbage-style lie-and-guess game).
- Backend: Django 6.0.2 + Django Channels (WebSockets) + Redis
- Frontend: Angular 19 shell + shared TypeScript API client library
- Database: MySQL (SQLite fallback for dev)
- Deployment: Proxmox LXC containers (not Docker)
Commands
Backend (Django)
python manage.py runserver # Dev server
python manage.py migrate # Apply migrations
python manage.py test # Run all backend tests
python manage.py test lobby # Run tests for a single app
python manage.py shell # Django shell
Frontend — API client (/frontend)
cd frontend
npm install
npm test # Vitest unit tests
npm run build # TypeScript compile check (--noEmit)
Frontend — Angular shell (/frontend/angular)
cd frontend/angular
npm install
npm start # Dev server (ng serve)
npm run build # Production build
npm run test # Vitest unit tests
i18n validation
python scripts/check_i18n_drift.py # Check for key drift between locales
Architecture
Backend apps
| App | Purpose |
|---|---|
partyhub/ |
Main Django project — settings, root URLs, ASGI/WSGI, i18n bootstrap |
lobby/ |
Session & player management — create/join session, locale-aware error responses |
fupogfakta/ |
Game logic — all domain models, score calculation (server-authoritative) |
realtime/ |
WebSocket event layer (stub) |
voice/ |
Voice/TTS interface (stub, Phase 2) |
core_admin/ |
Health endpoint (/healthz), global admin |
Key domain models (all in fupogfakta/models.py): GameSession, Player, Category, Question, RoundConfig, RoundQuestion, LieAnswer, Guess, ScoreEvent.
Score calculation is server-side only. ScoreEvent provides an auditable trail of all point changes.
Frontend layers
- Shared API client (
frontend/src/) — pure TypeScript, framework-agnostic. Defines all API types (api/types.ts) and HTTP client abstraction (api/client.ts). - Angular shell (
frontend/angular/) — Angular 19 standalone components (no NgModules), hash-based routing.host-shell.componentfor the presenter screen;player-shell.componentfor mobile players.
The Angular shell consumes the shared client via frontend/src/api/angular-client.ts.
Real-time flow
LOBBY → LIE → GUESS → REVEAL → FINISHED — phase transitions broadcast a PhaseViewModel to all connected clients via WebSocket. Clients are read-only; only the server is authoritative for state.
i18n
- Single source of truth:
shared/i18n/lobby.json(keys in bothenandda) - Loaded once at startup with LRU cache (
partyhub/i18n_bootstrap.py) - Key naming: domain-first —
frontend.ui.host.*,frontend.ui.player.*,backend.errors.*,backend.error_codes.* - Locale resolved from
Accept-Languageheader; missing key returns key + logs warning; missing translation falls back toen
Key Conventions
Errors
Backend error responses use stable machine-readable codes (backend.error_codes.*) with separately localized messages. Never couple error code strings to locale.
Game constraints (MVP)
- 3–12 players per session
- Session codes: 6-char alphanumeric (no 0/O/1/I/L)
- Anti-cheat: no duplicate lies, lies cannot match the correct answer, answer order randomized
Git workflow
main: stable baselinefeature/<name>: development branchesrelease/vX.Y.Z: release preparation- Release: merge → create release branch → update
VERSION+CHANGELOG.md→ tag → push
TypeScript
Strict mode required. Target ES2022. API response interfaces in frontend/src/api/types.ts must match backend responses exactly.
Database
Use ForeignKey with explicit on_delete (PROTECT/CASCADE/SET_NULL). Add db_index=True on frequently queried fields. Migrations are auto-generated by Django and versioned in migrations/.
Environment Variables
DJANGO_SECRET_KEY, DJANGO_DEBUG, DJANGO_ALLOWED_HOSTS
DB_ENGINE, DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT
CHANNEL_REDIS_HOST, CHANNEL_REDIS_PORT
USE_SPA_UI (fallback: WPP_SPA_ENABLED)
WPP_SPA_ASSET_BASE, WPP_SPA_ASSET_VERSION
Test Files of Note
lobby/tests.py— comprehensive Django TestCase coverage for session/player/i18n/error flowsfrontend/angular/src/app/api-contract-smoke.spec.ts— API contract smoke testsfrontend/angular/src/app/lobby-i18n.spec.ts— i18n parity checksfrontend/tests/lobby-loader.parity.test.ts— shared i18n loader parity