From ddad1bc91437e6d3086741d703abb2e9bbc2b328 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:22:15 +0100 Subject: [PATCH 1/7] Add lobby MVP endpoints for create/join/session-state --- lobby/urls.py | 8 +++++ lobby/views.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 lobby/urls.py diff --git a/lobby/urls.py b/lobby/urls.py new file mode 100644 index 0000000..7df9970 --- /dev/null +++ b/lobby/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('create', views.create_session, name='lobby-create-session'), + path('join', views.join_session, name='lobby-join-session'), + path('state/', views.session_state, name='lobby-session-state'), +] diff --git a/lobby/views.py b/lobby/views.py index 91ea44a..8534a5d 100644 --- a/lobby/views.py +++ b/lobby/views.py @@ -1,3 +1,79 @@ -from django.shortcuts import render +import random +import string +import json -# Create your views here. +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse +from django.views.decorators.http import require_GET, require_POST +from django.views.decorators.csrf import csrf_exempt + +from fupogfakta.models import GameSession, Player + + +def _session_code(length: int = 6) -> str: + alphabet = string.ascii_uppercase + string.digits + for _ in range(20): + code = ''.join(random.choice(alphabet) for _ in range(length)) + if not GameSession.objects.filter(code=code).exists(): + return code + raise RuntimeError('Kunne ikke generere unik session-kode') + + +@login_required +@require_POST +def create_session(request): + session = GameSession.objects.create(host=request.user, code=_session_code()) + return JsonResponse({'ok': True, 'session': {'code': session.code, 'status': session.status}}) + + +@csrf_exempt +@require_POST +def join_session(request): + try: + payload = json.loads(request.body.decode('utf-8')) + except Exception: + payload = {} + + code = (payload.get('code') or '').strip().upper() + nickname = (payload.get('nickname') or '').strip() + + if not code or not nickname: + return JsonResponse({'ok': False, 'error': 'Mangler code eller nickname'}, status=400) + + try: + session = GameSession.objects.get(code=code) + except GameSession.DoesNotExist: + return JsonResponse({'ok': False, 'error': 'Ugyldig session-kode'}, status=404) + + if session.status == GameSession.Status.FINISHED: + return JsonResponse({'ok': False, 'error': 'Spillet er afsluttet'}, status=409) + + player, _created = Player.objects.get_or_create(session=session, nickname=nickname) + player.is_connected = True + player.save(update_fields=['is_connected']) + + return JsonResponse({ + 'ok': True, + 'player': {'id': player.id, 'nickname': player.nickname}, + 'session': {'code': session.code, 'status': session.status}, + }) + + +@require_GET +def session_state(_request, code: str): + code = code.strip().upper() + try: + session = GameSession.objects.get(code=code) + except GameSession.DoesNotExist: + return JsonResponse({'ok': False, 'error': 'Ugyldig session-kode'}, status=404) + + players = list(session.players.values('id', 'nickname', 'score', 'is_connected')) + return JsonResponse({ + 'ok': True, + 'session': { + 'code': session.code, + 'status': session.status, + 'current_round': session.current_round, + }, + 'players': players, + }) -- 2.39.5 From f26f1e2a5bbf96f4580c4a1c63d3b620cb008f49 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:22:58 +0100 Subject: [PATCH 2/7] Wire lobby routes into main URL config --- partyhub/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/partyhub/urls.py b/partyhub/urls.py index 4a4b4d3..373484e 100644 --- a/partyhub/urls.py +++ b/partyhub/urls.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.http import JsonResponse -from django.urls import path +from django.urls import path, include def health(_request): @@ -8,6 +8,7 @@ def health(_request): urlpatterns = [ + path('api/lobby/', include('lobby.urls')) , path('admin/', admin.site.urls), path('healthz', health, name='healthz'), ] -- 2.39.5 From e2e119380815ab4fc21a18769b3cf6602c559d68 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:23:43 +0100 Subject: [PATCH 3/7] Add i18n production-hardening checklist inspired by email-manager --- TODO.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TODO.md b/TODO.md index 3c359b9..af5891a 100644 --- a/TODO.md +++ b/TODO.md @@ -108,3 +108,11 @@ Byg **Weirsøe Party Protocol**: en dansk party-webapp platform ala Jackbox, hvo - [ ] (Need-to-have) Audit-log for host-handlinger (start/stop/skip) - [ ] (Nice-to-have) Runde-tema musik/lyd-cues - [ ] (Nice-to-have) Hurtig onboarding-skærm for nye spillere + +### Fase 11 — i18n (email-manager model) +- [ ] Sæt LANGUAGES op med dev (jank-english), en, da +- [ ] Tilføj LocaleMiddleware + LOCALE_PATHS +- [ ] Brug `{% load i18n %}` i templates + gettext i Python +- [ ] Opret .po for en og da (dev beholdes som udviklingssprog) +- [ ] Tilføj make-targets/kommandoer for makemessages og compilemessages +- [ ] Tilføj test der sikrer i18n tags i templates (inspireret af email-manager) -- 2.39.5 From d1e58811bb8d80aef83e92347ee09b3e26535109 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:25:36 +0100 Subject: [PATCH 4/7] Add CI quality-gate baseline and merge policy targets --- .gitea/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++++++ TODO.md | 7 +++++++ docs/QUALITY_GATES.md | 17 +++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 .gitea/workflows/ci.yml create mode 100644 docs/QUALITY_GATES.md diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..f277444 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + pull_request: + push: + branches: [ main, 'feature/**', 'release/**' ] + +jobs: + test-and-quality: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install pytest pytest-cov ruff black mypy + + - name: Lint + run: ruff check . + + - name: Format check + run: black --check . + + - name: Type check + run: mypy . || true + + - name: Tests + coverage + run: | + pytest --maxfail=1 --disable-warnings --cov=. --cov-report=term-missing --cov-report=xml --cov-fail-under=70 diff --git a/TODO.md b/TODO.md index af5891a..ac1f4a6 100644 --- a/TODO.md +++ b/TODO.md @@ -116,3 +116,10 @@ Byg **Weirsøe Party Protocol**: en dansk party-webapp platform ala Jackbox, hvo - [ ] Opret .po for en og da (dev beholdes som udviklingssprog) - [ ] Tilføj make-targets/kommandoer for makemessages og compilemessages - [ ] Tilføj test der sikrer i18n tags i templates (inspireret af email-manager) + +### Fase 12 — CI/CD og merge-gates (Gitea) +- [ ] Opret CI-workflow i .gitea/workflows/ci.yml +- [ ] Kør lint, format, tests, coverage i CI +- [ ] Enforce coverage >= 70% +- [ ] Branch protection på main (kræv grøn CI + review) +- [ ] Tilføj quality gate-dokumentation i docs/QUALITY_GATES.md diff --git a/docs/QUALITY_GATES.md b/docs/QUALITY_GATES.md new file mode 100644 index 0000000..aabd0e9 --- /dev/null +++ b/docs/QUALITY_GATES.md @@ -0,0 +1,17 @@ +# Quality gates (mål) + +## Merge til main kræver +1. Alle tests grønne +2. Test coverage >= 70% +3. Lint/format/type checks grønne + +## Planlagte checks +- pytest + pytest-cov (coverage XML + summary) +- ruff (lint) +- black --check (format) +- mypy (type checks, gradvis indfasning) + +## Enforcement i Gitea +- Branch protection på main +- Kræv successful checks fra CI-workflow før merge +- Kræv mindst 1 review (kan justeres) -- 2.39.5 From 2f102a1a5e0dc47797eef9f6b9eee79e24d26d56 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:33:08 +0100 Subject: [PATCH 5/7] Move project docs to repo wiki and keep docs folder minimal --- docs/ARCHITECTURE.md | 27 --------------------------- docs/QUALITY_GATES.md | 17 ----------------- docs/README.md | 8 ++++++++ 3 files changed, 8 insertions(+), 44 deletions(-) delete mode 100644 docs/ARCHITECTURE.md delete mode 100644 docs/QUALITY_GATES.md create mode 100644 docs/README.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index 6d57ec6..0000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,27 +0,0 @@ -# Arkitektur (MVP) - -## Moduler -- `core_admin`: global drift/admin, health, valideringer -- `lobby`: session creation/join, player presence -- `fupogfakta`: game rules, rounds, scoring (spil 1) -- `realtime`: websocket events + state sync -- `voice`: fælles voice-acting/TTS interface - -## Auth & sessions -- Login (username/password) kræves for at oprette/hoste spil -- Deltagelse i kørende spil sker via session-kode - -## Voice-acting (platformkrav) -- Alle spil skal kunne afspille voice lines via fælles interface -- Voice er modulært pr. spil (ikke hardcoded) - -## Realtidsmodel -- Host-screen og mobilklienter forbinder via websocket -- Autoritativ game state ligger server-side -- Klienter sender intents (`submit_lie`, `submit_guess`) -- Server broadcaster state transitions - -## Datamodel-principper -- Score beregnes server-side -- Hver scoreændring gemmes i `ScoreEvent` -- Runde-konfiguration gemmes per session (points ikke hardcoded) diff --git a/docs/QUALITY_GATES.md b/docs/QUALITY_GATES.md deleted file mode 100644 index aabd0e9..0000000 --- a/docs/QUALITY_GATES.md +++ /dev/null @@ -1,17 +0,0 @@ -# Quality gates (mål) - -## Merge til main kræver -1. Alle tests grønne -2. Test coverage >= 70% -3. Lint/format/type checks grønne - -## Planlagte checks -- pytest + pytest-cov (coverage XML + summary) -- ruff (lint) -- black --check (format) -- mypy (type checks, gradvis indfasning) - -## Enforcement i Gitea -- Branch protection på main -- Kræv successful checks fra CI-workflow før merge -- Kræv mindst 1 review (kan justeres) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..b679555 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,8 @@ +# Documentation moved to Wiki + +Projekt-dokumentation vedligeholdes i repo-wiki: + +- Wiki repo: `weirsoe-party-protocol.wiki` +- Gitea wiki URL: `https://gitea.weircon.dk/wpp/weirsoe-party-protocol/wiki` + +Denne `docs/` mappe holdes minimal fremover. -- 2.39.5 From e0fe152b834e2a83f140e073503435ed5a4c9ad8 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:53:35 +0100 Subject: [PATCH 6/7] Add coordination ledger for task/branch ownership --- coordination/README.md | 8 ++++++++ coordination/assignments.json | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 coordination/README.md create mode 100644 coordination/assignments.json diff --git a/coordination/README.md b/coordination/README.md new file mode 100644 index 0000000..7501962 --- /dev/null +++ b/coordination/README.md @@ -0,0 +1,8 @@ +# Coordination + +Denne mappe bruges af scheduler/dev-runners til at holde styr på: +- hvem der ejer hvilken opgave +- hvilken branch der er aktiv +- hvad der står i queue + +Single source of truth: `assignments.json`. diff --git a/coordination/assignments.json b/coordination/assignments.json new file mode 100644 index 0000000..15c0b3b --- /dev/null +++ b/coordination/assignments.json @@ -0,0 +1,5 @@ +{ + "updatedAt": "2026-02-27T00:00:00Z", + "active": [], + "queue": [] +} -- 2.39.5 From bd42d29b375940993ec241e9ab296c1ef8c42c15 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Fri, 27 Feb 2026 12:58:43 +0100 Subject: [PATCH 7/7] Add scheduler tracker for bot-specific work queue --- coordination/scheduler_tasks.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 coordination/scheduler_tasks.json diff --git a/coordination/scheduler_tasks.json b/coordination/scheduler_tasks.json new file mode 100644 index 0000000..2a8d9ce --- /dev/null +++ b/coordination/scheduler_tasks.json @@ -0,0 +1,26 @@ +{ + "updatedAt": "2026-02-27T00:00:00Z", + "tasks": [ + { + "id": "BOT-PR-POLICY", + "title": "Dev-runner skal oprette PR ved feature-ready", + "ownerRole": "job-scheduler", + "status": "active", + "priority": "high" + }, + { + "id": "BOT-REVIEW-ONLY-PRS", + "title": "Review-runner reviewer kun åbne PRs og commenter i PR", + "ownerRole": "review-runner", + "status": "active", + "priority": "high" + }, + { + "id": "BOT-MERGE-GATE", + "title": "Integrator-runner merger kun ved grønne gates", + "ownerRole": "integrator-runner", + "status": "active", + "priority": "high" + } + ] +} -- 2.39.5