Jeopardy-Spiel für Moderation über Beamer oder Screenshare: Startseite mit Team- und Themenauswahl, 5×5-Spielfeld, Frage-Popup mit Punktevergabe. Später ist ein Online-Modus vorgesehen; die Auslieferung erfolgt als Docker-Container.
- Technisches Konzept – Architektur, Datenmodell, Design, Betrieb
- Arbeitsplan & Subtasks – Aufgabenschnitt, Commit-Regeln, Umsetzungsstand
- Fragen pflegen – Aufbau der Fragenpools, Schwierigkeit, Import
- Inhalte für Agents erstellen – Kategorien, Spalten und Fragen als ergänzende SQL-Dateien, Tabellen und Qualitätsregeln
- Agent-Skill: create-jeopardy-questions – wiederverwendbarer Workflow und SQL-Vorlage zur manuellen Übernahme
- Fragen-Datenbank und API – PostgreSQL, lokale Einrichtung, Zugriff weiterer Anwendungen, Import und Backup
- Admin-Backend – Fragen pflegen, SQL-Lieferungen mit Testlauf einspielen, Protokoll und Anmeldung über Authentik
- Kubernetes-Deployment-Übergabe – Images, Konfiguration, Datenbank, Sicherheit und Abnahme für den Deployment-Agenten
- Architekturentscheidungen: Schnittstellen-Vertrag · Technologie-Stack · Transport-Naht · Auslieferung im Container
Startseite: Teams festlegen (ein Team genügt – dann läuft das Spiel als Übungsmodus ohne Ranking), eine Themenkategorie wählen und die Schwierigkeit von 1 bis 5 einstellen. Beim Start zieht das Spiel aus dem Fragenvorrat der Kategorie ein eigenes 5×5-Spielfeld: fünf Rubriken als Spalten, je fünf Fragen in aufsteigender Härte. Jede Partie bekommt andere Fragen – wer dieselbe noch einmal spielen will, teilt den Link, in dem die Ziehungsnummer steht. Alternativ lässt sich weiterhin ein fertiges Fragenset als JSON-Datei laden.
Auf dem Spielfeld öffnet ein Klick auf eine Karte die Frage; die Musterlösung und die Punktebuttons erscheinen erst nach „Antwort anzeigen". Erst ein Punktebutton wertet die Frage – dann wird die Karte grau. Punkte werden addiert oder abgezogen und fallen nie unter null. Teamnamen lassen sich jederzeit oben ändern, die Punktebuttons übernehmen den Namen sofort. Ein laufendes Spiel übersteht das Schließen des Browsers. Bei „Neues Spiel“ – auch aus der Auswertung – sind Teams, Kategorie, Schwierigkeit, Bedenkzeit, Veto-Zeit und Abzugsregel vorbelegt. Die Ziehung wird erneuert und die Punkte beginnen bei null. Importierte JSON-Spiele bleiben als Vorlage ausgewählt.
Jede Frage im Vorrat trägt eine Stufe von 1 bis 9. Der Regler schiebt darüber ein Fenster von fünf Stufen – eine je Zeile. In jeder Reglerstellung bekommt das Brett damit fünf verschiedene, aufsteigende Stufen: Die 100er-Karte ist immer die leichteste, die 500er immer die schwerste. Die Skala reicht bis 9, weil das Fenster fünf Stufen breit ist und der Regler es um vier Stellungen weiterschiebt:
| Regler | 100er | 200er | 300er | 400er | 500er |
|---|---|---|---|---|---|
| 1 Locker | 1 | 2 | 3 | 4 | 5 |
| 2 Leicht | 2 | 3 | 4 | 5 | 6 |
| 3 Ausgewogen | 3 | 4 | 5 | 6 | 7 |
| 4 Fordernd | 4 | 5 | 6 | 7 | 8 |
| 5 Für Kenner | 5 | 6 | 7 | 8 | 9 |
Punkte bleiben immer 100 bis 500: Sie ordnen das Brett und sind nur innerhalb einer Partie vergleichbar. Details zum Vorrat stehen in content/README.md.
Über „Fragen bewerten“ auf der Startseite lässt sich die Schwierigkeit zufälliger Fragen kalibrieren: erst Frage, dann Antwort und Bewertung. „Zu schwer“ erhöht den Schwierigkeitswert um 0,2, „zu leicht“ senkt ihn um 0,2; „Schwierigkeit passt“ zählt eine Zustimmung ohne Scoreänderung. Die drei Buttons zeigen die gerundete aktuelle und die benachbarten Stufen. PostgreSQL speichert Score und Historie. Neue Spiele nutzen die gerundete Stufe; laufende und importierte JSON-Spiele bleiben unverändert. Details: Schwierigkeitsbewertung.
Unter /admin lassen sich Fragen suchen, bearbeiten, anlegen und löschen sowie SQL-Lieferungen
aus content/sql/ einspielen – erst als Testlauf mit Rollback, dann dauerhaft. Jede Änderung
landet mit Benutzer im Protokoll. Die Anmeldung übernimmt Authentik am Ingress; lokal genügt
ADMIN_AUTH=dev npm run dev:api. Details: Admin-Backend.
npm install
docker compose up -d postgres api --build
npm run dev # http://localhost:5173| Befehl | Zweck |
|---|---|
npm run dev |
Entwicklungsserver |
npm run dev:api |
Fragen-API (benötigt DATABASE_URL) |
npm run db:migrate |
PostgreSQL-Schema migrieren |
npm run db:seed |
Fragen einmalig initialisieren |
npm run db:import |
JSON-Pools bewusst in PostgreSQL übernehmen |
npm run test:db |
Integration gegen separate PostgreSQL-Test-DB |
npm run build |
Produktions-Build nach apps/web/dist |
npm run preview |
Gebautes Ergebnis lokal ausliefern |
npm run lint |
ESLint über das gesamte Monorepo |
npm run typecheck |
TypeScript-Prüfung aller Projekte |
npm test |
Unit- und Komponententests (Vitest) |
npm run test:coverage |
Tests mit Coverage-Schwellen für game-core |
npm run test:junit |
Wie oben, zusätzlich JUnit-Bericht für CI |
npm run test:e2e |
End-to-End-Tests (Playwright) |
npm run validate:content |
Prüft Index und Fragenpools in content/topics |
npm run build:info |
Commit und Datum für die Fußzeile bereitstellen |
Gebaut und geprüft wird auf jenkins.d39s.de; die Pipeline steht im Jenkinsfile und nutzt
die gemeinsame jenkins-library. Zwei Stufen:
- Prüfen im
playwright-Pod:npm ci, Formatprüfung, Lint, Typecheck, Seed-/Importdaten, Unit- und Komponententests, echte PostgreSQL-Integration und End-to-End-Tests. Ein PostgreSQL-Sidecar mit temporärem Volume stellt eine isolierte Testdatenbank bereit. UI-Browsertests mocken die API; die DB-Tests prüfen Migration, Import, Scores und Speicherung. Die Testberichte entstehen als JUnit unterreports/und laufen überpublishChecks/withChecksals GitHub-Check zurück; der Playwright-Bericht wird als Artefakt gesichert. - Images bauen über den Library-Schritt
kaniko, jeweils in einem eigenen Pod.docker/Dockerfileliefertharbor.d39s.de/library/web-jeopardy,docker/api.Dockerfileliefertharbor.d39s.de/library/web-jeopardy-api. Beide nutzen das Repository-Wurzelverzeichnis als Kontext und dieselbe Tag-Strategie. Vor dem Web-Build schreibt die Stufe Commit und Baudatum nachapps/web/.env.production– im Kontext liegt kein.git, sonst bliebe die Fußzeile der Startseite ohne Commit.
Die Tags vergibt die Library: br-<zweig> auf Zweigen, pr-<nummer> bei Pull Requests,
latest auf dem Hauptzweig und Versionsnummern aus Git-Tags. Gibt es kein Ziel, baut kaniko
mit --no-push – der Build wird also auch dort geprüft, wo nichts veröffentlicht wird.
Eine GitHub-Action gibt es nicht mehr; Jenkins meldet die Ergebnisse als Check nach GitHub zurück.
npm run build:info # Commit und Datum für die Fußzeile, siehe Versionierung
docker compose up --build # http://localhost:8080Compose startet Weboberfläche über nginx, Node-Fragen-API, PostgreSQL 17 und lokales pgAdmin. Die vorhandenen Fragen werden beim ersten API-Start übernommen. Besonderheiten:
- Persistente Fragen: PostgreSQL speichert Fragen in einem benannten Volume. Die API
liefert Themen und Pools über
/api/v1; nginx leitet diese Anfragen weiter. - Fragen ohne neues Image: per API ändern oder JSON-Pools nach Prüfung mit
docker compose exec api npm run db:importübernehmen. Neustarts überschreiben nichts. - JSON-Spielimport: fertige Spiele werden weiterhin lokal im Browser importiert, unabhängig von Datenbank und API.
- Verlaufsadressen: unbekannte Pfade beantwortet
index.html,/gamefunktioniert also auch beim direkten Aufruf. - Zwischenspeicher: gehashte Dateien in
/assetswerden dauerhaft gecacht,index.html, API-Antworten und/config.jsonbewusst nicht. - Laufzeitkonfiguration: Der Einstiegspunkt schreibt
config.jsonaus Umgebungsvariablen (derzeitJEOPARDY_WS_URLals Platzhalter für den späteren Online-Modus), sodass dasselbe Image in mehreren Umgebungen läuft. - API-Ziel im Frontend-Pod:
JEOPARDY_API_URLsetzt beim Containerstart das nginx-Ziel, standardmäßighttp://api:3001. In Kubernetes etwahttp://jeopardy-api:3001verwenden, ohne abschließenden Slash oder/api. Browseranfragen bleiben auf/api/v1derselben Origin. - Keine Fragen im Webimage: Die JSON-Pools sind nur Seed-/Importquelle im API-Image und Testdaten im Repository. Das Frontend lädt alle Fragen ausschließlich aus PostgreSQL via API.
apps/web/ Oberfläche (React, Vite, Tailwind)
apps/api/ Fragen-API, PostgreSQL-Zugriff, Migrationen und Import
packages/game-core/ Spiellogik ohne Framework-Bezug (Typen, Schemas, Reducer, Ziehung)
content/topics/ JSON-Seed und Importquelle, Laufzeitdaten liegen in PostgreSQL
docker/ Dockerfile, nginx-Konfiguration, Compose
docs/ Konzept, Arbeitsplan, ADRs
e2e/ End-to-End-Tests
Unten auf der Startseite steht, welcher Stand gerade läuft:
Version 2.1.0 · Commit d186d11 · Stand 09.09.2026
So ist auf jedem Beamer und in jedem Screenshot ablesbar, welches Build zu sehen ist. Der Commit-Hash führt per Klick zum Stand im GitHub-Repository.
Maßgeblich ist die version in der package.json im Wurzelverzeichnis. Jede weitere
Änderung und jedes Release folgt Semantic Versioning –
MAJOR.MINOR.PATCH:
| Stufe | Wann sie steigt |
|---|---|
| MAJOR | Bruch am Verhalten oder an den Daten, etwa ein neues Schema für Fragensets |
| MINOR | Neue Funktion, abwärtskompatibel |
| PATCH | Fehlerbehebung ohne neue Funktion |
Bis 0.2.0 galt eine Vorabphase, in der auch Brüche nur MINOR erhöht haben. Seit 2.1.0 gilt SemVer ohne Ausnahme: Ein Bruch erhöht immer MAJOR. Die Version wandert nicht mit jedem Commit, sondern mit dem Release. Ein Release setzt alle Arbeitsbereiche gemeinsam und legt das Git-Tag an, aus dem die Pipeline die Image-Tags ableitet:
npm version <major|minor|patch> --workspaces --include-workspace-root
git push --follow-tagsCommit und Datum kommen aus dem Build, nicht aus dem Quelltext:
- Lokal (
npm run dev,npm run build) liest Vite den kurzen Commit-Hash direkt aus dem Arbeitsverzeichnis; als Datum gilt der Zeitpunkt des Builds. - Im Container gibt es kein
.git(siehe.dockerignore). Dort liefertnpm run build:infodie Angaben vorab alsapps/web/.env.production; die Jenkins-Pipeline schreibt dieselbe Datei ausGIT_COMMIT. Fehlt sie, steht in der FußzeileCommit unbekannt.
Verbindliche Commit-Regeln und Best Practices stehen in
docs/arbeitsplan.md (Kapitel 6 und 7). Kurzfassung: Conventional
Commits, kleine Commits, main bleibt jederzeit grün, Releases nach SemVer.