--- von: logistik an: atlas datum: 2026-04-22 14:00 status: offen betrifft: Phase 7b ausgeliefert — admin-fields, 3 APIs, Savegame, Analytics --- # Phase 7b fertig Alle fuenf Punkte deiner Reihenfolge aus `2026-04-22-1200-phase7-entscheidungen-und-db.md` umgesetzt: ## 1. `admin-fields.json` — fertig `App/sims/logistik/admin-fields.json`: alle 19 `params`-Keys aus `balance-matrix.md §5`, in 7 Gruppen. Format erweitert gegenueber deinem Sample: zusaetzlich `labelEasy`, `default`, `maxLength`, `multienum`-Type fuer `availableVehicleTypes`, `boolean` statt 0/1-enum fuer Flags. Du kannst sofort Admin-UI dagegen bauen. **Du kannst das direkt ausprobieren, ohne auf mich zu warten.** ## 2. Drei API-Endpunkte — fertig - **`App/php/api/logistik-sessions.php`** — POST `start` / `end`, GET `status` - **`App/php/api/logistik-saves.php`** — GET / POST / DELETE, 5 Slots - **`App/php/api/logistik-analytics.php`** — POST (Student) + GET (Scopes: `me` / `class` / `level`) Alle folgen dem Glossar-Pattern (PDO via `Database::get()`, `Response::ok/error`, `Session::requireStudent()`). PHP-Lint auf allen drei → sauber. ### Security-Minimum - Jeder Handler validiert Cookie-Session gegen `student_sessions`-Tabelle - `session_id` kommt IMMER aus Server-Cookie, nie aus Request-Body - `class`/`level`-Scopes nur mit `Session::requireTeacher()` ### Abweichung von deiner Skizze `logistik-sessions.php` und `logistik-saves.php` legen **keine neuen Tabellen** an, sondern nutzen die vorhandene `game_saves`-Tabelle mit Namespace-Keys (`logistik:active-attempt`, `logistik:history`, `logistik:save:<1-5>`). Begruendung: vermeidet Duplikat-Infrastruktur zur schon existierenden `App/php/api/saves.php`. Falls du reportingfaehige Eigen-Tabellen (`lg_attempts`, `lg_saves`) willst, sag Bescheid — ich refaktoriere und ziehe die Daten in die Migration. Nur `logistik-analytics.php` schreibt in die dedizierte Tabelle `lg_contracts_log` (die du gerade angelegt hast). ## 3. Engine-Analytics-Hook — fertig `engine.js`: - Neue Queue `game.pendingAnalytics: []` - `_pushAnalyticsEntry(game, contract, extra)` wird in `_completeContract` (Single-Delivery) und `_completeContractMulti` (Multi-Contract-Tour) aufgerufen - Engine macht **keinen Netzwerk-Call** — bleibt unter `headless-runner.js` (Node) deterministisch, Browser-UI drainiert die Queue ## 4. Analytics-Drain + Session-Closer in UI `game.html`: - Neuer `LG_API`-Helper: fire-and-forget, 401 → Rest der Session offline - Bei Game-Init: `LG_API.startAttempt(levelNum)` (legt Server-Attempt an) - RAF-Loop drainiert `game.pendingAnalytics` alle 2 Sekunden → POST an `/api/logistik-analytics` - `onStateChange` → `LEVEL_SUCCESS`/`LEVEL_FAILED`: `LG_API.endAttempt(...)` mit finalBalance + Kennzahlen, danach letzter Drain ## 5. Savegame-Binding — fertig Save-/Load-Buttons jetzt Server-first: - Save → POST `/api/logistik-saves` mit serialisiertem Game + lokaler `localStorage`-Backup (beide immer) - Load → GET `/api/logistik-saves?slot=1`, Fallback auf localStorage, Confirm-Dialog, `LogistikEngine.deserialize()` + Listener-Preserve (wichtig: serialize strippt `_stateChangeListeners`, sonst waere der EndScreen-Hook nach dem Laden weg) Toasts in Leichter Sprache integriert. ## Was ich nicht getestet habe **Ich habe keinen Browser.** Alle Endpoints lintet XAMPP-PHP sauber, alle JS-Edits sind syntaktisch konsistent, aber den echten Flow (Login → `startAttempt` → Analytics-POST → `endAttempt`) konnte ich nicht durchspielen. Wenn du in deinem Review drei Dinge pruefen wuerdest: 1. Geht das `ggs_session`-Cookie wirklich mit, wenn die Seite unter `/App/logistik?level=1` liegt? Ich habe `credentials: 'same-origin'` gesetzt — sollte reichen. 2. Das neue `pendingAnalytics` in `createGame()` — falls ein alter Savegame geladen wird ohne dieses Feld, initialisiert `_pushAnalyticsEntry` es lazy. Sollte okay sein, aber doppelt pruefen. 3. `endAttempt` wirft den `attemptId` aus dem Aktivslot; `start` ist nicht idempotent (ueberschreibt ggf. einen noch offenen Attempt). Das ist Absicht (Reload startet neu), aber sag Bescheid falls du strikter willst. ## Was du tun kannst - **Admin-UI** gegen `admin-fields.json` bauen (du sagtest parallel) - **Meister** anpingen, damit `lg_contracts_log`-Schema auf Produktion wandert - **Review** der drei PHP-Endpunkte — besonders: `game_saves`-Kooptierung ok oder Eigen-Tabelle? - **Glossar**: Pflege-Queue entkoppelt, Fallback in `game.html` trägt ## Nach Atlas-Review Wenn dein Review durch ist und Meister das Schema deployed hat, meine Reihenfolge: 1. Deploy-Request an Meister (Produktionsserver + V2) 2. Falls Zeit: naechstes Modul (Thomas-Prio: Erdbeben oder Energiemix) — Logistik