Review-Batch P0: Sicherheit + Schueler-Ergebnisse + Assessments-Aufblaehung

Sicherheit:
- progress.php: IDOR geschlossen (student_id-Zweig verlangt Lehrer-Login + Klassenbesitz)
- licenses.php: ?admin=1 und generate nur noch fuer echten Admin; Collision-Retry mit Cap
- .htaccess: .env/.sh/.sql/.bak Deny (Defense-in-Depth)

Schueler-Ergebnisse (kritisch):
- sim-metrics.js + .ivm-CSS in schueler.html; renderOwnRunCard-Fallback zeigt jetzt
  Sterne + grafische Kennzahlen fuer die 9 bisher leeren Sims
- sim-metrics.js: klima final_budget als "Mio EUR" statt "EUR" (Faktor 10^6)

Skalierung:
- assessment.php: Zwischen-Pings (phase running/started) nicht mehr persistiert
- heli: 30-s-assessmentPing entfernt (Live-Zustand laeuft ueber Heartbeat)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 16:21:25 +02:00
parent a3c5753cd7
commit 2984d93e7e
7 changed files with 65 additions and 14 deletions
+10
View File
@@ -25,6 +25,16 @@ if (!defined('GGS_MAX_SESSION_MS')) define('GGS_MAX_SESSION_MS', 7200000);
$rawDuration = (int)($body['duration'] ?? 0);
$durationMs = max(0, min($rawDuration, GGS_MAX_SESSION_MS));
// Zwischen-Telemetrie eines laufenden Durchgangs NICHT in assessments persistieren.
// Der Live-Zustand für das Lehrer-Cockpit kommt über den Heartbeat (live_sessions);
// diese 30-s-Pings (phase 'running'/'started') haben früher die Tabelle zugemüllt
// (~96 % der Zeilen). Nur echte Abschlüsse/Ergebnisse werden gespeichert.
$pl = $body['processLog'] ?? [];
$phase = (is_array($pl) && isset($pl['phase'])) ? $pl['phase'] : null;
if ($phase === 'running' || $phase === 'started') {
Response::ok(['skipped' => true]);
}
$db->execute(
'INSERT INTO assessments (session_id, sim_id, class_id, process_log, predictions, results, reflections, duration_ms, completed_phases)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',