- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/ - 12 code-workspace-Files - STATUS-*.md - viele M/D/R-Änderungen an bereits getrackten Files - .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
5.9 KiB
Vertrag 3: Output-API
Was ein Modul am Ende einer Sitzung an die Plattform liefert. Plus Endpoint zum Zwischenspeichern des Resume-States.
Endgültiges Ergebnis bei Modul-Abschluss
Wenn Schüler*in das Modul abschließt (egal ob bestanden oder abgebrochen), pusht das Modul genau einen Result-Call:
POST /v2beta/api/result
Authorization: Bearer <session_token>
Content-Type: application/json
{
"moduleSlug": "logistik",
"moduleVersion": "2.0.0",
"specVersion": "1.0",
"completed": true,
"abandoned": false,
"score": 78,
"scoreMax": 100,
"durationS": 1452,
"difficulty": "L1",
"mode": "teacher_started",
"milestonesReached": [
"first-order-accepted",
"level-1-cleared"
],
"lehrplanCoverage": {
"AT-GW-1.4.2": "full",
"AT-GW-2.1.1": "partial",
"AT-GW-3.5.4": "none"
},
"freeTextAnswers": [
{
"promptId": "reflexion-end",
"promptText": "Warum hast du dich für die Bahnverbindung entschieden?",
"answerText": "Weil sie billiger war und nicht im Stau steht."
}
],
"artifacts": [
{
"type": "image/png",
"url": "/v2beta/sims/logistik/uploads/student-4711/route-final.png",
"label": "Letzte gewählte Route",
"thumbnail": "/v2beta/sims/logistik/uploads/student-4711/route-final-thumb.png"
}
],
"moduleSpecificData": {
"ordersCompleted": 6,
"ordersFailed": 2,
"totalCO2Kg": 142,
"totalKm": 1845
},
"ts": "2026-05-15T14:48:00Z"
}
Pflicht-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
moduleSlug |
String | Aus Manifest |
moduleVersion |
String | Aus Manifest |
specVersion |
String | Welche Spec-Version genutzt wurde |
completed |
Boolean | Modul ehrlich abgeschlossen (nicht abgebrochen) |
abandoned |
Boolean | Schüler*in hat Tab geschlossen / Stunde zu Ende ohne Abschluss |
score |
Integer 0–N | Punktzahl |
scoreMax |
Integer | Maximal mögliche Punktzahl |
durationS |
Integer | Reine Bearbeitungszeit (ohne Pausen >5min) |
difficulty |
String | Aus Input-Param |
mode |
String | Aus Input-Param |
lehrplanCoverage |
Object | Pro Anker aus Manifest: full / partial / none |
ts |
ISO-Timestamp | Zeitpunkt des Abschlusses |
Optionale Felder
milestonesReached— alle erreichten Milestone-IDs (Subset vonmanifest.telemetryMilestones)freeTextAnswers— Reflexionsfragen-Antworten der Schüler*in (für Lehrperson-Auswertung)artifacts— Modul-Output (Bilder, Karten, Audio) als URLsmoduleSpecificData— Frei strukturiertes JSON mit Modul-eigenen Kennzahlen für die Auswertung
Lehrplan-Coverage
Modul muss pro deklariertem Lehrplan-Anker entscheiden:
full— Schüler*in hat zu diesem Anker gearbeitet UND erfolgreich abgeschlossenpartial— hat zu diesem Anker gearbeitet, aber nicht voll geschafftnone— hat diesen Anker in dieser Sitzung nicht berührt (z.B. weil bestimmtes Level nicht erreicht)
Resume-State zwischenspeichern
Während der Sitzung kann (und soll) das Modul regelmäßig den State speichern, damit Schüler*in nach Crash / Logout fortsetzen kann:
PUT /v2beta/api/module/state
Authorization: Bearer <session_token>
Content-Type: application/json
{
"moduleSlug": "logistik",
"state": {
"<beliebiges Modul-JSON>": "..."
},
"summary": "Tag 3, Level 2, 4 von 8 Aufträgen erledigt"
}
Response 200:
{ "ok": true, "savedAt": "2026-05-15T14:23:00Z" }
Empfohlene Frequenz: jede 30s wenn State sich verändert hat, oder bei jedem Milestone. Nicht öfter (Server-Last).
Achtung: state ist ein opakes Modul-internes Format. Plattform
speichert es als JSON-Blob in module_state_v2-Tabelle, ohne es zu
parsen. Das Feld summary ist für die Lehrperson-Anzeige.
Artifacts hochladen
Wenn das Modul Bilder/Audio/Karten produziert, die in der Lehrer-Auswertung sichtbar sein sollen:
POST /v2beta/api/artifact
Authorization: Bearer <session_token>
Content-Type: multipart/form-data
[file]
moduleSlug=logistik
label=Letzte gewählte Route
Response 201:
{
"id": 8842,
"url": "/v2beta/sims/logistik/uploads/student-4711/route-final.png",
"thumbnail": "/v2beta/sims/logistik/uploads/student-4711/route-final-thumb.png"
}
URL und Thumbnail dann in artifacts-Array des Result-Calls referenzieren.
Was die Plattform mit dem Result macht
- Speichert in
assessments_v2(mitcreated_by_version='v2') - Aktualisiert
student_progress_v2(Modul-Fortschritt für Lerngeschichte-Anzeige) - Aktualisiert
lehrplan_progress_v2(welche Anker hat Schüler*in abgedeckt) - Pushed an Lehrer-Dashboard (Live-Update via Server-Sent-Events)
- Macht Result für die Klassen-Auswertung sichtbar
Level-Unlock-Update
Beim Result-Empfang aktualisiert die Plattform automatisch den
Level-Unlock-Status der Schüler*in (in student_level_unlock_v2):
attempts_per_level[difficulty] += 1best_score_per_level[difficulty]= max von alt und neu- Wenn
completed = trueUNDscore / scoreMax >= 0.6UND Schüler*in war aufhighest_unlocked_level:highest_completed_level = difficultyhighest_unlocked_level= nächster Level ausmanifest.difficultyLevels(falls vorhanden)
Modul muss sich darum nicht kümmern — passiert serverseitig.
✅ Geklärt mit Thomas (2026-05-17)
freeTextAnswers: mit Klarnamen an die Lehrperson (wie V1). Pädagogisch nötig — Lehrperson kann gezielt auf einzelne Schülerin eingehen. Andere Schülerinnen sehen die Antworten nicht.- Artifacts löschen (DSGVO): per Lehrperson-Cockpit „Sitzung komplett löschen" — eine Aktion löscht Assessment + zugeordnete Artifacts. Separater DELETE-Endpoint kommt mit dem Cockpit.
moduleSpecificData: bleibt opakes JSON. Cross-Modul-Vergleiche laufen überscore,scoreMax,lehrplanCoverage— Modul-eigene Kennzahlen sind Modul-Sache, kein Standardisierungs-Druck.