# Anhang: Level-Unlock-Konzept (Drei-Modi-Logik) Beschreibt, wie Schüler*innen Schwierigkeitsstufen wählen können — in welchem Modus, mit welchem Recht, und wie die Freischaltung läuft. ## Drei Modi ### A) Freies Arbeiten (`mode=free`) Schüler*in öffnet ein Modul, das die Lehrperson generell für die Klasse freigegeben hat. Sie wählt eine Schwierigkeit aus dem **freigeschalteten Bereich** ihres Profils. - Default-Start: Level 1 (L1) immer freigeschaltet - L2 freigeschaltet, sobald L1 erfolgreich abgeschlossen (Score / ScoreMax ≥ 60% UND `completed = true`) - L3 freigeschaltet, sobald L2 erfolgreich abgeschlossen - … usw. für alle in `manifest.difficultyLevels` definierten Stufen Modul liest `levelUnlocks[moduleSlug].highestUnlocked` aus dem Profil und rendert Level-Wähler entsprechend (z.B. L1 + L2 wählbar, L3 ausgegraut mit Schloss-Icon). ### B) Auftragsmodus (`mode=teacher_started`) Lehrperson hat einen Auftrag erstellt (`class_assignments_v2`) mit fester `difficulty`. Modul startet **direkt** mit dieser Schwierigkeit, Schüler*in kann nicht wechseln. Level-Wähler wird ausgeblendet. ### C) Nachteilsausgleich-Override (Schüler*in × beide Modi) Wenn `students.nachteilsausgleich = TRUE` (von Lehrperson in Klassenliste gesetzt), darf die Schüler*in **immer** jeden Level frei wählen — auch im Auftragsmodus. Pädagogische Begründung: - Kind mit Lernschwäche darf auf L1 herunter, wenn der Auftrag L2 war - Kind mit Hochbegabung darf auf L3 hoch, wenn der Auftrag L1 war - Übergeordnetes Prinzip: keine künstliche Über- oder Unterforderung Modul erkennt das aus `profile.nachteilsausgleich` und ignoriert die `difficulty`-URL-Vorgabe — zeigt stattdessen den Level-Wähler. ## DB-Tabellen ### `student_level_unlock_v2` ``` student_id INT module_slug VARCHAR(64) highest_unlocked_level VARCHAR(20) -- 'L1', 'L2', 'L3' highest_completed_level VARCHAR(20) -- nullable best_score_per_level JSON -- {"L1": {"score":95,"max":100}, "L2":{...}} attempts_per_level JSON -- {"L1": 3, "L2": 1} last_played_at TIMESTAMP PRIMARY KEY (student_id, module_slug) ``` ### `students.nachteilsausgleich` ``` ALTER TABLE students ADD COLUMN nachteilsausgleich BOOLEAN DEFAULT FALSE ``` ### `class_assignments_v2` ``` id BIGINT class_id INT teacher_id INT module_slug VARCHAR(64) difficulty VARCHAR(20) -- vorgegebene Schwierigkeit custom_params JSON -- V3: weitere Lehrperson-Overrides starts_at, ends_at, active ``` ## Automatische Updates beim Result-Empfang Wenn ein Modul ein Result via `POST /api/result` postet, aktualisiert die Plattform `student_level_unlock_v2` automatisch: 1. `attempts_per_level[difficulty] += 1` 2. `best_score_per_level[difficulty]` = max(alt, neu) 3. Wenn `completed = true` UND `score/scoreMax >= 0.6`: - `highest_completed_level = max(alt, difficulty)` - Wenn `difficulty == highest_unlocked_level` UND es einen nächsten Level in `manifest.difficultyLevels` gibt: - `highest_unlocked_level = nächster Level` Modul muss keinen Update-Call machen — passiert serverseitig im `result.php`-Endpoint. ## Lehrperson-Sicht im Cockpit (V2) Pro Schüler*in × Modul zeigt das Cockpit: - `highest_completed_level` mit Best-Score - `highest_unlocked_level` (was als nächstes freigeschaltet ist) - `attempts_per_level` (wie oft pro Stufe versucht) - Liste der Versuche mit Datum + Score Damit ist die Lerngeschichte transparent. ## V3-Ausblick (nicht heute) In V3 darf die Lehrperson: - Beim Auftrag zusätzlich zur `difficulty` einzelne Parameter überschreiben (z.B. „L2 mit 8000 Startbudget statt 5000") via `custom_params` in `class_assignments_v2` - Frei-Modus-Levels pro Klasse einschränken (z.B. „diese Klasse darf nur L1 und L2 nutzen") V2: nur `difficulty` einstellbar. Genug für den Anfang. ## Memory-Verweis Siehe [[project-v2-level-unlock-konzept]] in der Atlas-Memory.