# GeoGraSim — Komplett-Review & ToDo (2026-08-14) ## ✅ ERLEDIGT (Batch 1, 2026-08-14, deployed + Prod) - **#2 IDOR progress.php** — student_id-Zweig verlangt jetzt Lehrer-Login + Klassenbesitz (403 sonst). - **#3 licenses.php** — `?admin=1` + `generate` nur noch echter Admin (`$_SESSION['admin_id']`); Collision-Retry mit Cap gegen Endlosschleife. - **#4 .env-Deny** — `` für `.env*/.sh/.sql/.bak` in .htaccess (Docroot aktualisiert); `.env` weiterhin 404 (verifiziert). - **#6 Schüler-Ergebnisse** — sim-metrics.js + .ivm-CSS in schueler.html; `renderOwnRunCard`-Fallback zeigt Sterne + grafische Kacheln für die 9 bisher leeren Sims. - **#13 klima-Budget** — SIM_METRICS `final_budget` als „Mio €" (statt „€"). - **#7 Assessments-Aufblähung** — assessment.php skippt phase running/started; heli-30s-Ping entfernt; Altlast bereinigt (lokal 8678→276, Prod 1696→197). - **#9/#16 Cockpit/Matrix-Performance** — akute Last schon durch #7 gekappt (Scan ~200 statt 8000 Zeilen); zusätzlich Indizes `assessments(class_id,submitted_at)` + `student_results(class_id,completed_at)` gesetzt (lokal+Prod). APCu nicht verfügbar → App-Cache verworfen; Benchmark-Summary-Tabelle = späteres, größeres Stück falls nötig. - **#8 String-Identität → student_id-FK (Stufe 1+2)** — `student_sessions.student_id` (Spalte+Index+Backfill, lokal 35/35, Prod 90/91); `Session::createStudent` setzt es künftig; ALLE ~15 Name-Joins (Benchmark, live×5, results×5, modules, profile, progress×2) auf `student_id` umgestellt. Verlustfrei verifiziert (alt==neu, diff=0 auf Prod). Robust gegen Umbenennung. *Rest (optional):* 1 Waisen-Session „Susi1" (kein Schüler), assessments-eigene student_id-Spalte (nicht nötig). ## Geklärt ohne Code-Änderung (Entscheidung Thomas, 2026-08-14) - **#1 Secrets — Rotieren WEGGELASSEN.** `git push` geht nur an eigenen Gitea (`git.schroffenegger.at:2222`), nichts Öffentliches → Restrisiko akzeptiert. Keine Rotation, kein History-Rewrite. - **#5 Klartext-Passwörter — WORKS AS DESIGNED.** `password_plaintext` = systemvergebener PIN (druckbar). Lehrperson-Anlage/Reset setzt PIN+Hash; Selbst-Registrierung setzt KEIN plaintext; es gibt keinen Schüler-Selbständerungs-Flow → kein geändertes Passwort liegt je im Klartext. Kein Bug. - *Zukunfts-Hinweis:* falls je ein Schüler-„Passwort ändern"-Feature gebaut wird, muss es `password_plaintext = NULL` setzen. ## ✅ ERLEDIGT (Batch 2, 2026-08-15 — Balancing sonnensystem + energiemanager) - **#10 sonnensystem** — Bewertung war bedeutungslos (Lösung sofort aufgedeckt + Endlos-Retry → immer 5★). NEU: - Falsche Antwort deckt die richtige NICHT mehr auf → nur diese Option wird gesperrt, man wählt weiter (`obsAnswered` umgebaut, `.obs-option.spent`). - Sterne = **Erst-Treffer-Quote** (persistiert in `sonnensystem_obs_firsttry`), nicht mehr completed/total. Schwellen 0.85/0.68/0.50/0.30. - `level`-Feld (1–4) jetzt **genutzt**: Schwierigkeits-Badge pro Aufgabe (Grundlagen/Aufbau/Vertiefung/Profi). - Endscreen zeigt „Auf Anhieb richtig X/Y". Payload: `firstTryCount`/`firstTryQuote`. Benchmark.php `scoreSonnensystem` nutzt `firstTryQuote` (Fallback = alt). sim-metrics.js: „Auf Anhieb"-Kachel. - **#11 energiemanager** — kein Fail → immer 5★. NEU: - **Echter Blackout** an der Netzfrequenz: `freqError` akkumuliert (`·retain + balance·0.10`), Regelreserve zieht zurück; < 49,5 Hz oder > 50,5 Hz → Blackout-Overlay, Tag muss neu geplant werden (Plan bleibt erhalten). - **Schwierigkeitsrampe** über `retain` je Set (0.45 Frühling → 0.70 Wochenende): früh viel Reserve/verzeihend, spät summieren sich Fehler. - Frequenz-Tacho zeigt jetzt die **akkumulierte** Frequenz (Wegdriften sichtbar). Blackouts deckeln Sterne (1→max 3★, ≥2→max 2★), erscheinen in Set-Bilanz + `GGS_LIVE_STATE` (phase `blackout`, `blackouts`). - Numerisch verifiziert: optimales Spiel bleibt 49,9–50,0 Hz (nie Blackout); grober Richtungsfehler (Pumpen in Abendspitze) → 47,9 Hz → Blackout. Beide game.html + Benchmark.php syntaxgeprüft. - **Offen/Notiz:** „konkurrierende Stufen" ist über Tank-Zwang + Frequenz-Drift jetzt spürbar, aber echte Mehr-Strategien-Trade-offs bräuchten Config-Redesign (18 Tage neu tunen) → separat mit Thomas. Tank-Übertrag „Speicher von gestern" ist derzeit nur kosmetisch (runDayStepwise resettet auf tankTopInit) — bewusst NICHT angefasst (Solvability). Für Thomas notiert. - **DEPLOYED + Prod-verifiziert 2026-08-15** (Top-Level + App/, apache graceful) · committed · Gitea-Push ok. ## ❌ GESTRICHEN (Thomas-Entscheidung) - **Heli-Navigation NICHT erschweren.** Wird nicht mehr angefasst (früheres #19 „Navi-Drittel entschärfen" ist damit erledigt/vom Tisch). ## 📋 OFFENE TODOS (Stand 2026-08-15) ### A · Balancing — weiche Sims (kein echter Verlierzustand/Abschluss) - **fluss, farmer, tourismustal, weltküche, eu-werkstatt:** je ein sinnvoller Fail/Abschluss (Muster wie energiemanager). - **fluss:** Level-Skalierung (Wetter/Zeit). **farmer:** Klimahinweis VOR dem Pflanzen + wählbare Level. **busfahrt:** L3-Ziel (35 k) nachrechnen / `fixedFee` aktivieren. ### B · Konsistenz & Verdrahtung - **#12 Drei Feld-Schemata → eine Quelle** (SIM_METRICS / MODULE_HIGHLIGHTS / LIVE_PRIMARY_FIELDS). Lücken: `fluggesellschaft` in SIM_METRICS+badges.js; `LIVE_PRIMARY_FIELDS` für klima-3d/farmer/logistik. - **#14 Generischer Live-Vergleich** zeigt „0 %"/rohe Phase für weltkueche/farmer/fluss/logistik/kofferdetektiv/tourismus* (mit #12 lösen). - **#15 Lehrplan Liechtenstein (FL)** für eu-werkstatt, busfahrt, logistik, tourismusregion. - **#22 `weltkueche.page_url`** setzen (Info-Button kaputt) · **kofferdetektiv** fehlt `module_info`-Eintrag. - **#23 `$_SESSION['student_id']` wird nie gesetzt** → Leichte Sprache / per-Schüler-Land greift für Cookie-Schüler nie. Prüfen + fixen. - **#17 class_modules/class_assignments** transaktional vereinheitlichen (eine autoritative Quelle, `create`+`set_mode` in einem Write). ### C · Sicherheits-Härtung (keine akute Lücke mehr) - **#21** Login-Throttling/Lockout · `session_regenerate_id(true)` nach Login · Cookie-Flags (HttpOnly/SameSite/Secure) · CSRF/SameSite · Foto-Upload-PIN (`0815`) aus `.env`. ### D · Aufräumen (Wartbarkeit) - **#25 ~40 MB `.bak`-Müll + `_inbox` + DB-Dumps aus git** + `.gitignore` (macht jeden Push/Deploy schneller). ← größter Sofort-Nutzen - **#24 Toter Code:** renderLiveCockpit + `_cockpit*`, `toggleAssignmentPause`, `IV_PLABEL`/`ivParams`, altes `ACHIEVEMENTS`. - **#27** Toter Vite-Build-Stack (`vite.config.ts`, `App/src/`) + verwaiste Sims (wal/landwirtschaft/vulkan/staustufen) klären/entfernen. - **#26** design-system.css in teacher/schueler einbinden · **#28** Matrix-Spaltenköpfe Kurzname statt Emoji (iPad/a11y) · **#29** `kofferdetektiv/outlines.json` (1,4 MB) lazy laden · **#30** Migrations-Runner + `LIVE_SIM_SHORT` Geister-Module (stadt/regenwald/erdbeben) bereinigen. --- Read-only-Audit über 6 Dimensionen (Verdrahtung, Darstellungen, Skalierung/DB, Balancing, Codequalität, Sicherheit). Nichts geändert. Priorisiert P0→P3. **Positiv vorab:** SQL durchgängig prepared (keine ausnutzbare Injection), Fremd-Inhalte escaped (keine cross-user-XSS), DB-vs-JSON sauber getrennt (kein Laufzeitzustand in Dateien), alle 13 aktiven Sims sind grundverdrahtet. Vorbild-Balance: tourismusregion + klima. ## P0 — Sofort (Sicherheit / Datenintegrität) 1. **[Sec] Secrets aus git entfernen + rotieren.** MySQL-Root-PW im Klartext in `Don_t_Deploy/deploy.sh`, `deploy-2026-04-26.sh`, `bulk-reset-lernapps.php`; SMTP-PW-Fallback in `lib/Mailer.php:15`. Blockiert sicheres Gitea-Push. → rotieren, untracken, aus History (BFG/filter-repo). 2. **[Sec] IDOR in `progress.php:34`.** Zweig `if($studentId && $simId)` hat KEINEN Auth-Guard → fremder Fortschritt/Results ohne Login lesbar (ID enumerierbar). Kleiner, dringender Fix. 3. **[Sec] `licenses.php` Access Control.** `?admin=1` (Z.15) autorisiert jede Lehrperson → liest ALLE Lizenzcodes; `action=generate` (Z.173) ohne Admin → 1000 Codes generierbar. An `$_SESSION['admin_id']` binden. 4. **[Sec] `.env`-Deny ergänzen (Defense-in-Depth).** Verifiziert: `.env.production/.local` werden aktuell NICHT ausgeliefert (HTTP 404), aber es gibt keinen bewussten Schutz. `Require all denied` in `.htaccess`. 5. **[Sec] Schüler-Passwörter Klartext.** `students.password_plaintext` (auch im GET). Zugriff strikt auf Ticket-Druck scopen, aus normalem Schüler-GET raus (besser Reset-only). ## P1 — Hoch (Korrektheit / Skalierung / Balancing-kritisch) 6. **[Darstellung] Schüler sehen bei 9/15 Sims keine Ergebnisse.** `renderOwnRunCard` (schueler.html) hat nur 6 Renderer + Fallback zeigt nur Datum/Dauer; `sim-metrics.js` ist in schueler.html NICHT eingebunden. → einbinden + Fallback nutzt `renderSimMetrics(simId,d)`. 7. **[Skalierung] `assessments`-Aufblähung.** `assessment.php:28` immer INSERT; Heli-Ping alle 30 s → 8678 Zeilen bei 31 Schülern, 96,7 % Wegwerf-Telemetrie (phase 'running'). → Zwischenpings NICHT in `assessments` (nur `live_sessions.state_json`) + Purge-Job. 8. **[Skalierung/Code] String-Identität → `student_id`-FK.** Alles per `class_id + display_name` verknüpft (kein FK, unindexiert; „Anna" 16×). Umbenennen/Doppelname zerlegt Historie; Join nicht indexierbar. FK auf `student_sessions` (+`assessments`), ~40 Name-Joins ersetzen. 9. **[Skalierung] Cache-lose Voll-Historien-Aggregation.** `live.php` (benchRows/lastLogin) + `results.php` Matrix scoren die GESAMTE Klassen-Historie pro Poll, alle 4 s. → Datums-/LIMIT-Grenzen + gecachte Benchmark-Aggregate. 10. **[Balancing] sonnensystem — Bewertung bedeutungslos.** Falsche Antwort deckt sofort die richtige auf + Endlos-Retry → immer 5★; `obsShowEnd` nur bei 100 %; `level` 1–4 ungenutzt. → Score aus Erst-Treffer; Lösung nicht sofort zeigen. 11. **[Balancing] energiemanager — immer 5★, kein Fail.** Eindeutiges Lookup (5er-Schritte) löst alle Sets. → konkurrierende Stufen + echter Blackout-Fail (Frequenz-Tacho) + Schwierigkeitsrampe. ## P2 — Mittel (Konsistenz / Balancing / Skalierung) 12. **[Code/Darstellung] Drei Feld-Schemata konsolidieren** (SIM_METRICS / MODULE_HIGHLIGHTS / LIVE_PRIMARY_FIELDS) → eine Quelle. Sofort-Lücken: `fluggesellschaft` in SIM_METRICS+badges.js; `LIVE_PRIMARY_FIELDS` für klima-3d/farmer/logistik. 13. **[Darstellung] klima `final_budget`** in SIM_METRICS als „Mio €" (aktuell „€", 10⁶ falsch). 14. **[Darstellung] Generischer Live-Vergleich** zeigt „0 %"+rohe Phase für weltkueche/farmer/fluss/logistik/kofferdetektiv/tourismus* (mit #12 lösen). 15. **[Verdrahtung] Lehrplan Liechtenstein (FL)** für eu-werkstatt, busfahrt, logistik, tourismusregion ergänzen (D-A-CH+FL-Regel). 16. **[Skalierung] Indizes:** `assessments(class_id, submitted_at)`, `student_results(class_id, completed_at)`, Join-Seite `student_sessions`. 17. **[Code] class_modules/class_assignments** transaktional vereinheitlichen (eine autoritative Quelle; `create` und `set_mode` in einem Write). 18. **[Balancing] Echter Verlierzustand + Abschluss-Feedback** für die „weichen" Sims: fluss, farmer, tourismustal, weltküche, eu-werkstatt. 19. ~~**[Balancing] heli** Navi-Drittel entschärfen~~ — **GESTRICHEN (Thomas 2026-08-15): Heli-Navigation bleibt, nicht erschweren.** 20. **[Balancing] fluss** Level-Skalierung (Wetter/Zeit); **farmer** Klimahinweis VOR dem Pflanzen + wählbare Level; **busfahrt** L3-Ziel (35 k) nachrechnen/`fixedFee` aktivieren. 21. **[Sec] Härtung:** Login-Throttling/Lockout, `session_regenerate_id(true)` nach Login, Session-Cookie explizit (HttpOnly/SameSite/Secure), CSRF-Token oder SameSite erzwingen, foto-upload-PIN (`0815`) aus .env. 22. **[Verdrahtung] `weltkueche.page_url`** setzen (Info-Button/href kaputt); **kofferdetektiv** fehlt `module_info`-Eintrag (überall sonst verdrahtet). 23. **[Code] `$_SESSION['student_id']` wird nie gesetzt** → Leichte Sprache / per-Schüler-Land greifen für Cookie-Schüler nie (stiller Fallback). Verifizieren + fixen. ## P3 — Aufräumen (Wartbarkeit / niedrig) 24. **[Code] Toter Code:** `renderLiveCockpit` + ~15 `_cockpit*`-Helfer, `toggleAssignmentPause`, `IV_PLABEL`/`ivParams`, altes `ACHIEVEMENTS` (schueler.html). 25. **[Code] ~40 MB `.bak`-Müll** (347 Dateien, v. a. heli/sounds), `_inbox/` (~300 md), DB-Dumps aus git; `.gitignore` (`*.bak*`). 26. **[Code] design-system.css** in teacher/schueler einbinden (715 bzw. 130 Hex hartkodiert); perspektivisch auf `--ggs-*`. 27. **[Code] Toter Vite-Build-Stack** (`vite.config.ts`, `App/src/`), verwaiste Sims (wal/landwirtschaft/vulkan/staustufen) klären/entfernen. 28. **[Darstellung] Matrix-Spaltenköpfe:** sichtbarer Kurzname statt nur Emoji (a11y/iPad). 29. **[Skalierung] `kofferdetektiv/outlines.json` (1,4 MB)** cachen/lazy laden. 30. **[Code/Infra] Migrations-Runner** (`schema_migrations`) + idempotentes Deploy (`--delete`-Schutz, Mirror-Whitelist entschärfen); `LIVE_SIM_SHORT` Geister-Module (stadt/regenwald/erdbeben) bereinigen. --- Systemisches Muster Balancing: häufigster Mangel = **fehlender echter Verlierzustand** + „Lösung aufgedeckt + Endlos-Retry → garantierte Bestnote". Systemisches Muster Code: gute Abstraktionen existieren, werden aber nicht erzwungen (String-Join, 3 Schemata, design-system.css ungenutzt).