- app.php: BASE_URL fuer *.geograsim.at war hart 'https://geograsim.at' -> auf
v3.geograsim.at lud die Glossar-API cross-origin -> CORS/NetworkError
("Glossar konnte nicht geladen werden"). Jetzt BASE_URL='https://'.$host
(same-origin auf jeder Umgebung; prod-neutral, geograsim.at bleibt gleich).
- weltkueche/game.html: Zweit-Lieferant hiess pauschal „Nachbarland" — Frankreich
ist aber kein Nachbar Oesterreichs. Jetzt „europaeisches Land in unserer Naehe".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- admin-todo.html: mobile-freundliche ToDo/Review-Liste (Prioritaeten, Haekchen +
Notizfelder je Punkt, localStorage, Notizen-Export), admin-gated, noindex. In
admin-licenses.html Nav + Backend-Werkzeuge verlinkt.
- admin.php: devPin auch bei STAGING=1 (v3, Mail bewusst tot) -> Self-Service-
Admin-Login ohne Mailversand. Prod unveraendert (STAGING dort nie definiert,
2FA-Mail-Pflicht bleibt).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Beim Hinzufuegen von firebase/php-jwt + predis war PHPMailer aus composer.json
und dem Autoloader gefallen (Dateien fehlten ganz). Folge: `new PHPMailer` fatalt
-> 500 bei register/reset/2FA/Schueler-Zugang. Auf v3 aufgedeckt und behoben:
composer.json require + installed.json + Autoloader (App/vendor) mit PHPMailer,
firebase, predis. Verifiziert: alle 3 Namespaces laden. KRITISCH fuer Prod-Deploy
(Manifest spiegelt vendor/), sonst waere dort der Mailversand gebrochen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem: lokal konnte man sich nicht als Admin anmelden — der 2FA-PIN kam nie
an (kein SMTP), und Mailer::sendAdminPin() warf sogar eine Exception, die den
Login komplett abbrach (leere Antwort → „MFA fehlt").
- admin.php: Mailversand nur auf Prod + in try/catch (Mail-Fehler darf den
Login NIE blocken). Lokal (!IS_PRODUCTION) wird der PIN als `devPin` in der
Login-Antwort zurückgegeben — auf Prod NIEMALS (2FA bleibt Pflicht).
- admin.html: devPin wird lokal automatisch ins PIN-Feld vorausgefüllt + als
Hinweis angezeigt.
Verifiziert (temp Test-Admin): login → devPin → verify → authenticated:true,
admin-weltkueche.html erreichbar. Prod unberührt (IS_PRODUCTION-Gate).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tages-Balken neu kodiert (nach Thomas' Spec):
- Eine Farbe pro Simulation (simColor, stabil per Hash).
- Balkenhöhe = Maß für den Erfolg (mehr Sterne → höher) → Leistungen auf einen
Blick vergleichbar.
- Rahmen kodiert den Zustand: fertig gespielt = geschlossener dünner Rahmen ·
noch dran = rechts offener Rahmen · Abbruch = gestrichelt + ✖ am Ende.
- Beschriftung: 3-Buchstaben-Kürzel (eng) → Wort → Wort+Lektion (Platz).
- Legende entsprechend erneuert.
Datenbasis vorhanden: live.php summary liefert success (inkl. 'aborted'),
stars, completed pro Session. Offen für v2: „läuft noch"-Balken aus aktiven
live_sessions einblenden (Tag-View ist bisher assessments-basiert = Abschlüsse).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diagnose per headless-Sim-Harness (.dontDeploy/tools/tr-balance-harness.mjs):
„alles zubauen" senkte die Umwelt nur 75→50 (über der 45-Schwelle) und der
Exit-Umwelt-Malus war TOTER Flag-Code → man konnte der Umwelt kaum schaden.
- model.js: (1) Exit-Umwelt-Malus wirklich angewandt — env<60 zieht bei
umweltbewussten Gästen Zufriedenheit ab (je tiefer, desto mehr). (2) Über-
tourismus-Drift im 10-s-Takt: dichte Bebauung (>6 Bauwerke) + Verkehr zehren
die Umwelt aus. (3) Einmalige Lern-Warnkarte, wenn Umwelt < 50 kippt.
- data.js: Naturschutzgebiet-Beschreibung klar (rettet die Umwelt +20, Natur-
Attraktionen +15 %, sperrt Bauplätze — Naturschutz vs. Ausbau abwägen).
- main.js: Willkommenskarte erklärt die Umwelt-Mechanik für Schüler.
Messung nachher: „alles zubauen" → Umwelt 75→37 (unter 45), Umweltziel
verfehlt, Ø-Sterne fallen. Feintuning Sterne-Kurve/Ansprüche-Eskalation
bleibt für Thomas' Playtest (Game-Feeling headless nicht bewertbar).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue admin-geschützte Seite admin-weltkueche.html: spiegelt die Spiel-Logik
(Heimat + Handels-Gravitation Menge÷Entfernung + Markt-Tags) und zeigt pro
Gericht × Zutat die vom Spiel akzeptierten Herkunftsländer (🟢 richtig) und
die Distraktoren (🔴). Filter nach Kategorie + Suche + „nur Auffällige".
Auffällig-Heuristik: Heimat-Zweig-Zutat mit „richtigem" Land > 1500 km
(surft echte Ausreißer, ohne Welt-Zutaten wie Pfeffer falsch zu flaggen) —
aktuell 5 Kandidaten. In Admin-Nav + Backend-Werkzeuge verlinkt.
Verifiziert: 30 Gerichte, Kartoffel/Eier → [AT, DE] (nicht Frankreich).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem: bei Pause lief die „Seit"-Zeit im Lehrer-Cockpit weiter, obwohl das
Spiel steht — live-client.js akkumulierte activeMs unabhängig vom Pause-Zustand.
- live-client.js: opt-in Pause-Unterstützung. window.__GGS_LIVE__.setPaused(bool)
friert die activeMs-Buchhaltung ein (lastTickAt wird weiter aktualisiert, damit
beim Fortsetzen nichts nachspringt). __paused zusätzlich im Heartbeat. Default
aus → alle anderen Sims unberührt.
- logistik game.html: Pause-/Auto-Button ruft setPaused(mode==='pause').
Verifiziert (Playwright): activeMs 0→2000 (läuft) → 2000 (Pause eingefroren)
→ 3999 (Fortsetzen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vorbereitung für den JWT+Redis-Umschalter: alle verstreuten
$_SESSION['teacher_id'|admin_id']-Zugriffe laufen jetzt durch Session::-Helper,
damit der Backend-Tausch später EINE Datei (Session.php) ist statt 18 Stellen.
- Session.php: neue Admin-Helper adminId()/loginAdmin()/logoutAdmin()/
requireAdmin() (mirror der Teacher-Helper). teacherId()/adminId() starten
die Session jetzt lazy (Aufrufer müssen Session::start() nicht mehr).
- 18 Fundstellen kanalisiert (admin.php, admin-accounts, admin-modules,
licenses, levels, waypoints, foto-upload, admin_gate, save_map).
- Country.php + app.php cockpit_href: über Session:: mit class_exists-Fallback
(Bootstrap/Lib-Kontext, Session evtl. nicht geladen).
Verhaltensneutral: 14/14 Lint OK, Helper-Round-Trip 6/6 PASS, Live-Smoke
(admin status/modules/accounts/licenses) weist unauth. Requests wie bisher
mit 401/403 ab. AUTH_BACKEND bleibt 'session' — Live unverändert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vorbereitung für pod-unabhängige Sessions (k8s-Ziel). Ändert am Live-System
NICHTS: AUTH_BACKEND='session' bleibt Default, die neuen Libs sind noch
nirgends verdrahtet.
- composer eingeführt: firebase/php-jwt ^6.11 + predis/predis ^2.4 (pure PHP,
keine Redis-Extension nötig → läuft auf XAMPP wie im Prod-Image). vendor/
committed (kein Composer auf dem Server).
- Jwt.php: HS256-Access-Token (issue/verify), decode() IMMER mit explizitem
Algorithmus (mitigiert Algorithmus-Confusion). 8/8 Tests grün.
- SessionStore.php: predis-gestützter Session/Refresh-Store (sess:<sid>,
Sliding-TTL, revoke=DEL) — die widerrufbare Session hinter dem kurzen JWT.
- app.php: vendor/autoload (guarded), Konstanten AUTH_BACKEND (Default session),
REDIS_URL, JWT_TTL, JWT_REFRESH_TTL. JWT_SECRET bewusst ohne Default.
- docker-compose.dev.yml: Redis (+ redis-commander UI) für lokale Dev-Parität.
- .env.example um Auth-Block ergänzt.
Nächste Phasen: $_SESSION-Zugriffe (293) durch Session:: kanalisieren →
Backend-Umschalter in Session.php → doppelgleisiger Cutover → Reporting auf
student_id-FK ziehen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Startbildschirm: Name/Klasscode-Felder entfernt (Kinder sind über die
Plattform-Session identifiziert). Klick auf eine Wegkarte startet die
Partie sofort — separater „Partie starten"-Button entfernt.
- Abschluss: „Ergebnis speichern"-Button entfernt; Speichern passiert schon
automatisch am Partie-Ende (submitAssessment). Hinweis „automatisch
gespeichert" ergänzt. btnSave-Listener null-sicher gemacht.
- Seilbahn: Talstation (Baukörper + Satteldach + Umlenkrad) ergänzt — der
Lift-Anfang wirkte vorher „transparent".
- Responsive/iPad: Panels bekommen Höhen-Deckel + internes Scrollen (decken
nie den ganzen Schirm zu). Neue Media-Query für iPad-Landscape (901–1200px
/ niedrige Höhe): kompaktere Panels, Graphen nach rechts-unten aus dem
Info-Panel-Bereich. Sehr flache Screens blenden die Graphen aus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Filter-JS liest a.dataset.anchorType, aber die Anker-<div>s setzten
kein data-anchor-type (nur data-country). Dadurch war `type === 'fach'`
nie wahr → für ein gewähltes Land wurde nie ein Anker ausgeblendet.
Fix: data-anchor-type am Anker-div ergänzt. Gilt für alle Modul-Seiten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
teacher.html: Menü „Live" → „Ergebnisse" mit Unteransichten
Tag·Aktuell·Vergleich·Gesamt (alte Ergebnisse-Ansicht ist jetzt „Gesamt").
Neue Kennzahl Qualität (grafischer richtig/falsch-Balken) in Aktuell +
Vergleich + Weltküche-Zeile, Gerichte-Zähler (Fleiß), Labels entschärft
(„Kritisch" → Stark/Solide/Viele Fehler).
Weltküche: korrekte Artikel (der/die/das) für alle 70 Zutaten in
production-matrix.json; verdrehten Herkunfts-Satz + Heimat-Banner neu und
marktbewusst (Ukraine-Distraktor ehrlich erklärt), „man"-Konstruktionen
für Singular/Plural.
_scripts.php: renderPage() injizierte Favicon per strrpos ins letzte
</head> — das lag in teacher.htmls printBatchTickets-JS-String → SyntaxError
zerschoss das ganze Inline-Script auf /teacher. Fix: strpos (erstes </head>).
tourismusregion: neue Karte passstrasse in maps-custom.json (Route bergauf
136 Punkte, 41 Bauslots) aus Editor-Export.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- keine Vorbereiten/paused/Start-freigeben/Pause mehr — Aufgabe ist ab Vergabe
sofort startbar (paused:false), Card zeigt nur "Laeuft" + Beenden
- Schueler-Card immer "Jetzt starten" (kein Warte-Zustand)
- "Aufgabe beenden" jetzt ordentlicher Dialog (#modal-stopassign) statt confirm()
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Modal "Aufgabe erteilen": Frist-Buttons (Heute/Morgen/+1 Woche/Kein Limit),
Default +1 Woche, Tempo-Checkbox "Vorbereiten", Live-Zusammenfassung als
Bestaetigung, Button "Auftrag erteilen"
- Aktive Klassen-Aufgabe-Card: Sim-Bild + Status (Vorbereitet/Laeuft) +
Steuerung "Start freigeben" / "Pause" / "Beenden" direkt auf der Card
(Tempo-Start nicht mehr in der individuellen Freigabe)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- aktive Klassenaufgabe wird automatisch als Vergleichs-Modul vorgewaehlt
(Chip mit 📋 markiert, immer vorne)
- Aufgaben-Banner: begonnen X/N (aus matrix) · gerade aktiv A · Oe Fortschritt
- zeigt Aufgabe auch wenn noch niemand aktiv ist (mit Hinweis)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- _liveProgressPct/_liveMood: aus dem Live-State jeder Sim ableitbarer
Fortschritt (%) und Lage-Ampel (health/heuristik) -> modueluebergreifend
vergleichbar
- weltkueche: redundante "Gerichte" ersetzt durch Fortschritt-Balken + Lage-Ampel
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- LIVE_PRIMARY_FIELDS.weltkueche: Gericht/Herkunft/Zutaten/Gerichte/Fehlklicks
(statt Rohdaten-Dump aller State-Keys) — 5 Spalten, kein Quer-Scroll
- Idle/Pause: live.php Fenster 30s->2h (LIVE_IDLE_WINDOW_SEC); Aktuell zeigt
laenger inaktive Sessions als "pausiert" (⏸, grau) statt sie zu verlieren;
braucht-Hilfe + aktiv-Zaehler nur fuer wirklich aktive Sessions
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Live-Modi jetzt nur Tag / Aktuell / Vergleich (Cockpit-Toggle raus)
- Aktuell: Live-"braucht Hilfe"-Banner + rote Zeilen-Hervorhebung (Heuristik
gespiegelt aus live.php), Spectator per Zeilenklick bleibt
- Reflexionen als Block am Ende von Aktuell, gecacht gegen 4s-Refresh-Flackern
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Live-Tab direkt nach Uebersicht (tabs-Array + DOM synchron)
- Live-Modus-Default 'uebersicht' (Tag), Toggle-Reihenfolge Tag zuerst
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Datums-Picker (von/bis) jetzt auch im Modul-Detail-Modal; Aendern laedt die
Ansicht mit neuem Zeitraum und haelt Uebersichts-Cards synchron
- _modFilter global in localStorage persistiert (bleibt bis Aenderung)
- resetModDateModal ↺ setzt auf Schuljahresbeginn
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wochen-Saeulengrafik:
- Pfeile Woche vor/zurueck (Kalenderwoche, view=activity&week_offset)
- Datum unter jedem Wochentag, halbierte + condensed Schrift
- Y-Skala links mit Anzahl, skaliert auf Max-Saeulenhoehe
- rendert auch bei leerer Woche (mit Hinweis) fuer die Navigation
Triage: alle 5 Cards immer sichtbar, leere mit "Aktuell niemand betroffen".
Module — Stand der Klasse:
- von/bis-Datumsfilter (Default bis=heute, von=Schuljahresbeginn 1. August)
- neuer view=mod_stats speist die Cards datumsgefiltert
- view=module auf student_results umgestellt (Datum+Score+JSON), from/to-Filter
wirkt auf Tabelle, Highlights, Champions, classStats; Zeitraum im Modal-Header
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- results.php view=today: heutige finale Laeufe (topToday) + vorher/nachher-Progress
je Schueler:in x Sim (aus student_results rekonstruiert) fuer Badge-Erkennung
- teacher.html: Sektion "Top Performers heute" (heutige Wertung, Sterne + Erfolg)
ersetzt Allzeit-Top; darunter "Neue Abzeichen heute" (badges.js, jetzt erfuellt
aber vor heute nicht)
- Wochen-Saeulengrafik: Sim-Titel klein in die Balkenabschnitte, hoehere Grafik
- Modul-Tabelle: Spielzeit-Spalte sortierbar (Quoten-Spalten schon sortierbar)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>