Files
geograsim/App/php/api/assessment.php
T
Adminator c1f90e255d Lehreransicht aufräumen: Sim-Labels + Logistik-Spalten + assessment-Skip-Fix
- SIM_LABELS: EIN Wort + eindeutiges 3-Buchstaben-Kürzel je App (zentrale
  Quelle simWord()/simCode()). Tages-Balken nutzt jetzt Kürzel (eng) → Wort
  (mittel) → Wort+Lektion (breit) statt kryptischem "Log L1".
- LIVE_PRIMARY_FIELDS['logistik'] ergänzt (Stufe · Budget · Geliefert/Gesamt ·
  Unterwegs · Offen · Verspätet · Fortschritt) — vorher Roh-Dump aller Keys.
- Aktuell-Fallback (uncurated Sims): interne __-Heartbeat-Keys + simId/
  timestamp/screen ausgeblendet, nicht mehr als Spalten.
- assessment.php: Skip-Bug gefixt — las phase aus $body['processLog']['phase'],
  gesendet wird $body['phase']. Dadurch landeten alle 'started'/'running'-Pings
  als LEERE Zeilen in assessments und verschmutzten Ergebnisse/Tag. Jetzt
  greift der Skip; nur echte 'completed'-Abschlüsse werden gespeichert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-19 15:05:42 +02:00

60 lines
2.3 KiB
PHP

<?php
/**
* API: Assessment-Daten speichern
* POST /api/assessment {simId, processLog, predictions, results, reflections, duration, completedPhases}
*/
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
Response::error('Nur POST erlaubt', 405);
}
$sessionId = Session::requireStudent();
$body = json_decode(file_get_contents('php://input'), true);
if (!$body || !isset($body['simId'])) {
Response::error('simId erforderlich');
}
$db = Database::get();
// class_id aus student_session holen
$session = $db->fetchOne('SELECT class_id FROM student_sessions WHERE id = ?', [$sessionId]);
$classId = $session ? $session['class_id'] : null;
// Cap defensiv: nie >120 min in die DB (siehe GGS_MAX_SESSION_MS).
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.
// phase steht auf oberster Body-Ebene (alle Sims senden {simId, phase, …}).
// Früher wurde fälschlich $body['processLog']['phase'] gelesen → der Skip
// griff nie, und JEDER 'started'/'running'-Ping landete als leere Zeile in
// assessments (verschmutzt Ergebnisse/Tag). Robust: oberste Ebene, Fallback nested.
$pl = $body['processLog'] ?? [];
$phase = $body['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 (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[
$sessionId,
$body['simId'],
$classId,
json_encode($body['processLog'] ?? []),
json_encode($body['predictions'] ?? []),
json_encode($body['results'] ?? []),
json_encode($body['reflections'] ?? []),
$durationMs,
json_encode($body['completedPhases'] ?? []),
]
);
Response::ok(['id' => $db->lastInsertId()]);