This commit is contained in:
+36
-23
@@ -9,13 +9,13 @@ Das Dashboard von Mindflux (`mindflux2`, Spring Boot 3.4.4 / Java 17 / PostgreSQ
|
||||
3. **Bug Hunter** – „Finde Fehler im Code, denke wie ein Debugger und löse knifflige Bugs."
|
||||
4. **Netzwerker – Das Router-Rätselspiel** – „Verbinde Netzwerke, konfiguriere IPs und löse Routing-Herausforderungen."
|
||||
|
||||
Die Infrastruktur wartet bereits auf sie: Die Spiel-Keys `escape-room`, `service-clash`, `bug-hunter`, `netzwerker` stehen schon in der Score-Allowlist (`GameScoreController.KNOWN_GAMES`, Zeile 23–25) und in `ProgressService.GAMES` (Zeile 23–26); die Dashboard-Icons (`lock`, `sword`, `bug`, `network`) existieren in `dashboard.html`. Ziel dieses Plans: detaillierte, umsetzungsreife Designs für alle vier Spiele nach dem etablierten Architektur-Rezept der vorhandenen Spiele (MindMatch, TechTacular, Syntax Saga, Dev Lab) sowie ein priorisierter Verbesserungs-/Optimierungskatalog für den Rest der Plattform.
|
||||
Die Infrastruktur wartet bereits auf sie: Die Spiel-Keys `codeescape`, `serviceclash`, `bughunter`, `networker` stehen in der Score-Allowlist (`GameScoreController.KNOWN_GAMES`) und in `ProgressService.GAMES`; die Dashboard-Icons (`lock`, `sword`, `bug`, `network`) existieren in `dashboard.html`. Ziel dieses Plans: detaillierte, umsetzungsreife Designs für alle vier Spiele nach dem etablierten Architektur-Rezept der vorhandenen Spiele (MindMatch, TechTacular, SyntaxSaga, DevLab) sowie ein priorisierter Verbesserungs-/Optimierungskatalog für den Rest der Plattform.
|
||||
|
||||
**Zielgruppe & inhaltlicher Anspruch: die GESAMTE Fachinformatiker-Ausbildung.** Nicht nur AP1 – abgedeckt werden muss die komplette Ausbildung bis einschließlich **AP2** (beide Fachrichtungen: Anwendungsentwicklung/FIAE und Systemintegration/FISI). Konsequenzen für alle Spiele und Inhalte:
|
||||
|
||||
- **Schwierigkeitsstufen = Ausbildungsprogression.** Die in allen vier Designs vorhandenen Stufen (Junior/Senior/Principal, leicht/mittel/schwer, Welten 1–3, Schicht 1–3) werden inhaltlich gemappt: untere Stufen ≈ 1. Lehrjahr/AP1-Stoff, obere Stufen ≈ AP2-Niveau. Kein Schema-Umbau nötig – die `difficulty`-Felder existieren in allen Datenmodellen bereits; es ist eine **Content-Kuratierungs-Regel**.
|
||||
- **AP2-Content pro Spiel (Startrichtung):** CodeEscape → Szenarien zu Verschlüsselung/Zertifikaten, Virtualisierung/Container, Backup-Strategien; BugHunter → Principal-Fälle auf FIAE-AP2-Niveau (Nebenläufigkeit/Threads, Transaktions-/SQL-Fehler, Design-Pattern-Missbrauch, OWASP-Lücken); ServiceClash → Schichten mit Change-Management, Monitoring/Eskalationsketten, Security-Incidents (FISI-AP2); NetWorker → Welten zu VLAN, statischem Routing über mehrere Hops, Firewall-Regeln und (Ausbau) IPv6/Subnetting-Transfer.
|
||||
- **Content-Tagging:** Beim Kuratieren jedes Inhalts (Seeder-JSONs, Admin-Eingaben) wird vermerkt, ob er AP1-, AP2/FIAE- oder AP2/FISI-relevant ist – zunächst als Konvention im Titel/`description` (z. B. Präfix „[AP2]"), später optional als eigenes Feld + Filter in den Lobbys („Zeige nur AP2-Stoff").
|
||||
- **Content-Tagging:** Neue Parent-Inhalte erhalten von Anfang an ein persistiertes Feld `exam_scope VARCHAR(20) NOT NULL DEFAULT 'AP1'` mit der Allowlist `AP1 | AP2_FIAE | AP2_FISI | CROSS`. Seeder und Admin validieren dieses Feld; Katalog-DTOs geben es aus. Titelpräfixe sind nur Anzeige, nie Datenquelle. Lobby-Filter können dadurch später ohne Migration ergänzt werden.
|
||||
- **FinalFlux erweitern:** Das bestehende Lernmodul ist rein AP1-fokussiert (28 Seiten + FluxChecks). Die Struktur (statische Themenseiten + Frage-JSONs) trägt problemlos einen **AP2-Ast** – als eigener Sidebar-Block „AP2 Anwendungsentwicklung" / „AP2 Systemintegration" (in Teil 2 als Punkt S10 aufgenommen).
|
||||
- Die vorhandenen FinalFlux-Inhalte (IP-Berechnung, VLAN, OSI, Wirtschaft) bleiben die AP1-Basis, auf der die Spiele aufsetzen.
|
||||
|
||||
@@ -41,7 +41,7 @@ Vorgabe: Alle Spielnamen folgen dem MindMatch-Muster – **ein Wort, englisch, C
|
||||
| Bug Hunter | **BugHunter** | `/bughunter` | `bughunter` |
|
||||
| Netzwerker – Das Router-Rätselspiel | **NetWorker** | `/networker` | `networker` |
|
||||
|
||||
Begründung Keys: Die vorhandenen Routen sind alle klein und zusammengeschrieben (`/mindmatch`, `/syntaxsaga` …) – die neuen Routen folgen dem. Die vier reservierten Keys (`escape-room`, `service-clash`, `bug-hunter`, `netzwerker`) haben **noch keine Scores in der DB** und werden daher jetzt kostenlos auf das einheitliche Schema umbenannt (`codeescape`, `serviceclash`, `bughunter`, `networker`) – zu ändern in `GameScoreController.KNOWN_GAMES`, `ProgressService.GAMES` und den jeweiligen Service-`GAME`-Konstanten. Nur `syntax-saga` behält seinen Key (Bestandsdaten), Anzeigename wird trotzdem `SyntaxSaga`. Anzeigenamen anpassen in: `dashboard.html`-`GAMES`-Array, `ProgressService.GAMES`, Seitentiteln/Templates der neuen Spiele. _Alle nachfolgenden Abschnitte verwenden bereits die neuen Namen; wo im Text noch V9–V12-Design-Details Alt-Keys nennen, gilt die Tabelle hier._
|
||||
Begründung Keys: Die vorhandenen Routen sind alle klein und zusammengeschrieben (`/mindmatch`, `/syntaxsaga` …) – die neuen Routen folgen dem. Die historischen Plan-Aliasse `escape-room`, `service-clash`, `bug-hunter` und `netzwerker` hatten noch keine Scores und wurden deshalb vor der Implementierung auf `codeescape`, `serviceclash`, `bughunter` und `networker` vereinheitlicht. Nur `syntax-saga` behält seinen Key wegen möglicher Bestandsdaten. Die Tabelle und der Abschnitt „Gemeinsames Architektur-Rezept" sind die verbindliche Quelle; verbliebene Altbegriffe in erklärenden Designpassagen sind keine Routen- oder Schema-Vorgaben.
|
||||
|
||||
---
|
||||
|
||||
@@ -70,7 +70,7 @@ Dazu je Spiel ein eigenes Karten-Design auf dem Dashboard (Hover-Animation im je
|
||||
|
||||
Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan: **Dev Lab**, `DevLabService.java` + `devlabgame.js`):
|
||||
|
||||
1. **Flyway-Migration** `db/migration/V9__…` ff. (V8 ist die letzte; `ddl-auto=validate` ⇒ Migration ist Pflicht). SQL-Stil: `BIGINT GENERATED BY DEFAULT AS IDENTITY`, `slug VARCHAR UNIQUE`, `sort_order INT DEFAULT 0`, `active BOOLEAN DEFAULT TRUE`, `FK … ON DELETE CASCADE`, Indizes.
|
||||
1. **Flyway-Migration** ab `db/migration/V11__…` (V9/V10 sind durch User-/Datenintegrität belegt; `ddl-auto=validate` ⇒ Migration ist Pflicht). Reserviert: V11 CodeEscape, V12 BugHunter, V13 NetWorker, V14 ServiceClash; danach FluxNet. SQL-Stil: `BIGINT GENERATED BY DEFAULT AS IDENTITY`, `slug VARCHAR UNIQUE`, `exam_scope VARCHAR(20)`, `sort_order INT DEFAULT 0`, `active BOOLEAN DEFAULT TRUE`, `FK … ON DELETE CASCADE`, Indizes.
|
||||
2. **Entities** in `model/` (Parent mit `@OneToMany(cascade=ALL, orphanRemoval=true)`, Lösungs-Logik nur serverseitig auf der Entity).
|
||||
3. **Repository** in `repository/` (`findAllByActiveTrueOrderBySortOrderAscIdAsc()`, `findBySlug`, `countBy…Id`).
|
||||
4. **Service** in `service/` mit Konstante `GAME = "<key>"`, injiziert `GameScoreService`; `@Transactional(readOnly=true)` für Build/Check, `@Transactional` für `finish`. **Score wird ausschließlich serverseitig berechnet** (`gameScoreService.recordScore(user, GAME, deck, score, moves, seconds)`); Client sendet nur Roh-Antworten.
|
||||
@@ -82,11 +82,21 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
10. **Frontend:** Template in `templates/`, eigenes CSS mit eindeutigem Präfix (nur `theme.css`-Tokens, Erfolg = blaues ✓, Fehler = rotes ✗, **nie grün**), JS als IIFE in `static/js/`, Highscore via `GET /api/games/<key>/stats`, Cache-Busting `?v=N`.
|
||||
11. **Integration:** Route in `SecurityConfig`-CSRF-Ignore-Liste aufnehmen, Dashboard-Karte in `dashboard.html` von `/comingsoon` auf die echte Route umstellen. (`KNOWN_GAMES` + `ProgressService` enthalten die Keys bereits.)
|
||||
|
||||
### Verbindlicher Sicherheitsvertrag für neue Spiele (S3)
|
||||
|
||||
1. Session-/Katalogantworten enthalten nur opaque IDs und lösungsfreie DTOs; Lösung, Reveal-Status und Scoring-Metadaten bleiben serverseitig.
|
||||
2. `finish` akzeptiert nur IDs aus der angeforderten Runde und verwirft fremde, doppelte oder nicht zum Parent gehörende IDs.
|
||||
3. Punkte, Sterne, Highscore, gelöste Anzahl und Boni werden ausschließlich serverseitig aus kanonischen Daten neu berechnet.
|
||||
4. `durationSeconds` muss plausibel sein (`>= 1` und höchstens das konfigurierte Limit plus dokumentierte Toleranz); Listen und Zähler erhalten fachliche Obergrenzen.
|
||||
5. Reveal-/Hint-Nutzung wird serverseitig protokolliert oder beim Finish erneut validiert und kann nicht durch Weglassen im Request verborgen werden.
|
||||
6. Deterministische Seeds werden spätestens bei ServiceClash mit einem serverseitigen HMAC signiert; der Client darf keinen frei wählbaren Seed zur Wertung einreichen.
|
||||
7. Für jedes Spiel entstehen Negativtests: fremde IDs, Duplikate, überlange Listen, unmögliche Zeiten, manipulierte gesperrte Felder und Reveal-vor-Finish.
|
||||
|
||||
---
|
||||
|
||||
## Teil 1: Spieldesigns
|
||||
|
||||
### Spiel 1: Code Escape Room (Key: `escape-room`, Migration V9)
|
||||
### Spiel 1: CodeEscape (Key: `codeescape`, Migration V11)
|
||||
|
||||
**Konzept:** Der Spieler ist in einer digitalen Umgebung eingesperrt (Serverraum, Admin-Büro, Rechenzentrum). Ein **Szenario** = ein Durchlauf mit 3 Räumen in fester Reihenfolge; jeder Raum enthält 2–3 IT-Rätsel plus ein **Tür-Keypad**. Jedes gelöste Rätsel liefert ein **Code-Fragment** (Ziffern/Hex-Chunk in einer Inventar-Leiste); die Fragmente ergeben zusammen den Türcode zum nächsten Raum. Countdown erzeugt Zeitdruck; ein 2-stufiges Hinweis-System tauscht Punkte gegen Hilfe.
|
||||
|
||||
@@ -103,9 +113,9 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
- Pro Rätsel: `punkte × versuchsfaktor × hinweisfaktor` (Versuch: 1.0/0.6/0.3, aufgedeckt 0; Hinweis: keiner ×1.0, Stufe 1 ×0.8, Stufe 2 ×0.6). Hinweis-Nutzung wird **serverseitig in der HttpSession** protokolliert (der `/hint`-Endpoint merkt sich die höchste gelieferte Stufe pro Rätsel) – der Client kann sie nicht unterschlagen. _(Einzige bewusste Abweichung vom sonst zustandslosen Muster.)_
|
||||
- Pro geöffneter Tür: pauschal **+50**.
|
||||
- Sterne aus `baseScore/maxScore` (≥0.8→3, ≥0.5→2). **Zeitbonus danach**, nur bei Flucht: `max(0, round(500 × (zeitlimit − sekunden) / zeitlimit))` – die MindMatch-Idee, auf 15-Minuten-Läufe skaliert. Timer auf 0 bricht nicht ab: HUD wechselt in „ALARM"-Zustand (pulsierendes `var(--danger)`), der Bonus ist nur weg.
|
||||
- `recordScore(user, "escape-room", szenarioSlug, baseScore + zeitbonus, gelösteRätsel, sekunden)`.
|
||||
- `recordScore(user, "codeescape", szenarioSlug, baseScore + zeitbonus, gelösteRätsel, sekunden)`.
|
||||
|
||||
**Datenmodell (`V9__escape_room.sql`):** 3 Tabellen im V8-Stil:
|
||||
**Datenmodell (`V11__codeescape.sql`):** 3 Tabellen im V8-Stil:
|
||||
- `escape_scenarios` (id, slug UNIQUE, title, difficulty, description, time_limit_seconds INT DEFAULT 900, sort_order, active)
|
||||
- `escape_rooms` (id, scenario_id FK CASCADE, title, intro, door_prompt, **door_code VARCHAR(50)**, success_text, sort_order)
|
||||
- `escape_puzzles` (id, room_id FK CASCADE, puzzle_type VARCHAR(30), prompt, points INT DEFAULT 100, **code_fragment VARCHAR(20)**, sort_order, payload VARCHAR(8000))
|
||||
@@ -116,7 +126,7 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
- `check(puzzleId, reveal, submission)` – Typ `code`: neuer trivialer Checker via `anyEquals(payload.solutions, answer, caseSensitive)`; **`choice`/`order`/`match`: Checker 1:1 aus `DevLabService` kopieren.** Bei `correct || reveal` kommt `"fragment"` in die Antwort.
|
||||
- `openDoor(roomId, code)`, `hint(session, puzzleId, level)`, `finish(...)` wie oben; plus Admin-Methoden nach Dev-Lab-Vorbild.
|
||||
|
||||
**API (`/api/escape-room`):** `GET /scenarios`, `GET /session/{slug}`, `POST /check` (`{puzzleId, reveal, submission:{answer}}` → `{correct, fragment, successText}`), `POST /door` (`{roomId, code}` → `{open, successText}`), `POST /hint` (`{puzzleId, level}` → `{text, level}`), `POST /finish` (`{slug, durationSeconds, escaped, items:[{puzzleId, submission, attempts, revealed}], doors:[{roomId, code}]}` → `{score, baseScore, maxScore, timeBonus, solvedPuzzles, roomsOpened, escaped, stars, highscore, newHighscore, plays}`).
|
||||
**API (`/api/codeescape`):** `GET /scenarios`, `GET /session/{slug}`, `POST /check` (`{puzzleId, reveal, submission:{answer}}` → `{correct, fragment, successText}`), `POST /door` (`{roomId, code}` → `{open, successText}`), `POST /hint` (`{puzzleId, level}` → `{text, level}`), `POST /finish` (`{slug, durationSeconds, escaped, items:[{puzzleId, submission, attempts, revealed}], doors:[{roomId, code}]}` → `{score, baseScore, maxScore, timeBonus, solvedPuzzles, roomsOpened, escaped, stars, highscore, newHighscore, plays}`).
|
||||
|
||||
**Frontend:** `templates/escape-room.html`, `static/js/escaperoom.js` (IIFE-State-Machine `LOBBY → INTRO → ROOM(i) → PUZZLE_MODAL → DOOR_TRY → TRANSITION → … → RESULT`), `static/css/escaperoom.css` mit Präfix `esc-`. **Die `choice`/`order`/`match`-Renderer aus `devlabgame.js` (Vertrag `{render, collect, lock, mark}`) portieren**, nur ein `code`-Renderer (Terminal-Artefakt + Textfeld) kommt neu dazu. Layout: HUD oben (Raumtitel, Raum-Punkte ● ● ○, Timer-Chip), Mitte Rätselkarten, unten Fragment-Chips + Keypad-Button. Nur Theme-Tokens, Erfolg blau ✓, Fehler rot ✗.
|
||||
|
||||
@@ -128,7 +138,7 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
|
||||
---
|
||||
|
||||
### Spiel 2: Bug Hunter (Key: `bug-hunter`, Migration V10)
|
||||
### Spiel 2: BugHunter (Key: `bughunter`, Migration V12)
|
||||
|
||||
**Konzept:** Der Spieler ist Debugging-Detektiv und arbeitet **Fallakten** ab. Ein Fall („Hunt") ist ein Mini-Projekt aus 2–4 Dateien, das sich falsch verhält; Beweismittel sind simulierte Konsolen-Ausgabe / Stacktrace / Ticket-Text. Pro Bug eine Drei-Phasen-Schleife: **ORTEN** (fehlerhafte Zeile im Tab-Code-Viewer anklicken) → **KLASSIFIZIEREN** (Syntax / Logik / Laufzeit / Sicherheit) → **FIXEN** (korrigierte Zeile aus 4 Kandidaten wählen). Saubere Bugs bauen eine **Combo-Serie** auf. Stufen: Junior / Senior / Principal.
|
||||
|
||||
@@ -138,9 +148,9 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
- Phasengewichte pro Bug: Orten 40 %, Klassifizieren 20 %, Fixen 40 %. Phasen-Award = `gewicht × punkte × versuchsfaktor` (1.0/0.6/0.3, aufgedeckt 0).
|
||||
- Sterne aus `baseScore/maxScore` (Genauigkeitsmaß, ohne Combo).
|
||||
- **Combo:** Ein Bug ist _sauber_, wenn alle 3 Phasen im 1. Versuch ohne Aufdecken gelingen. Serienposition n bringt `(min(n,4) − 1) × 10 % × punkte` Bonus (2. saubere in Folge +10 %, … 4.+ +30 %); Bonus wird **nach** der Sternberechnung addiert. Kein Timer – Bug Hunter belohnt Präzision, Zeitdruck gehört dem Escape Room.
|
||||
- Basispunkte pro Bug nach Stufe: Junior 100, Senior 150, Principal 200. `recordScore(user, "bug-hunter", huntSlug, baseScore + comboBonus, gelösteBugs, sekunden)`.
|
||||
- Basispunkte pro Bug nach Stufe: Junior 100, Senior 150, Principal 200. `recordScore(user, "bughunter", huntSlug, baseScore + comboBonus, gelösteBugs, sekunden)`.
|
||||
|
||||
**Datenmodell (`V10__bug_hunter.sql`):**
|
||||
**Datenmodell (`V12__bughunter.sql`):**
|
||||
- `bughunter_hunts` (id, slug UNIQUE, title, code_language, difficulty DEFAULT 'junior', description, briefing VARCHAR(2000), console_output VARCHAR(4000), sort_order, active)
|
||||
- `bughunter_files` (id, hunt_id FK CASCADE, filename, content VARCHAR(8000), sort_order) – eigene Tabelle, damit der Code-Viewer-Inhalt von allen Bugs geteilt wird und im Admin als Textarea editierbar ist
|
||||
- `bughunter_bugs` (id, hunt_id FK CASCADE, points DEFAULT 100, sort_order, payload VARCHAR(8000)) – Payload: `{"file","line","category","evidence","fixOptions":[4],"fixIndex","explanation"}`
|
||||
@@ -151,7 +161,7 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
- `checkPhase(bugId, phase, reveal, submission)`: `locate` vergleicht file+line, liefert bei Erfolg/Aufdecken `location` zurück; `classify` vergleicht die Kategorie und liefert bei Auflösung erst die **gemischten `fixOptions`** (Phasen-Gate: der Fix-Text würde sonst die Position verraten); `fix` prüft die Wahl (Logik = Dev Labs `checkChoice`) und liefert `fixedLine` + `explanation` fürs Debriefing.
|
||||
- `finish(...)`: prüft alle Phasen aus den Roh-Antworten neu, Gewichte + Versuchsfaktoren, Streak/Combo, Sterne, `recordScore`.
|
||||
|
||||
**API (`/api/bug-hunter`):** `GET /hunts`, `GET /session/{slug}`, `POST /check` (`{bugId, phase, reveal, submission}`), `POST /finish` (`{slug, durationSeconds, items:[{bugId, locate:{file,line,attempts,revealed}, classify:{category,…}, fix:{choice,…}}]}` → `{score, baseScore, maxScore, comboBonus, maxCombo, bugsSolved, totalBugs, stars, highscore, newHighscore, plays}`).
|
||||
**API (`/api/bughunter`):** `GET /hunts`, `GET /session/{slug}`, `POST /check` (`{bugId, phase, reveal, submission}`), `POST /finish` (`{slug, durationSeconds, items:[{bugId, locate:{file,line,attempts,revealed}, classify:{category,…}, fix:{choice,…}}]}` → `{score, baseScore, maxScore, comboBonus, maxCombo, bugsSolved, totalBugs, stars, highscore, newHighscore, plays}`).
|
||||
|
||||
**Frontend:** `templates/bug-hunter.html`, `static/js/bughunter.js` (State-Machine `LOBBY → BRIEFING → HUNT {pro Bug: LOCATE → CLASSIFY → FIX → DEBRIEF} → RESULT`), `static/css/bughunter.css` Präfix `bh-`. Layout: **links 60 %** Datei-Tabs + Monospace-Code-Viewer mit Zeilennummern-Gutter (Zeilenklick nur in LOCATE aktiv); **rechts 40 %** Beweis-Karte (Terminal-Style `consoleOutput`, Briefing, Bug-Hinweis), Aktions-Panel (wechselt pro Phase; Kategorie-/Fix-Buttons nutzen das `choice`-Renderer-Muster aus `devlabgame.js`), Combo-Chip + Fortschritt („Bug 2/3"). Debriefing tauscht die Bug-Zeile sichtbar gegen `fixedLine` (blaues Diff-Highlight).
|
||||
|
||||
@@ -163,7 +173,7 @@ Jedes neue Spiel folgt exakt dem Muster der vorhandenen Spiele (bester Bauplan:
|
||||
|
||||
---
|
||||
|
||||
### Spiel 3: Service Clash (Key: `service-clash`, Migration V11)
|
||||
### Spiel 3: ServiceClash (Key: `serviceclash`, Migration V14)
|
||||
|
||||
**Konzept: „Deine Schicht am Service Desk."** Der Spieler ist Junior-Admin im First-Level-Support. Tickets treffen auf einer Zeitleiste ein; jedes muss **eingeordnet** (Incident vs. Service Request), **priorisiert** (Hoch/Mittel/Niedrig anhand von Impact-×-Dringlichkeit-Hinweisen im Tickettext) und **gelöst** werden (richtige Erstmaßnahme aus 3–4 Optionen) – bevor sein SLA-Timer abläuft. Unbehandelte Tickets beschädigen die „Systemgesundheit"; bei 0 endet die Schicht vorzeitig.
|
||||
|
||||
@@ -188,14 +198,14 @@ maxScore = Σ B + 200 ; Sterne nach Plattform-Konvention
|
||||
- Jeder Klick geht an `POST /check` (sofortiges ✓/✗-Feedback; Lösungen verlassen den Server nie).
|
||||
- `POST /finish` sendet `{slug, seed, decisions[], durationSeconds}`; der Server **regeneriert die Schicht aus dem Seed und re-simuliert das Entscheidungslog** (Plausibilitätschecks: Zeitstempel ≥ Spawn-Offset, ≤ Schichtdauer, monoton pro Ticket) und berechnet Gesundheit, SLA-Faktoren und Score neu. Härtungs-Ausbau: HMAC-signierter Seed.
|
||||
|
||||
**Datenmodell (`V11__service_clash.sql`):**
|
||||
**Datenmodell (`V14__serviceclash.sql`):**
|
||||
- `service_clash_shifts` (id, slug UNIQUE, title, description, difficulty INT, wave_count INT DEFAULT 3, wave_seconds INT DEFAULT 60, spawn_count INT DEFAULT 12, settings VARCHAR(4000) /* JSON: SLA-Defaults, Health-Regeln, Prio-Stufe an/aus */, sort_order, active)
|
||||
- `service_clash_tickets` (id, shift_id FK CASCADE, wave INT, base_points INT DEFAULT 100, sort_order, payload VARCHAR(8000)) + FK-Index
|
||||
- Ticket-Payload: `{title, requester, text, kind (normal|phishing), options[], correctIndex✂, category✂, priority✂, slaSeconds, explanation✂, successText}` (✂ = wird von `sanitize()` entfernt).
|
||||
|
||||
**Backend:** Entities `ServiceClashShift`/`ServiceClashTicket`, Standard-Repos (`findAllByShiftIdOrderByWaveAscSortOrderAscIdAsc`, `countByShiftId`). `ServiceClashService`: `buildCatalog()`, `buildSession(slug)` (Seed + `generatePlan()`), `check(templateId, step, value, reveal)` mit `step ∈ classify|priority|solve` (Vergleich immer über Options-**Text**, nie Indizes – immun gegen Mischungs-Versatz), `finish(...)` (Plan aus Seed regenerieren, Log re-simulieren, `recordScore(user, "service-clash", slug, score, gelöste, sekunden)`), Admin-Methoden nach Dev-Lab-Vorbild.
|
||||
|
||||
**API (`/api/service-clash`):** `GET /catalog`, `GET /session/{slug}` (liefert `seed`, Wellen-Konfiguration, Ticket-Instanzen `{instanceId, templateId, wave, spawnAtMs, …}`), `POST /check`, `POST /finish` → `{score, maxScore, stars, resolved, total, slaBreaches, health, highscore, newHighscore, plays, tickets[Debrief-Aufschlüsselung]}`.
|
||||
**API (`/api/serviceclash`):** `GET /catalog`, `GET /session/{slug}` (liefert `seed`, Wellen-Konfiguration, Ticket-Instanzen `{instanceId, templateId, wave, spawnAtMs, …}`), `POST /check`, `POST /finish` → `{score, maxScore, stars, resolved, total, slaBreaches, health, highscore, newHighscore, plays, tickets[Debrief-Aufschlüsselung]}`.
|
||||
|
||||
**Frontend:** `templates/service-clash.html`, `static/js/serviceclash.js` (State-Machine `SHIFT_SELECT → BRIEFING → RUNNING ⇄ WAVE_BREAK → DEBRIEF`; **ein** `setInterval(250 ms)`-Tick: fällige Tickets spawnen, SLA-Ringe aktualisieren), `static/css/service-clash.css` Präfix `sc-`. Layout: Topbar (Schicht-Uhr, Wellen-Pips, Gesundheits-Meter, „Gelöst 4/8"), links die Ticket-Queue (Karten mit SLA-Ring, pulsierender roter Rand bei Überfälligkeit), Mitte das aktive Ticket mit 3-Stufen-Flow, unten ein Event-Log („14:02 Ticket ‚ERP down' eingegangen"). SLA-Ringe: `var(--accent)`, unter 25 % `var(--danger)`.
|
||||
|
||||
@@ -209,7 +219,7 @@ maxScore = Σ B + 200 ; Sterne nach Plattform-Konvention
|
||||
|
||||
---
|
||||
|
||||
### Spiel 4: Netzwerker – Das Router-Rätselspiel (Key: `netzwerker`, Migration V12)
|
||||
### Spiel 4: NetWorker (Key: `networker`, Migration V13)
|
||||
|
||||
**Konzept:** Netzwerk-Puzzle in der Tradition von Schaltkreis-Spielen. Jedes Level zeigt eine **SVG-Topologie** (PCs, Switch, Router, Server, Cloud). Geräte haben fehlende oder kaputte Konfiguration (IP, Maske, Gateway, Kabel, statische Routen). Ziel: alle **Ping-Ziele** erfüllen („PC1 muss SRV1 erreichen", später auch negativ: „Gast-PC darf den Server NICHT erreichen"). „Pings testen" ruft einen **serverseitigen Netzwerk-Simulator**, der jeden Ping Hop-für-Hop auflöst und Pass/Fail plus didaktische Diagnose liefert („Das Paket verlässt PC1 nicht: Laut Maske liegt das Ziel im eigenen Netz – stimmt die Maske?").
|
||||
|
||||
@@ -219,7 +229,7 @@ maxScore = Σ B + 200 ; Sterne nach Plattform-Konvention
|
||||
|
||||
**Versuche & Punkte:** Jeder „Pings testen"-Klick mit mindestens einem roten Ziel verbraucht einen Versuch (1.0/0.6/0.3, `MAX_ATTEMPTS=3`, danach „Lösung anzeigen" = 0 Punkte). **Bewertet wird ausschließlich per Simulation, nie per Exact-Match** – viele Konfigurationen sind gültig (jede freie Host-IP funktioniert); die Musterlösung dient nur dem Aufdecken. Levelpunkte 100–200; Sterne am Weltende nach Konvention; `/finish` re-simuliert die final eingereichten Konfigurationen serverseitig. `recordScore(user, "netzwerker", weltSlug, score, gelöste, sekunden)`.
|
||||
|
||||
**Datenmodell (`V12__netzwerker.sql`):**
|
||||
**Datenmodell (`V13__networker.sql`):**
|
||||
- `netzwerker_worlds` (id, slug UNIQUE, title, description, difficulty INT, sort_order, active)
|
||||
- `netzwerker_levels` (id, world_id FK CASCADE, title, level_type VARCHAR(30) /* assign|cable|fix|route|vlan */, points INT DEFAULT 100, sort_order, payload VARCHAR(8000) /* JSON-Topologie inkl. Musterlösung */) + FK-Index
|
||||
|
||||
@@ -230,7 +240,7 @@ maxScore = Σ B + 200 ; Sterne nach Plattform-Konvention
|
||||
|
||||
**`NetzwerkerService`:** `buildCatalog()`, `buildSession(slug)` (Level per `sanitizeLevel()`: Werte editierbarer Felder, zu ziehende Links, Routen-Lösungszeilen und `solution`-Block entfernt; gesperrte Werte, Positionen, Ziele, Hints gehen mit), `check(levelId, reveal, config)` (`mergeSubmission()` legt eingereichte Werte **nur über editierbare Felder** – Manipulation gesperrter Felder wird ignoriert; alle Ziele durch `NetSimulator.ping`; Antwort mit Trace/Diagnose pro Ziel), `finish(...)`, Admin-CRUD **plus Qualitäts-Gate beim Speichern: die hinterlegte Musterlösung wird durch den Simulator geschickt – Speichern wird abgelehnt, wenn sie nicht alle Ziele erfüllt.**
|
||||
|
||||
**API (`/api/netzwerker`):** `GET /catalog`, `GET /session/{slug}`, `POST /check` (`{levelId, reveal, config:{ifaces[], links[], routes[], vlans[]}}` → `{allPassed, validation[], goals:[{id, passed, trace[] | failAt, reason, message}]}`; Masken-Eingabe akzeptiert `24`, `/24` oder `255.255.255.0` – Server normalisiert), `POST /finish` → Dev-Lab-Result-Form.
|
||||
**API (`/api/networker`):** `GET /catalog`, `GET /session/{slug}`, `POST /check` (`{levelId, reveal, config:{ifaces[], links[], routes[], vlans[]}}` → `{allPassed, validation[], goals:[{id, passed, trace[] | failAt, reason, message}]}`; Masken-Eingabe akzeptiert `24`, `/24` oder `255.255.255.0` – Server normalisiert), `POST /finish` → Dev-Lab-Result-Form.
|
||||
|
||||
**Frontend:** `templates/netzwerker.html`, `static/js/netzwerker.js` (State-Machine `WORLD_SELECT → LEVEL_INTRO → EDITING ⇄ CHECKING → LEVEL_DONE → SUMMARY`), `static/css/netzwerker.css` Präfix `nw-`. **SVG-Ansatz:** ein `<svg viewBox="0 0 1000 620">`, Geräte-Glyphen als `<symbol>`-Defs im Strichstil der Dashboard-Icons, Positionen aus dem Payload; Links als `<path>`, Ports als Kreise an der Gerätekante. **Die Paket-Animation ist die Belohnung:** bei Erfolg wandert ein leuchtender Punkt entlang des tatsächlich vom Server gelieferten `trace`-Pfads (`requestAnimationFrame`); bei Fehlschlag stirbt er exakt am `failAt`-Hop mit rotem Burst. Kabelmodus: Port A klicken → Gummiband-Linie → Port B; gezogenes Kabel per Klick löschen. Layout: Canvas links/Mitte, rechts Ziel-Liste (mit Diagnosetexten unter roten Zielen) + Konfigurations-Panel des gewählten Geräts, Footer mit „Pings testen" / „Lösung anzeigen" / Hinweis-Toggle.
|
||||
|
||||
@@ -247,10 +257,11 @@ maxScore = Σ B + 200 ; Sterne nach Plattform-Konvention
|
||||
### Empfohlene Baureihenfolge & Gesamtaufwand
|
||||
|
||||
0. **Vorarbeiten:** Namensschema umsetzen (Dashboard-Namen, Keys, `devlab` in `ProgressService` = W1) · K2 (Legacy-Endpunkt löschen) und W8 (N+1-Muster) beheben, damit die neuen Services das saubere Muster übernehmen · Spiel-Akzent-Tokens in `theme.css` anlegen. ≈ 1 PT — **✅ erledigt bis auf die Spiel-Akzent-Tokens.**
|
||||
1. **CodeEscape (V9)** – validiert die Wiederverwendung der DevLab-Checker/-Renderer mit minimalem Risiko. ≈ 5,5 PT
|
||||
2. **BugHunter (V10)** – übernimmt Terminal-Styling und Choice-Renderer aus Schritt 1. ≈ 4,5 PT
|
||||
3. **NetWorker (V12)** – **Simulator zuerst, testgetrieben** (pures Java, kein UI-Risiko), dann SVG-Frontend. ≈ 9,5 PT
|
||||
4. **ServiceClash (V11)** – komplexestes Frontend (Echtzeit-Tick); profitiert von allen Vorarbeiten. ≈ 7,5 PT
|
||||
1. **FluxTimer ✅** – risikoarmer, rein lokaler Ausbau; validiert den globalen UI-Bootstrap und belegt die Glocke vor FluxNet. ≈ 1,5–2 PT
|
||||
2. **CodeEscape (V11)** – validiert die Wiederverwendung der DevLab-Checker/-Renderer mit minimalem Risiko. ≈ 5,5 PT
|
||||
3. **BugHunter (V12)** – übernimmt Terminal-Styling und Choice-Renderer aus Schritt 2. ≈ 4,5 PT
|
||||
4. **NetWorker (V13)** – **Simulator zuerst, testgetrieben** (pures Java, kein UI-Risiko), dann SVG-Frontend. ≈ 9,5 PT
|
||||
5. **ServiceClash (V14)** – komplexestes Frontend (Echtzeit-Tick); profitiert von allen Vorarbeiten. ≈ 7,5 PT
|
||||
|
||||
**Gesamt-MVP aller vier Spiele: ≈ 28 Personentage.** Der Navigations-Umbau (Abschnitt 2.3) und die restlichen Teil-2-Punkte können parallel oder dazwischen erfolgen; empfohlen ist der Sidebar-/Tab-Umbau **vor** dem vierten Spiel, damit alle neuen Seiten die Fragmente nutzen.
|
||||
|
||||
@@ -307,7 +318,7 @@ Der Verdacht „Profilbutton fehlt / Einstellungen nicht im Profil / irgendwas i
|
||||
|---|-------|----------|
|
||||
| S1 ✅ teilweise | **Template-Duplikation** – 33 Templates ohne ein einziges `th:fragment`; jede Seite dupliziert `<head>`, Sidebar, Footer | `templates/fragments/layout.html` mit `head`, `sidebar`, `footer`-Fragmenten einführen; schrittweise umstellen (zuerst bei den 4 neuen Spielen verwenden, dann Bestand migrieren). |
|
||||
| S2 ✅ | **4 parallele User-Anlage-Pfade** mit inkonsistenten Regeln (`RegisterController`, REST-`UserController`, `AdminUserController`, `UserViewController`) | Nach Löschung von K2: Restlogik in einen `UserService` konsolidieren (ein Ort für Encoding, Rollen, Uniqueness). |
|
||||
| S3 ☐ | **Score-Manipulation durch eigene Nutzer möglich** (Roh-Werte fälschbar, Reveal-vor-Finish) | Akzeptables Risiko (nur eigener Highscore), aber bei den neuen Spielen von Anfang an minimieren: Server generiert Runden-Daten mit IDs, `finish` validiert nur bekannte IDs, Zeit-Plausibilitätscheck (z. B. `durationSeconds ≥ 1`, Obergrenzen für `pairs`/`moves`). |
|
||||
| S3 ✅ Fundament | **Score-Manipulation durch eigene Nutzer möglich** (Roh-Werte fälschbar, Reveal-vor-Finish) | Verbindlicher Sicherheitsvertrag ist oben dokumentiert und gilt für jedes neue Spiel; konkrete Implementierung und Negativtests entstehen jeweils mit dem Spiel. |
|
||||
| S4 ✅ | **Infrastruktur**: kein Actuator/Healthcheck, Dockerfile läuft als root, kein Dependency-Layer-Caching, CI ohne Tests, Java-Versionskonflikt (pom: 17, Dockerfile: 21) | `spring-boot-starter-actuator` (+ `HEALTHCHECK` in compose), `USER`-Directive, Dockerfile zweistufig mit `dependency:go-offline`-Layer, Test-Stage in `.gitea/workflows/mindflux.yml`, Java-Version angleichen (empfohlen: beide auf 21). |
|
||||
| S5 ✅ | **Datenmodell**: `game_scores`/`achievements` referenzieren `username` ohne FK; `email` ohne UNIQUE | FK auf `users(username)` + `UNIQUE(email)` per Migration ergänzen (vorher Dubletten bereinigen). |
|
||||
| S6 ✅ | **Logout per GET** (`SecurityConfig.java:36`) – kleiner Logout-CSRF-Vektor | Auf POST-Logout mit CSRF-Token umstellen (kleines Formular im Sidebar-Footer). |
|
||||
@@ -433,6 +444,8 @@ Eine Freundschaft zwischen A und B liegt genau einmal vor (Anfrage-Richtung = re
|
||||
|
||||
## Teil 4: FluxTimer – Der Pausen-Lerntimer
|
||||
|
||||
> ✅ **MVP umgesetzt:** lokaler Zustand, globaler Countdown, Einstellungen, Schnellzugriff über die Glocke, In-App-Overlay, Snooze, Probelauf sowie optionale Browser-Benachrichtigung und Web-Audio-Signal. Eine serverseitige Synchronisation bleibt bewusst optional.
|
||||
|
||||
> Opt-in-Erinnerungstimer im Look der Zeitschaltkreise des DeLorean: Nach frei wählbarer Zeit erinnert Mindflux ans Aufstehen, Trinken, Essen – oder was immer man einträgt. Standardmäßig **deaktiviert**, jederzeit abschaltbar, komplett frei einstellbar.
|
||||
|
||||
### 4.1 Funktionsumfang
|
||||
|
||||
Reference in New Issue
Block a user