# LehrerApp — Entwicklungs-Roadmap Strukturierte ToDo-Liste aller offenen Entwicklungsschritte. Jeder Punkt ist so formuliert, dass er einzeln an einen Agenten übergeben werden kann. **Stand:** 2026-08-04 **Legende:** `[ ]` offen · `[~]` teilweise umgesetzt · `[x]` fertig --- ## 0. Konventionen für alle Aufgaben Diese Regeln gelten für jede Aufgabe unten und müssen nicht wiederholt werden. - **MVVM:** Logik in ViewModels (`CommunityToolkit.Mvvm`, `[ObservableProperty]` / `[RelayCommand]`), Views enthalten nur Binding. Kein Code-Behind außer Dialog-Verdrahtung. - **DI:** Neue Repositories/Services/ViewModels in `LehrerApp.Desktop/AppBootstrapper.cs` registrieren. Repositories + Listen-VMs = Singleton, Detail-/Dialog-VMs = Transient. - **Daten:** Neue Collections in `LehrerApp.Data/LiteDbContext.cs` anlegen, Indexe in `EnsureIndexes()`. Interface nach `LehrerApp.Core/Interfaces/IRepositories.cs`, Implementierung nach `LehrerApp.Data/Repositories/AllRepositories.cs`. - **Dialoge:** `Window` mit `Close(true/false)`, DataContext manuell gesetzt (Muster siehe [AddGroupDialog.axaml.cs](LehrerApp.Desktop/Views/Groups/AddGroupDialog.axaml.cs)). - **Sprache:** Alle UI-Texte auf Deutsch. Datumsformat `dd.MM.yyyy`, Kultur `de-DE`. - **Modelle:** `UpdatedAt` bei jedem Speichern setzen (Grundlage für Sync-Konfliktauflösung). --- ## 1. Klausuren & Leistungsüberprüfungen Modelle `Exam`, `ExamTask`, `GradingKeyEntry`, `ExamResult` existieren bereits in [Exam.cs](LehrerApp.Core/Models/Exam.cs), Repositories ebenfalls. Die komplette UI fehlt. **Niveaudifferenzierung (E/G/Förder) ist bereits umgesetzt** — nicht aus dieser Liste, sondern ein separater Bedarf (Nachteilsausgleich/Binnendifferenzierung): `LearningGroup.IsDifferentiated` (Checkbox in den Stammdaten) blendet eine Niveau-Zuordnung je Schüler ein (`GroupMembership.Niveau`, Schüler-Tab). Klausuren bekommen optional ein `Niveau`; Punkteeingabe und Auswertung filtern dann automatisch auf die passenden Schüler. Workflow: G-Klausur normal anlegen, per "Duplizieren" (1.1.4) die E-Variante mit eigenen Aufgaben/Punkten ableiten (Niveau wird beim Duplizieren bewusst zurückgesetzt). Vollständig individuelle Förderklausuren (nur für einen einzelnen Schüler) laufen pragmatisch über "Abwesend" bei den übrigen Schülern statt über eine eigene Schüler-Zuordnung. ### 1.1 Klausur anlegen und verwalten - [x] **1.1.1** Dialog `AddExamDialog` — Titel, Datum, Fach, Klausurnummer, Notizen. Ersetzt den TODO-Stub `AddExam()` in [GroupViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs). Umgesetzt als `ExamDialog`/`ExamDialogViewModel`. - [x] **1.1.2** Klausur bearbeiten/löschen (Kontextmenü im Klausuren-Tab, Löschen mit Rückfrage). - [x] **1.1.3** Statuswechsel `Planned → Conducted → Graded → Returned` per Button, inkl. Farbcodierung des Status im DataGrid. - [x] **1.1.4** Klausur aus bestehender Klausur duplizieren (Aufgaben + Notenschlüssel übernehmen, neues Datum) — für Parallelkurse. ### 1.2 Aufgabenstruktur (`ExamTask`) - [x] **1.2.1** Editor für die Aufgabenliste: Nr., Titel, Maximalpunkte, Gewichtung. Zeilen hinzufügen/entfernen/umsortieren. Umgesetzt im `ExamDialog` (Teil von 1.1.1). - [x] **1.2.2** Automatische Anzeige der Gesamtpunktzahl, Warnung bei 0 Punkten. - [ ] **1.2.3** Optional: Teilaufgaben (a/b/c) — erfordert Modellerweiterung, vorher entscheiden. - [x] **1.2.4** Zuordnung von Kompetenzen (`CompetencyItem`) zu einzelnen Aufgaben — Voraussetzung für die Kompetenzauswertung in 8.3. ### 1.3 Notenschlüssel - [x] **1.3.1** Editor für `GradingKey` mit Vorbelegung aus `GradingService.DefaultKey1To6()` / `DefaultKey0To15()` je nach `GradingSystem` der Gruppe. Umgesetzt im `ExamDialog` (Teil von 1.1.1), analog zum Aufgaben-Editor. - [x] **1.3.2** Notenschlüssel als wiederverwendbare Vorlage speichern (neues Modell `GradingKeyTemplate` + Repository) und in Einstellungen verwalten. - [x] **1.3.3** Live-Vorschau: Punktegrenzen absolut anzeigen (z.B. "Note 2 ab 45 von 60 P."). - [x] **1.3.4** Validierung: lückenlose, absteigende Prozentgrenzen, keine Dopplungen (`GradingService.ValidateGradingKey`). ### 1.4 Punkteeingabe & Korrektur - [x] **1.4.1** Eingaberaster: Zeilen = Schüler, Spalten = Aufgaben, letzte Spalte Summe + Note. Note wird live über `GradingService.CalculateGrade()` berechnet. Umgesetzt als eigener Dialog `ExamGradingDialog`, erreichbar über "Punkte eingeben" im Klausuren-Tab (Button/Kontextmenü bei ausgewählter Klausur). - [x] **1.4.2** Tastaturnavigation: Tab bewegt sich nativ zur nächsten Zelle, Enter/Pfeil-Hoch/ Pfeil-Runter springen zur gleichen Spalte in der Nachbarzeile, direkte Zifferneingabe und halbe Punkte (Komma oder Punkt) erlaubt. - [x] **1.4.3** Kennzeichnung "Abwesend" (`ExamResult.Absent`) per Checkbox — Note zeigt "abwesend" statt einer berechneten Note. Ausschluss aus Statistiken über 1.5 umgesetzt. - [x] **1.4.4** Kommentarfeld pro Schüler (`ExamResult.Comment`). - [x] **1.4.5** Validierung: Punkte < 0 oder > Maximalpunkte der Aufgabe wird rot markiert und nicht gespeichert (`PointsCell.TrySetValue`). - [x] **1.4.6** Autosave nach jeder Zelle (kein expliziter Speichern-Button nötig). ### 1.5 Klausurauswertung - [x] **1.5.1** Notenspiegel (Häufigkeitsverteilung als Balken), Durchschnitt, Median, Anteil unter 4 / unter 5 Punkten. Umgesetzt als neuer Dialog `ExamEvaluationDialog`, erreichbar über "Auswertung" im Klausuren-Tab. Bei Notensystem 1–6 zeigt der Schwellenwert sinngemäß "Anteil nicht ausreichend (Note 5/6)" statt der Punktegrenzen. Abwesende werden aus allen Statistiken ausgeschlossen (löst damit auch den Hinweis aus 1.4.3 ein). - [x] **1.5.2** Aufgabenanalyse: durchschnittlicher Erfüllungsgrad pro Aufgabe in Prozent, Kennzeichnung auffällig schwacher Aufgaben (Ø < 50 %, rot markiert). - [x] **1.5.3** Notenschlüssel nachträglich verschieben und Auswirkung sofort im Notenspiegel sehen — Änderungen wirken sich live aus, erst "Übernehmen" schreibt sie in die Klausur zurück. - [x] **1.5.4** Export der Auswertung — als eigenständiger CSV-Export direkt im Dialog umgesetzt (analog zum bestehenden JSON-Export der Kompetenzkataloge), nicht über eine gemeinsame Export-Infrastruktur, da Kapitel 11 ("Bisher nicht vorhanden — komplett neu") noch aussteht. --- ## 2. Noten & Zeugnisnoten Modell `Grade` existiert in [Planning.cs](LehrerApp.Core/Models/Planning.cs), `GradeRepository` ebenfalls. Der Tab "Noten" in [GroupDetailView.axaml](LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml) ist jetzt vollständig umgesetzt (siehe unten), ebenso der gleichnamige Tab im Schülerdetail (2.5). ### 2.1 Notenübersicht der Gruppe - [x] **2.1.1** Matrix: Zeilen = Schüler, Spalten = alle Leistungen (Klausuren, Mitarbeit je Halbjahr, sonstige Noten). Zelle zeigt Note/Punkte. - [x] **2.1.2** Spalte "Gesamt" mit gewichtetem Durchschnitt über `GradingService.WeightedAverage()`. - [x] **2.1.3** Sortierung nach Name / Gesamtnote, Umschalten Noten ↔ Punkte. - [x] **2.1.4** Halbjahresfilter (H1 / H2 / Gesamtjahr), berücksichtigt `GroupMembership.Period`. ### 2.2 Einzelnoten pflegen - [x] **2.2.1** Dialog "Note hinzufügen": Kategorie (`GradeCategory`), Wert, Datum, Gewichtung, Notiz. - [x] **2.2.2** Note bearbeiten / löschen mit Historie (wer/wann geändert) — mindestens `CreatedAt` sichtbar. - [x] **2.2.3** Sammelerfassung: eine Note (z.B. Hausaufgabenkontrolle) für die ganze Gruppe auf einmal. ### 2.3 Gewichtungsschema - [x] **2.3.1** Neues Modell `GradingScheme` je Gruppe: prozentuale Anteile von Klausuren / Mitarbeit / sonstige Leistungen (z.B. 50/40/10). - [x] **2.3.2** UI zur Bearbeitung, Validierung auf Summe 100 %. - [x] **2.3.3** Voreinstellung je Gruppentyp (`Class` vs. `Course`) in den Einstellungen. ### 2.4 Zeugnisnote - [x] **2.4.1** Berechnung der Zeugnisnote aus Schema (2.3) + allen Teilnoten, Rundungsregel konfigurierbar (kaufmännisch / pädagogisch abweichbar). - [x] **2.4.2** Manuelles Übersteuern mit Pflicht-Begründung (pädagogischer Spielraum). - [x] **2.4.3** Zeugnisnoten-Ansicht mit Sperren/Festschreiben zum Konferenztermin. - [x] **2.4.4** Export der Zeugnisnotenliste (siehe 11.2). ### 2.5 Notenentwicklung - [x] **2.5.1** Verlaufsdiagramm pro Schüler über das Schuljahr (im Schülerdetail). - [x] **2.5.2** Auffälligkeiten markieren: Abfall um ≥ 1 Note, Versetzungsgefährdung (Note 5/6). Umgesetzt über [GradeOverviewViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/GradeOverviewViewModels.cs) (Matrix-Tab, Einzelnoten-Dialoge), [ReportGradeViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/ReportGradeViewModels.cs) (Zeugnisnoten-Dialog) und die neuen Modelle `GradingScheme`/`ReportGrade` in [Planning.cs](LehrerApp.Core/Models/Planning.cs). Das Gewichtungsschema wird pro Gruppe gesucht, sonst die Voreinstellung des Gruppentyps (Einstellungen → Notenschema), sonst ein Fallback 50/40/10 verwendet; Bereiche ohne Werte werden bei der Berechnung ausgelassen und die verbleibenden Prozentanteile neu normiert (`GradingService.CalculateReportGrade()`). Notenentwicklung im Schülerdetail zeigt ein einfaches Balken-Sparkline je Lerngruppe über alle Klausur- und Einzelnoten-Einträge chronologisch — **jeder Balken ist ein einzelner `Grade`- bzw. Klausurergebnis-Eintrag, keine Mitarbeit-"Sitzung"**. Die Herkunft (Kategorie wie "Mündlich"/"Mitarbeit" oder Klausurtitel) stand ursprünglich nur im Tooltip und nicht sichtbar auf der Kachel — das führte zu Verwirrung, welche Zahl wofür steht, und wurde ergänzt (`GradeHistoryPoint.Label` jetzt auch unter dem Balken sichtbar, nicht nur im Tooltip), siehe [StudentDetailView.axaml](LehrerApp.Desktop/Views/Students/StudentDetailView.axaml). --- ## 3. Mündliche Mitarbeit — offene Punkte Grundfunktion ist umgesetzt (Sitzungen, Raster, Schnelleingabe-Dialog). Siehe [ParticipationViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/ParticipationViewModels.cs). ### 3.1 Aspekte konfigurieren - [ ] **3.1.1** UI zum Anlegen/Bearbeiten/Löschen von `ParticipationAspect` **pro Gruppe** (Fach Chemie: z.B. "Experiment", "Protokoll") — `GroupId = null` bleibt global. - [ ] **3.1.2** Reihenfolge der Aspekte per Drag & Drop oder Hoch/Runter-Buttons festlegen (bestimmt auch die Q/W/E/R/T-Belegung im Schnelleingabe-Dialog). - [ ] **3.1.3** Aspekt-Typen `Scale3`, `Binary`, `Points` in Raster und Dialog vollständig unterstützen (bisher primär `Scale5`). - [ ] **3.1.4** Aspekt deaktivieren statt löschen, damit alte Einträge gültig bleiben. ### 3.2 Aggregation zur Mitarbeitsnote - [x] **3.2.1** Gewichtung je Aspekt konfigurierbar (z.B. Qualität 50 %, Quantität 30 %, Experiment 20 %). - [x] **3.2.2** Berechnung einer Mitarbeitsnote je Halbjahr aus allen Sitzungen, Ausgabe als Note bzw. Punkte je nach `GradingSystem` der Gruppe. - [x] **3.2.3** Umgang mit fehlenden Werten festlegen (nicht bewertet ≠ schlecht bewertet). - [x] **3.2.4** Übernahme der berechneten Mitarbeitsnote als `Grade` mit `Category = Participation` (Anbindung an 2.1). - [x] **3.2.5** Trendanzeige pro Schüler (Entwicklung über die Sitzungen hinweg). Umgesetzt über den neuen Dialog "Ø Mitarbeitsnote" im Mitarbeit-Tab ([ParticipationGradeViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/ParticipationGradeViewModels.cs), [ParticipationGradeDialog.axaml](LehrerApp.Desktop/Views/Groups/ParticipationGradeDialog.axaml)): Zeitraum wählbar (Gesamtjahr/H1/H2), Aspekt-Gewichtung live editierbar (`ParticipationAspect.Weight`, da die eigentliche Aspekt-Verwaltung aus 3.1 noch fehlt), Mapping der Bewertungsskala (-2..+2) auf Note/Punkte über `GradingService.ParticipationGrade()`, einfache Trendanzeige (↑/↓/→) durch Vergleich der ersten mit der zweiten Hälfte der Sitzungen. "Übernehmen" aktualisiert eine bestehende Mitarbeit-Note für denselben Zeitraum statt sie zu duplizieren (erkannt über den `Grade.Note`-Tag). ### 3.3 Sitzungen - [ ] **3.3.1** Sitzung automatisch aus einer geplanten `Lesson` erzeugen (Datum + Thema übernehmen) — Abhängigkeit zu 4.2. - [x] **3.3.2** Anwesenheit in der Sitzung erfassen — als `ParticipationEntry.Attendance` (krank: Entschuldigung offen/entschuldigt/unentschuldigt), nicht als "verspätet"; siehe unten. Vorgriff auf 5.2, ersetzt dessen 5.2.1/5.2.4 aber nicht vollständig (kein Fehlzeitenmodul über alle Stundentypen hinweg, nur innerhalb von Mitarbeit-Sitzungen). - [ ] **3.3.3** Sitzung bearbeiten/löschen inkl. Rückfrage bei vorhandenen Bewertungen. - [ ] **3.3.4** Sitzungen mehrerer Gruppen im Kalenderüberblick. ### Abschnittsnoten & Mitarbeits-Assistent (nicht aus dieser Liste, eigener Workflow-Bedarf) Ergänzt den Workflow "regelmäßig (alle 4–7 Wochen) mündliche Noten zu einer Abschnittsnote zusammenziehen, daraus die Halbjahresnote bilden": - `ParticipationEntry.HomeworkMissing` (bool) und `.Attendance` (`AttendanceStatus?`: `ExcusePending`/`Excused`/`Unexcused`) — editierbar direkt im Bewertungsraster ([ParticipationTabView.axaml](LehrerApp.Desktop/Views/Groups/ParticipationTabView.axaml), Spalten "HA"/"Anwesenheit") und im neuen Mitarbeits-Assistenten. `ExcusePending` ist bewusst ein Zwischenzustand, da die Entschuldigung meist erst später eintrifft. - Neues Modell `ParticipationSection` (Abschnitt: Start/Ende/Bezeichnung je Gruppe) — nur abgeschlossene Abschnitte werden gespeichert, der laufende Zeitraum ergibt sich aus dem Ende des letzten Abschnitts bis heute. - Neues Fenster **Mitarbeits-Assistent** ([ParticipationWizardViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/ParticipationWizardViewModels.cs), [ParticipationWizardDialog.axaml](LehrerApp.Desktop/Views/Groups/ParticipationWizardDialog.axaml)): Zeitleiste je Schüler (Sitzungen als Bewertungs-Badges, Klausurtermine, Symbole für Hausaufgaben/ Bemerkung/Anwesenheit), gruppiert nach Abschnitten. "Abschnitt abschließen" berechnet für alle Schüler einen Notenvorschlag aus den Sitzungen im Zeitraum und speichert ihn als `Grade` (`Category = Participation`, `Note = "Abschnitt: "`), individuell nachjustierbar. "Halbjahresnote aus Abschnitten übernehmen" mittelt die Abschnittsnoten eines Zeitraums und speichert sie über denselben `Grade.Note`-Tag wie der bestehende "Ø Mitarbeitsnote"-Dialog (3.2) — beide Wege sind kompatibel, der Assistent baut auf 3.2 auf statt es zu ersetzen. - Dashboard-Kachel "Offene Entschuldigungen": listet alle `ExcusePending`-Einträge der letzten 21 Tage gruppenübergreifend mit Direktauflösung; ältere Einträge werden ausgeblendet statt automatisch entschieden (pädagogische Entscheidung bleibt bei der Lehrkraft). --- ## 4. Unterrichtsplanung Modelle `Unit` und `Lesson` existieren, `UnitRepository`/`LessonRepository` ebenfalls. Navigationspunkt "Unterrichtsplanung" zeigt seit 4.3 den Stundenplan (`TimetableView`, Standardtab "Heute" + Bearbeiten-Raster) statt eines `PlaceholderViewModel`. Eine gruppenübergreifende Wochenansicht fehlt noch, siehe 4.4. 4.1/4.2 leben unabhängig davon im gruppenspezifischen Tab "Planung" (`GroupDetailView`), siehe unten. ### 4.1 Unterrichtseinheiten (`Unit`) - [x] **4.1.1** Listenansicht der Einheiten je Gruppe mit Status und Zeitraum (ersetzt den Platzhalter im Tab "Planung"). - [x] **4.1.2** Dialog Einheit anlegen/bearbeiten: Titel, Fach, Zeitraum, Status, Notizen. - [x] **4.1.3** Kompetenzen aus dem Katalog (siehe 8) einer Einheit zuordnen — Mehrfachauswahl. - [x] **4.1.4** Einheit als Vorlage speichern und in eine andere Gruppe kopieren (inkl. Stunden, ohne Datumsbezug). - [x] **4.1.5** Fortschrittsanzeige: gehaltene / geplante Stunden der Einheit. ### 4.2 Einzelstunden (`Lesson`) - [x] **4.2.1** Stundenliste innerhalb einer Einheit, sortiert nach Datum/Stundennummer. - [x] **4.2.2** Stundeneditor als tabellarischer Verlaufsplan (Vorbild: vom Nutzer bereitgestelltes Beispiel eines realen Stundenverlaufsplans) statt einzelnem Phase-Textfeld + Methoden-/ Materialien-Chips: mehrere Phasen-Zeilen (Einstieg, Erarbeitung 1, Sicherung 1, ...), je Zeile Name, Dauer (Minuten), Tätigkeit, Material (mit Autovervollständigung aus bisherigen Einträgen) und ein Kurzsymbol, das den Materialfluss kodiert (z.B. `Tb->SH` = Tafelbild wird ins Schülerheft übertragen). - [x] **4.2.3** Status `Planned → Conducted` setzen, Reflexionsfeld nach der Stunde. - [x] **4.2.4** Stunden verschieben (z.B. bei Ausfall) — Folgestunden automatisch nachrücken. - [ ] **4.2.5** Stunden serienweise aus dem Stundenplan (4.3) erzeugen. Bewusst nicht mit einem Ersatz-Mechanismus vorgezogen — hängt an 4.3 (Wochentag/Stunden-Muster aus dem Stundenplan), ein selbstgebautes "N Wochenstunden anlegen" wäre nur Mehrarbeit, die 4.3 später doppelt. Einzige Möglichkeit, Stunden anzulegen, bleibt vorerst der manuelle "+ Stunde"-Dialog (4.2.2). Umgesetzt über den neuen Tab "Planung" in [GroupDetailView.axaml](LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml) (ersetzt den bisherigen Platzhalter), analog zu Mitarbeit/Noten als eigenes UserControl [PlanningTabView.axaml](LehrerApp.Desktop/Views/Groups/PlanningTabView.axaml) mit eigenem [PlanningTabViewModel](LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs) (Einheiten-Tabelle oben, Stunden der ausgewählten Einheit darunter). Modelle, Repositories und DI-Registrierung existierten bereits; neu sind nur die UI-Schicht sowie zwei Verhaltensfragen: - **Fach** wird wie bei `Exam` nicht auf `Unit` gespeichert, sondern read-only aus `LearningGroup.SubjectId` anzeigt (jede Gruppe unterrichtet ein Fach). - **Verschieben mit Nachrücken (4.2.4):** `MoveLessonDialog` fragt neues Datum + Checkbox "Folgestunden automatisch verschieben" (Standard an) ab. Verschoben werden dabei nur noch geplante (`Planned`) Stunden derselben Einheit, die ursprünglich nach der verschobenen Stunde lagen; bereits durchgeführte (`Conducted`) Stunden bleiben unangetastet. - **Vorlage-Kopie (4.1.4):** `CopyUnitDialog` fragt Zielgruppe + neues Startdatum ab. "Ohne Datumsbezug" bedeutet konkret: die relativen Tages-Abstände der Stunden zueinander bleiben erhalten, werden aber auf das neue Startdatum re-verankert statt die alten Kalendertage zu übernehmen. Reflexion wird geleert, Status auf "Geplant" zurückgesetzt, `Lesson.GroupId` wird auf jeder Kopie explizit auf die Zielgruppe gesetzt (siehe [Datenmodell.md](docs/Datenmodell.md), Abschnitt "Bewusste Denormalisierung"). `LessonRepository.GetByUnit` sortiert jetzt zusätzlich nach `LessonNumber` bei gleichem Datum (Doppelstunden am selben Tag). **Nachtrag zu 4.2.2 (Verlaufsplan-Redesign):** `Lesson.Phase`/`Methods`/`Materials` wurden durch `Lesson.Phases: List` (Name/Dauer/Tätigkeit/Material/Kurzsymbol je Zeile) sowie ein optionales `Lesson.StartTime` ersetzt — Modelle, Migration und Editor in [Planning.cs](LehrerApp.Core/Models/Planning.cs), [LiteDbContext.cs](LehrerApp.Data/LiteDbContext.cs) (Schema-Version 3, `MigrateLessonPhases()` fasst alte Lessons verlustfrei in eine synthetisierte Phasen-Zeile zusammen) und [PlanningViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs). Design-Entscheidungen: - **Dauer ist die primäre Eingabe** je Phase (man plant in Zeitblöcken); die Uhrzeit je Phase wird im Editor nur zur Anzeige daraus abgeleitet (`LessonDialogViewModel.RecomputeTimes()`), sofern das optionale `StartTime`-Feld ("Beginn") gesetzt ist. Der Stundenplan (4.3) existiert noch nicht — bis dahin wird `StartTime` manuell gepflegt, könnte später automatisch befüllt werden. - **Kurzsymbol** (`LessonPhaseStep.Shorthand`) ist bewusst ein einzelnes Freitextfeld statt einer erzwungenen Von/Nach-Struktur (Nutzer-Feedback: manchmal ein Materialfluss-Pfeil wie "AB001->S", manchmal nur eine Sozialform ohne Pfeil wie "Plenum" oder "LDE"). Vorschläge kombinieren den in den Einstellungen gepflegten Kürzel-Katalog (neues Modell `ShorthandCode`, CRUD-Muster 1:1 von der Fach-Verwaltung übernommen; Startwerte `DefaultShorthandCodes` L/S/Tb/SH/AB/GA, solange der Katalog leer ist — kein DB-Seed) mit bereits in anderen Stunden der Gruppe frei getippten Werten (`PlanningTabViewModel.KnownShorthands`, analog zur Material-Autovervollständigung) — ein Kurzsymbol muss also nicht vorab im Katalog stehen, um beim nächsten Mal wieder vorgeschlagen zu werden. - **Tabellenlayout statt Karten** (Nutzer-Feedback: gestapelte Bordered-Cards pro Phase wirkten träge): der Verlaufsplan-Editor zeigt eine Kopfzeile mit Spaltentiteln und je Phase eine flache, einzeilige Zeile mit denselben Spaltenbreiten (Name/Dauer/Zeit/Tätigkeit/Material/Kurzsymbol/ Auf-Ab-Entfernen) statt mehrerer intern gestapelter Unterzeilen — nur die Tätigkeit wächst bei Bedarf mehrzeilig, alles andere bleibt einzeilig nebeneinander wie in der realen Vorlage. - Die Migration liest die alte Struktur bewusst über rohe `BsonDocument`s statt über die typisierte `Lessons`-Collection, da die alten Felder nach der Modelländerung beim typisierten Deserialisieren sonst bereits verworfen wären, bevor sie gelesen werden können. **Ideensammlung "Live-Unterrichtsmodus" (noch nicht geplant, nicht Teil von 4.2):** beim Besprechen des Verlaufsplan-Redesigns kamen weitergehende Wünsche auf, die bewusst zurückgestellt wurden, da sie eigene Datenmodelle (Live-Session-Zustand, Phasen-Verschiebung zwischen Stunden) brauchen: - Fortschrittslinie/Zeitanzeige während des Haltens der Stunde, die zeigt, wo man gerade stehen müsste. - "Fertig"/"Überziehen" je Phase anklickbar, nachfolgende Phasenzeiten passen sich automatisch an; Visualisierung, wie weit man dem Plan hinterherhängt. - Live-Sprung zwischen Wegen während des Haltens der Stunde (per Klick direkt in den alternativen Ablauf springen) — die Planungs-/Anzeigeseite (Kennzeichnen, gruppierte Darstellung) ist bereits umgesetzt, siehe Nachtrag unten; nur die Live-Interaktion beim Halten fehlt noch. - "Phase in nächste Stunde schieben"-Aktion, mit Hinweis-Symbol an der Folgestunde, dass dort noch offene Phasen/Arbeitsaufträge der Vorstunde einzuplanen sind. - Phasen-"Parkplatz": beim Planen Phasen ablegen können, ohne sie sofort einer Stunde zuzuordnen, und später flexibel in eine beliebige Stunde einfügen — Werkzeug, um Einheiten während des Schuljahres an die Realität anzupassen, wenn der Unterricht nicht wie geplant läuft. **Nachtrag — schreibgeschützte Verlaufsplan-Ansicht:** Um den Verlaufsplan-Editor überhaupt im Unterricht benutzen zu können, ohne versehentlich etwas zu verändern, gibt es jetzt `LessonViewerDialog` (erreichbar über "Anzeigen" im Stunden-Toolbar, sichtbar bei ausgewählter Stunde) — reine, größer geschriebene Anzeige des Verlaufsplans inkl. abgeleiteter Uhrzeit je Phase, ohne jede Bearbeitungs- oder Verlängern-/Verschieben-Funktion. Das ist bewusst nur ein Ausschnitt aus der "Fortschrittslinie"-Idee oben (rein statische Anzeige, keine Live-Aktualisierung nach Uhrzeit, kein "fertig"/"überziehen") — der volle Live-Modus bleibt Ideensammlung. **Nachtrag — Alternative Unterrichtsabläufe, zweite Iteration (echter Katalog statt Freitext):** Die erste Umsetzung (`LessonPhaseStep.AlternativePath: string?`, freier Bezeichner, Zuweisung über eine durchgehend sichtbare `AutoCompleteBox`-Spalte) wirkte im Alltag zu prominent für einen Fall, der selten vorkommt. Nutzer-Feedback: eine unauffällige Checkbox reicht für den Normalfall, die eigentliche Zuordnung gehört in einen separaten Dialog, und ein alternativer Ablauf sollte eine Erklärung tragen können (wann/wofür er gedacht ist, z.B. "bei Zeitmangel"). Redesign: - Neues Modell [`AlternativeLessonPath`](LehrerApp.Core/Models/Planning.cs) (Name + optionale `Description`) als eigener, wiederverwendbarer Katalog — `LessonPhaseStep.AlternativePathId: Guid?` referenziert einen Eintrag statt Freitext direkt zu speichern (`null` = Hauptweg). `IAlternativeLessonPathRepository`/`AlternativeLessonPathRepository`, eindeutig auf `Name`, kein eigenes Verwaltungs-UI in den Einstellungen — Einträge entstehen inline beim Zuweisen. - **Editor**: Die "Pfad"-Spalte ist jetzt eine einzelne `CheckBox` (`PhaseStepEditItem. HasAlternativePath`), deren `Content` bei Zuordnung den Namen des Ablaufs zeigt, `Foreground` deterministisch aus dem Namen eingefärbt (kleines, farbig unterstütztes Label statt breiter Eingabespalte). Ankreuzen öffnet `AlternativePathDialog` (Combobox über vorhandene Abläufe + Formular zum Anlegen eines neuen inkl. Beschreibung); Abwählen entfernt die Zuordnung direkt ohne Dialog. `LessonDialogViewModel.OnPickAlternativePath` (vom Code-Behind von `LessonDialog` selbst verdrahtet, nicht vom übergeordneten `PlanningTabView` — der Dialog braucht das `LessonDialog`-Fenster als Owner) kapselt diesen Ablauf. - **Viewer**: `LessonViewerViewModel` löst `AlternativePathId` über den Katalog auf und zeigt die hinterlegte Beschreibung unter der Gruppenüberschrift. - **Migration v3→v4** (`MigrateLessonAlternativePaths`): alte `AlternativePath`-Freitextwerte werden pro distinktem Namen zu einem `AlternativeLessonPath`-Katalogeintrag zusammengeführt (gleicher Name über mehrere Stunden hinweg → derselbe Eintrag, wiederverwendet) und referenziert. - Weiterhin bewusst **kein** Bedingungsfeld ("wenn an Stelle X nur noch weniger als Y Minuten") — das setzt Live-Zeiterfassung während des Unterrichtens voraus (siehe Live-Unterrichtsmodus oben) und war ausdrücklich als Idee, nicht als Anforderung formuliert. `AlternativeLessonPath. Description` deckt die Erklärung als Freitext ab; eine echte Bedingung bliebe für später. - Bewusst weiterhin **kein** Fork-Punkt-Modell: jede Gruppe berechnet ihre abgeleitete Uhrzeit im Viewer unabhängig ab `Lesson.StartTime`, nicht ab einer gemeinsamen Verzweigungsstelle im Hauptweg — deutlich einfacher und für den schnellen Überblick ausreichend. ### 4.3 Stundenplan - [x] **4.3.1** Neues Modell `TimetableSlot` (Gruppe, Wochentag, Stunde, Raum) + Repository — [Planning.cs](LehrerApp.Core/Models/Planning.cs), [TimetableSlotRepository](LehrerApp.Data/Repositories/AllRepositories.cs). Wiederkehrendes Muster (kein Datum) — für konkret gehaltene Stunden bleibt `Lesson` (4.2) zuständig. Pro Wochentag/Stunde höchstens eine Gruppe (eindeutiger Index + freundliche Fehlermeldung im Repository selbst, nicht erst über eine rohe `LiteException`): ein Lehrer kann nicht gleichzeitig an zwei Orten unterrichten. - [x] **4.3.2** Wochenstundenplan-Ansicht als Raster mit Farbcodierung je Gruppe — neuer Navigationspunkt "Unterrichtsplanung" (bisher `PlaceholderViewModel`) zeigt jetzt [TimetableView.axaml](LehrerApp.Desktop/Views/Planning/TimetableView.axaml). Mo–Fr × 1.–10. Stunde, Farbe deterministisch aus dem Gruppennamen (gleiches Hash-in-Palette-Muster wie bei den alternativen Unterrichtsabläufen in 4.2.2). - [x] **4.3.3** Bearbeitung per Klick im Raster — Klick auf eine leere Zelle öffnet `TimetableSlotDialog` zum Zuweisen (Gruppenauswahl + optionaler Raum), Klick auf eine belegte Zelle öffnet denselben Dialog zum Ändern/Entfernen. **Drag bewusst nicht umgesetzt:** Klick deckt die vollständige Bearbeitung (Zuweisen/Ändern/Entfernen) bereits ab: Drag wäre nur eine schnellere Geste für "Zuordnung an eine andere Zelle verschieben", kein zusätzlicher Funktionsumfang — bei Bedarf später ergänzbar. - [x] **4.3.4** Abgleich mit `LearningGroup.HoursPerWeek` — Seitenleiste "Abweichende Wochenstunden" listet jede Gruppe der aktuellen Schuljahres, deren eingetragene Slot-Anzahl nicht der hinterlegten Wochenstundenzahl entspricht. - [x] **4.3.5** Schulferien und Feiertage — gesetzliche Feiertage werden je Bundesland berechnet ([PublicHolidayService.cs](LehrerApp.Core/Services/PublicHolidayService.cs), Gauß'sche Osterformel + bundeslandspezifische Zusatzfeiertage, empirisch gegen bekannte Ostersonntage 2023–2027 verifiziert) statt gespeichert — anders als Schulferien sind sie algorithmisch herleitbar. Schulferien selbst sind **nicht** herleitbar (jährlich neu von den Bundesländern festgelegt) und werden deshalb manuell gepflegt (`SchoolHoliday`-Repository, CRUD in der Seitenleiste). Bundesland als persistente Einstellung ([SchoolCalendarSettingsService.cs](LehrerApp.Core/Services/SchoolCalendarSettingsService.cs)). "Aus der Planung ausnehmen" ist für dieses Kapitel als "nächste unterrichtsfreie Tage" sichtbar (kombinierte, sortierte Liste aus beiden Quellen) — die eigentliche Ausnahme aus generierten Stunden ist erst mit der (bewusst zurückgestellten) Serienerzeugung 4.2.5 relevant und verwendet dieselben zwei Datenquellen. **Nachtrag zu 4.3 (Nutzer-Feedback nach Erstumsetzung):** - **Ferien/Feiertage-Pflege verschoben:** Die Bundesland-Auswahl und das Schulferien-CRUD standen ursprünglich in der Seitenleiste des Stundenplans selbst — das wirkte dort deplatziert, da es eine einmalige Einstellung statt einer täglich genutzten Ansicht ist. Beides ist jetzt ein eigener Tab "Ferien & Feiertage" in den Einstellungen ([SettingsViewModel.cs](LehrerApp.Desktop/ViewModels/Settings/SettingsViewModel.cs), [SettingsView.axaml](LehrerApp.Desktop/Views/Settings/SettingsView.axaml)). Der Stundenplan selbst zeigt Bundesland und nächste unterrichtsfreie Tage nur noch lesend an ([TimetableViewModel.cs](LehrerApp.Desktop/ViewModels/Planning/TimetableViewModel.cs)). - **Badge "1"/"2" vor Ferien:** Die letzte bzw. vorletzte Stunde eines Wochentags vor den nächsten Schulferien wird im Bearbeiten-Raster mit einem kleinen Badge markiert — Erinnerung, rechtzeitig abzuschließen. Berechnet pro (Wochentag, Gruppe) statt pro einzelnem `TimetableSlot`: eine Doppelstunde besteht aus zwei Slots mit demselben Wochentag/derselben Gruppe und bekommt dadurch automatisch dasselbe Badge, ohne gesonderte Blockerkennung. Gesetzliche Feiertage werden beim Abzählen der verbleibenden Termine übersprungen. Bewusst nur an `SchoolHoliday` geknüpft, nicht an einzelne `PublicHoliday`-Tage — es geht um das Vorbereiten auf eine längere Unterbrechung, nicht um einen einzelnen freien Tag. - **"Heute" als neue Standardansicht:** Der Stundenplan öffnet jetzt auf einem nicht-editierenden Tab "Heute" (heutige Stunden mit Gruppe, Raum, Thema aus `Lesson.Topic` falls vorhanden, sowie ein Hinweis, wenn an dem Tag eine Klausur ansteht). Klick auf eine Stunde navigiert in die Lerngruppe (Tab "Planung"). Das bisherige Bearbeiten-Raster aus 4.3.2/4.3.3 ist über einen Button ("Stundenplan bearbeiten") als zweiter Tab weiterhin erreichbar. **Nachtrag zu 4.3, zweite Iteration (Wochenraster in der "Heute"-Ansicht):** Die Tagesliste allein beantwortete nicht "was steht in der Woche noch an" bzw. "was macht der parallele Kurs" — beides Fragen, die nur ein Blick über alle Gruppen hinweg beantwortet. Der Tab "Heute" zeigt deshalb jetzt zusätzlich ein schreibgeschütztes Wochenraster (Mo–Fr × 1.–10. Stunde, wie das Bearbeiten-Raster, aber ohne Klick-zum-Bearbeiten). Jede Kachel zeigt Fach (`Subject.ShortName`), Klasse, Raum und – falls für den Tag hinterlegt – das Thema der Stunde, dazu Symbole für: Ferien-Badge ("1"/"2", wie im Bearbeiten-Raster), Klausur an dem Tag (📝), letzte Stunde vor der nächsten Klausur dieser Gruppe (⏰) und ein geplantes Experiment (🧪). Die Tagesliste ist per `DockPanel` unten an die Seite angedockt, das Wochenraster füllt den verbleibenden Platz darüber ([TimetableViewModel.cs](LehrerApp.Desktop/ViewModels/Planning/TimetableViewModel.cs), [TimetableView.axaml](LehrerApp.Desktop/Views/Planning/TimetableView.axaml)). Klick auf eine Kachel navigiert wie in der Tagesliste zur Lerngruppe. - **"Letzte Stunde vor Klausur"** wird wie das Ferien-Badge pro (Wochentag, Gruppe) berechnet, aber am nächsten `Exam.Date` der jeweiligen Gruppe statt an einem gemeinsamen Ferientermin ausgerichtet — beide Badges teilen sich denselben Zähl-Helfer (`CountOccurrences`). - **"Experiment geplant"** hat kein eigenes Datenfeld — es ist eine Texterkennung über die bereits im Verlaufsplan-Editor (4.2.2) gepflegten `LessonPhaseStep`-Felder (Name/Aktivität/ Material enthält "Experiment", ohne Groß-/Kleinschreibung). Bewusst kein neues Modellfeld: die Information steckt in den meisten Fällen schon in der ohnehin gepflegten Phasenplanung. - Das Wochenraster zeigt bewusst nur die laufende Kalenderwoche ohne Vor-/Zurück-Navigation — für einen Blick auf zukünftige Wochen bleibt vorerst das Bearbeiten-Raster (zeigt das wiederkehrende Muster unabhängig vom Datum). **Nachtrag zu 4.3, dritte Iteration (Ferientage im Wochenraster ausgegraut statt eigener Liste):** Die Box "Nächste unterrichtsfreie Tage" wirkte neben dem neuen Wochenraster redundant — welche Tage frei sind, sieht man dort jetzt direkt an den betroffenen Stunden. Die Box (samt `UpcomingFreeDayItem`, `UpcomingFreeDays`, `BuildUpcomingFreeDays`, `BundeslandLabel`) wurde entfernt. Stattdessen werden Wochenkacheln, deren Datum in Schulferien fällt oder ein gesetzlicher Feiertag ist, grau eingefärbt (`WeekCellItem.IsHoliday`, Prüfung gegen `SchoolHoliday`-Zeitraum und die bereits für die Badges berechneten `PublicHoliday`-Daten) und zeigen statt der Klausur-/ Experiment-Symbole nur noch die Aufschrift "Ferien" — die Symbole wären an einem unterrichtsfreien Tag ohnehin nicht sinnvoll interpretierbar. **Nachtrag zu 4.3, vierte Iteration (Wochennavigation):** Schalter "‹"/"›" plus "Diese Woche" erlauben jetzt, im Wochenraster vor und zurück zu blättern (`TimetableViewModel.WeekOffset`, `PreviousWeekCommand`/`NextWeekCommand`/`CurrentWeekCommand`). Die Ferien-/Klausur-Nähe-Badges ("1"/"2" vor Ferien, ⏰ vor Klausur) waren bis dahin an "heute" verankert und pro (Wochentag, Gruppe) einmalig berechnet — das wäre beim Blättern falsch geworden (ein Badge hätte in jeder angezeigten Woche geklebt, nicht nur in der einen Woche, zu der es gehört). Für das Wochenraster berechnen `HolidayBadgeFor`/`IsLastBeforeExamFor` die Badges deshalb jetzt je Zelle am dort gezeigten Datum statt an "heute" — das Bearbeiten-Raster (zeigt ohnehin nur das wiederkehrende Muster ohne Datum) behält die alte, "heute"-verankerte Berechnung. Beim erneuten Navigieren in den Stundenplan (Sidebar-Klick) springt die Ansicht wieder auf die laufende Woche zurück. ### 4.4 Wochen-/Tagesansicht - [x] **4.4.1** Kalenderansicht über alle Gruppen: Woche und Tag — siehe Nachtrag zu 4.3 ("Heute"-Tab: Tagesliste unten angedockt, gruppenübergreifendes Wochenraster darüber, inkl. Vor-/Zurück-Navigation zwischen Kalenderwochen seit der vierten Iteration). **Nicht enthalten:** ein eigenständiger Kalendermonat-Überblick — bei Bedarf später ergänzbar. - [x] **4.4.2** Sprung von einer Stunde direkt in die Lerngruppe — siehe Nachtrag zu 4.3 ("Heute"-Tab, Klick navigiert zur Planung der Gruppe statt direkt in die Mitarbeitserfassung, da das für den Vorbereitungs-Kontext des Tages passender ist). - [ ] **4.4.3** Anzeige anstehender Klausurtermine und Abgabefristen im Kalender. *(Heutige Klausuren bereits im "Heute"-Tab sichtbar — mehrtägiger Vorausblick fehlt noch.)* ### 4.5 Vernetzung Stundenplan ↔ Unterrichtsplanung (zurückgestellt) Nutzer-Feedback nach der 4.3-Iterationen: Stundenplan (4.3, wiederkehrendes Muster) und Unterrichtsplanung (4.1/4.2, `Unit`/`Lesson` je Gruppe) laufen bisher zu getrennt nebeneinander. Ausdrücklich als Idee für später festgehalten, **nicht** jetzt umsetzen: - [ ] **4.5.1** Terminvorschlag beim Anlegen einer `Lesson`: Tag/Stunde anhand des Stundenplans vorschlagen, an dem die betroffene Gruppe laut `TimetableSlot` tatsächlich Unterricht hat, statt Datum/Stunde komplett frei einzutragen. - [ ] **4.5.2** Vom Stundenplan (Wochenraster oder Bearbeiten-Raster) direkt in einen "Viewer" der zugehörigen `Lesson` springen können — und von dort auch eine neue `Lesson` anlegen können. **Offene Frage, vor Umsetzung zu klären:** `Lesson` hängt an einer übergeordneten `Unit` (4.1) — beim Anlegen direkt aus dem Stundenplan heraus ist unklar, welcher `Unit` die neue Lesson zugeordnet werden soll (aktuellste offene Einheit der Gruppe? Rückfrage an die Lehrkraft?). Muss überdacht werden, bevor das gebaut wird. - [ ] **4.5.3** Aus diesem Lesson-Viewer heraus weiter verzweigen können: in die Zeugnisnote/ Bewertung der Gruppe, und in die Schnelldialoge für Mitarbeit sowie Anwesenheit/Hausaufgaben. - [ ] **4.5.4** Badges am Stundenplan/Lesson-Viewer, die anzeigen, ob eine Stunde bereits "kontrolliert" ist — u.a. ob in der vorherigen Stunde Hausaufgaben erteilt wurden und ob diese noch nicht kontrolliert sind. Muss sich pro Fall abschalten lassen: manchmal wird eine Hausaufgabe bewusst nicht kontrolliert, ohne dass bis Schuljahresende ständig daran erinnert werden soll. - [ ] **4.5.5** Stunden aus dieser Ansicht heraus verschieben können, wenn kurzfristig etwas dazwischenkommt. - [ ] **4.5.6** Bei Doppelstunden (90-Minuten-Planung laut Verlaufsplan, 4.2.2) den Inhalt sinnvoll auf die beiden Kacheln/Perioden aufteilen, damit z.B. gezielt nur die zweite Stunde eines Blocks verschoben werden kann, ohne den ganzen Block anzufassen. --- ## 5. Schülerdokumentation **Wichtige Abweichung von der ursprünglichen Planung (5.2):** Vor der Umsetzung zeigte sich, dass 5.2 wie ursprünglich beschrieben eine zweite, parallele Fehlzeiten-Erfassung neben dem bereits bestehenden Anwesenheits-Tracking aus Kapitel 3 (`ParticipationEntry.Attendance`, `AttendanceStatus`) ergeben hätte — zwei potenziell widersprüchliche Datenquellen für dieselbe Frage ("war der Schüler da?"). Auf Rückfrage entschieden: 5.2 wird als **Auswertung** der bestehenden Anwesenheitsdaten umgesetzt, keine zweite Erfassung. 5.2.1 und 5.2.4 existierten dadurch faktisch schon (Quick-Input-Dialog bzw. "Offene Entschuldigungen" im Dashboard). ### 5.1 Einträge erfassen - [x] **5.1.1** Dialog "Dokumentation hinzufügen" mit Typwahl (`Conversation`, `Incident`, `SupportPlan`, `Absence`) und typabhängigen Feldern — [DocumentationDialog.axaml](LehrerApp.Desktop/Views/Students/DocumentationDialog.axaml), [DocumentationViewModels.cs](LehrerApp.Desktop/ViewModels/Students/DocumentationViewModels.cs). Deutsche Anzeige über `DocumentationTypeDisplay`/`SupportStatusDisplay`, analog zum `NiveauDisplay`-Muster. Feldbezogene Validierung wie in 13.2.4. - [x] **5.1.2** Teilnehmerliste (`Participants`) bei Gesprächen — Chip-Liste mit Hinzufügen/ Entfernen im Dialog, nur sichtbar bei Typ "Gespräch". - [x] **5.1.3** Kennzeichen "vertraulich" — vertrauliche Einträge zeigen in der Übersicht nur Datum/Typ/Schloss-Symbol, Titel und Inhalt erst nach Klick auf "Anzeigen" (`DocumentationItem.IsRevealed`, session-lokal, keine erneute Passwortabfrage — dafür gibt es bereits die App-Sperre aus 13.3.5). - [x] **5.1.4** Bearbeiten/Löschen mit Rückfrage (neuer generischer `ConfirmDialog`); Löschen markiert nur `IsDeleted`/`DeletedAt` statt hart zu entfernen — `IDocumentationRepository.Delete`. Ein echtes `HardDelete` existiert separat, nur für die Löschfristen-Bereinigung in 5.4.2. - [x] **5.1.5** Zwei weitere Dokumentationstypen ergänzt (Nutzer-Feedback nach Erstauslieferung): - **Elternanruf** (`DocumentationType.ParentCall`): Gesprächspunkte werden im normalen Dialog vorab geplant (`ParentCallData.Points`); ein separater [ParentCallSessionDialog](LehrerApp.Desktop/Views/Students/ParentCallSessionDialog.axaml) ("Gespräch begleiten", Button an jedem Elternanruf-Eintrag) hakt sie während des Telefonats ab und hält Eindrücke/Ergänzungen als Protokoll fest (`ParentCallData.Impressions`, `IsConducted`, `ConductedDate`). Punkte mit unverändertem Text behalten beim erneuten Bearbeiten ihren Abhak-Status (Zuordnung über `ParentCallPoint.Id`, sonst über Textabgleich — ein umbenannter Punkt gilt als neu und startet offen; bewusste Vereinfachung). - **Elternbrief** (`DocumentationType.ParentLetter`): Entwurf/Inhalt, Absendedatum, Rückmeldung erhalten (ja/nein), Rückmeldedatum und -notiz (`ParentLetterData`). - **Datei-Anhänge** (an allen Dokumentationstypen, nicht nur Elternbrief): über LiteDBs eingebauten Dateispeicher (`ILiteStorage`, per Skript verifiziert — funktioniert zuverlässig, im Gegensatz zum defekten `Rebuild`-mit-Passwort aus 13.3.4) — [LiteAttachmentStorage.cs](LehrerApp.Data/LiteAttachmentStorage.cs). Größe strikt auf 10 MB je Datei begrenzt (`IAttachmentStorage.MaxSizeBytes`), damit die Datenbankdatei (und jedes Backup, 13.3.1) nicht durch Anhänge aufgebläht wird. Neu hochgeladene, aber nie gespeicherte Anhänge werden beim Abbrechen des Dialogs wieder gelöscht, damit keine verwaisten Blobs zurückbleiben; beim endgültigen Löschen eines Eintrags (5.4.2) werden auch dessen Anhänge mit entfernt. **Randnotiz:** Beim Schreiben der Tests für den Datei-Speicher fiel eine bereits vorher latent vorhandene Testinfrastruktur-Schwäche auf: `LiteDbContext` nutzt LiteDBs statischen, geteilten `BsonMapper.Global` für die Index-Auflösung — bei paralleler Testausführung über mehrere Testklassen hinweg (xUnit-Standard) führte das sporadisch zu "Member X not found on BsonMapper"-Fehlern in völlig unbeteiligten Tests. Behoben durch `[assembly: CollectionBehavior(DisableTestParallelization = true)]` in [AssemblyInfo.cs](LehrerApp.Data.Tests/AssemblyInfo.cs) — Data-Tests laufen jetzt sequenziell (bei elementaren In-Memory-Tests kein spürbarer Zeitverlust). - [x] **5.1.6** Labels zur Nachverfolgung (Nutzer-Feedback): freie Text-Labels an jedem Dokumentationseintrag (`Documentation.Tags`), mit AutoCompleteBox-Vorschlägen (`DocumentationTagDisplay.Suggestions`: Kritisch, Nacharbeiten, Mit JGL abklären, Erkundigung einholen, Elterngespräch nötig, Mit Schulleitung abklären, Klassenkonferenz, Frist beachten, Beobachten, Erledigt — eigene Labels bleiben trotzdem frei möglich). Farbcodierung nach Dringlichkeit statt nach Label-Identität (`DocumentationTagDisplay.ColorHex`): rot = Priorität, orange = Handlungsbedarf, blau = im Blick behalten, grün = abgeschlossen, grau = freies Label. Als farbige Chips in der Dokumentationsliste sichtbar (`DocumentationItem.TagChips`). Dabei außerdem behoben: die Farblegende der Notenentwicklung-Balken (2.5) fehlte sichtbar im UI (nur im Tooltip) — wirkte dadurch wie zufällige/abwechselnde Farbgebung statt wie das eigentliche Signal "Auffälligkeit". Jetzt als kleine Legende über dem Diagramm sichtbar, siehe [StudentDetailView.axaml](LehrerApp.Desktop/Views/Students/StudentDetailView.axaml). ### 5.2 Fehlzeiten (als Auswertung des bestehenden Anwesenheits-Trackings, siehe oben) - [x] **5.2.1** Schnelle Abwesenheitserfassung je Stunde — bereits vorhanden über `AttendanceHomeworkQuickInputDialog` und den Mitarbeits-Assistenten (Kapitel 3). - [x] **5.2.2** Fehlzeitenbilanz je Schüler und laufendes Schuljahr — [AttendanceBalanceService.cs](LehrerApp.Core/Services/AttendanceBalanceService.cs), reine Auswertungslogik (kontrollierte Stunden, entschuldigt/unentschuldigt/offen, Fehlquote in %), angezeigt im Schülerdetail-Tab "Dokumentation". Schulisch veranlasste Abwesenheit (`OtherSchoolEvent`) zählt bewusst nicht als Fehlzeit des Schülers. - [x] **5.2.3** Schwellenwert-Warnung (> 20 %) — `AttendanceBalance.ExceedsThreshold` im Schülerdetail sowie eine neue "Fehlzeiten-Warnung"-Karte im Dashboard (alle Schüler über dem Schwellenwert, sortiert nach Fehlquote). - [x] **5.2.4** Nachträgliches Entschuldigen mit Frist-Hinweis — bereits vorhanden über die "Offene Entschuldigungen"-Karte im Dashboard (21-Tage-Grenze, aus Kapitel 3). ### 5.3 Förderpläne - [x] **5.3.1** Förderplan anlegen (Maßnahmenliste, Überprüfungsdatum, Status) — über den 5.1-Dialog mit Typ "Förderplan" (`SupportData`: `Measures`, `ReviewDate`, `Status`). - [x] **5.3.2** Wiedervorlage: fällige Überprüfungen (Status Aktiv, Überprüfungsdatum in den nächsten 14 Tagen oder überfällig) erscheinen als eigene Dashboard-Karte "Förderplan-Wiedervorlage", überfällige rot hervorgehoben. - [x] **5.3.3** Verlaufsdokumentation — die Dokumentationsliste im Schülerdetail zeigt alle Förderplan-Einträge chronologisch; bewusst keine zusätzliche Gruppierung über eine Plan-ID, da das bestehende flache `Documentation`-Modell dafür ausreicht. ### 5.4 Datenschutz - [x] **5.4.1** Vertrauliche Einträge nur nach zusätzlicher Bestätigung anzeigen — siehe 5.1.3 (zusammen umgesetzt, da es sich um dieselbe UI-Stelle handelt). - [x] **5.4.2** Löschfristen — neuer Tab "Datenschutz" in den Einstellungen: konfigurierbare Aufbewahrungsfrist in Jahren ([PrivacySettingsService.cs](LehrerApp.Core/Services/PrivacySettingsService.cs), Standard 3 Jahre), Liste abgelaufener Einträge zur manuellen Prüfung mit "Endgültig löschen" (`IDocumentationRepository.HardDelete`). Löscht nie automatisch. - [x] **5.4.3** Export einzelner Schülerdaten für Auskunftsersuchen (Art. 15 DSGVO) — [PersonalDataExportService.cs](LehrerApp.Core/Services/PersonalDataExportService.cs), JSON-Export mit Stammdaten, Gruppenzuordnungen, Noten, Klausurergebnissen, Mitarbeit und Dokumentation (auch als vertraulich markierte Einträge — das Vertraulich-Kennzeichen blendet nur die laufende Ansicht aus, ist aber keine pauschale rechtliche Ausnahme vom Auskunftsanspruch der betroffenen Person selbst). **Hinweis:** ob im Einzelfall eine Ausnahme greift (z.B. schutzwürdige Belange Dritter nach Landes-Schulrecht), muss die verantwortliche Lehrkraft/Schule selbst prüfen — das ist keine Rechtsberatung. --- ## 6. Arbeitszeit & Aufgaben Modelle `WorkTask` und `TimeEntry` existieren, Repositories ebenfalls. Navigationspunkt "Arbeitszeit" ist ein `PlaceholderViewModel`. ### 6.1 Aufgabenverwaltung - [ ] **6.1.1** Aufgabenliste mit Filter nach Status, Kategorie, Gruppe und Fälligkeit. - [ ] **6.1.2** Aufgabe anlegen/bearbeiten: Titel, Kategorie, Gruppe, Fälligkeit, geschätzte Dauer, Notizen. - [ ] **6.1.3** Status per Klick wechseln (`Open → InProgress → Done`), erledigte ausblenden. - [ ] **6.1.4** Wiederkehrende Aufgaben (wöchentlich/monatlich). - [ ] **6.1.5** Automatische Aufgabe "Klausur korrigieren" beim Statuswechsel einer Klausur auf `Conducted` (Anbindung an 1.1.3). ### 6.2 Zeiterfassung - [ ] **6.2.1** Timer starten/stoppen mit Zuordnung zu Aufgabe oder Kategorie. - [ ] **6.2.2** Manuelle Nacherfassung eines Zeitblocks (Datum, Von–Bis oder Dauer). - [ ] **6.2.3** Wochenübersicht der erfassten Zeit, Summen je Kategorie. - [ ] **6.2.4** Schätzung vs. tatsächliche Dauer je Aufgabe vergleichen. ### 6.3 Auswertung - [ ] **6.3.1** Monats-/Jahresauswertung nach Kategorie und Gruppe (Diagramm + Tabelle). - [ ] **6.3.2** Abgleich mit der Pflichtstundenzahl (in Einstellungen hinterlegt). - [ ] **6.3.3** Export der Arbeitszeitauswertung (siehe 11.2). --- ## 7. Schüler & Gruppen — Verfeinerungen Grundfunktionen sind vorhanden ([StudentViewModels.cs](LehrerApp.Desktop/ViewModels/Students/StudentViewModels.cs), [GroupViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs)). Niveau-Zuordnung je Schüler (E/G/Förder, `GroupMembership.Niveau`) ist bereits umgesetzt, siehe Hinweis in Kapitel 1 — betrifft auch Kurse, nicht nur Klassen. ### 7.1 Schüler - [ ] **7.1.1** Schüler löschen / auf inaktiv setzen inkl. Hinweis auf verknüpfte Daten. - [ ] **7.1.2** Suche in der Schülerliste (Name, Gruppe) mit Sofortfilter. - [ ] **7.1.3** Foto/Avatar je Schüler (optional, lokal gespeichert) für schnellere Zuordnung. - [ ] **7.1.4** Serienbrieffelder aus Kontaktdaten (Anrede, Adresse) für Elternbriefe. - [ ] **7.1.5** Sitzplan je Gruppe (Raster mit Drag & Drop), Sprung von Sitzplatz zur Bewertung. ### 7.2 Gruppen - [x] **7.2.1** Gruppe bearbeiten und löschen — bereits vorhanden (`EditGroupCommand`/`DeleteGroupCommand`/ `ToggleArchiveCommand` in `GroupListViewModel`), nicht Teil der aktuellen Klausuren-Arbeit, beim Review aber bestätigt. Die Löschung läuft transaktional und entfernt alle fachlich abhängigen Datensätze (inkl. Zeugnisnoten, gruppenspezifischem Notenschema und Mitarbeitsabschnitten). Dokumentation, Aufgaben und Zeiteinträge bleiben als historische Nachweise erhalten; ihr `GroupId` wird auf `null` gesetzt. - [ ] **7.2.2** Gruppe ins neue Schuljahr übernehmen: Kopie mit gleicher Schülerschaft, neues `SchoolYear`, neue `GroupMembership`-Einträge. - [ ] **7.2.3** Schüler aus einer Gruppe entfernen (`GroupMembership.LeftAt` setzen statt löschen). - [ ] **7.2.4** Umgang mit `MembershipPeriod.Custom` in allen Auswertungen prüfen (Schüler zählt nur im belegten Zeitraum). - [ ] **7.2.5** Archivansicht abgeschlossener Schuljahre (schreibgeschützt). ### 7.3 Import - [ ] **7.3.1** CSV-Import von Schülerlisten mit Spaltenzuordnung im Dialog. - [ ] **7.3.2** Dublettenerkennung beim Import (Name + Geburtsdatum), Zusammenführen anbieten. - [ ] **7.3.3** Import-Vorschau mit Fehlerliste vor dem endgültigen Übernehmen. --- ## 8. Kompetenzen Katalogverwaltung und JSON-Import existieren in [SettingsViewModel.cs](LehrerApp.Desktop/ViewModels/Settings/SettingsViewModel.cs), Format dokumentiert in [Kompetenzkatalog-KI-Prompt.md](docs/Kompetenzkatalog-KI-Prompt.md). ### 8.1 Katalogverwaltung - [ ] **8.1.1** Kompetenzen innerhalb eines Bereichs umsortieren (`SortOrder` bearbeitbar machen). - [ ] **8.1.2** Katalog exportieren (JSON) — Gegenstück zum vorhandenen Import. - [ ] **8.1.3** Katalog von einer Jahrgangsstufe in eine andere kopieren. - [ ] **8.1.4** Import-Konflikte behandeln: Merge statt Ersetzen anbieten. ### 8.2 Verwendung im Unterricht - [ ] **8.2.1** Kompetenzen einer Unterrichtseinheit zuordnen (siehe 4.1.3). - [x] **8.2.2** Kompetenzen einzelnen Klausuraufgaben zuordnen — umgesetzt mit 1.2.4. - [ ] **8.2.3** Abdeckungsübersicht: welche Kompetenzen wurden im Schuljahr behandelt/geprüft? ### 8.3 Kompetenzorientierte Auswertung - [ ] **8.3.1** Kompetenzprofil je Schüler aus Klausuraufgaben-Ergebnissen berechnen. - [ ] **8.3.2** Gruppenübersicht: durchschnittlicher Erfüllungsgrad je Kompetenz, Identifikation von Wiederholungsbedarf. - [ ] **8.3.3** Kompetenzbericht je Schüler als Ausdruck/Export. --- ## 9. Dashboard Basis vorhanden in [DashboardViewModel.cs](LehrerApp.Desktop/ViewModels/DashboardViewModel.cs). Kleiner Monatskalender ist bereits umgesetzt (Farbcodierung Unterricht/Klausur, Hervorhebung "eigene Klasse" über `LearningGroup.IsOwnClass`, feste Kartenbreite/-position). - [ ] **9.1** Heutige Stunden mit Uhrzeit und Raum anzeigen (Abhängigkeit zu 4.3). - [ ] **9.2** Direkter Absprung von einer Stunde in Mitarbeitserfassung bzw. Stundenplanung. - [ ] **9.3** Kachel "Anstehende Termine": Klausuren, Förderplan-Überprüfungen, Abgabefristen. - [ ] **9.4** Kachel "Offene Korrekturen" mit Fortschritt (x von y Klausuren bewertet). - [ ] **9.5** Kachel "Auffälligkeiten": Fehlzeitenüberschreitungen, Notenabfall, Versetzungsgefährdung. - [ ] **9.6** Dashboard-Kacheln ein-/ausblendbar und in der Reihenfolge konfigurierbar. - [ ] **9.7** Automatische Aktualisierung beim Zurücknavigieren (aktuell nur manueller Refresh). - [ ] **9.8** Kalender-Detailansicht: Tag im Monatskalender anklickbar/auswählbar, zeigt in einem angrenzenden Feld die Termine dieses Tages (Unterricht, Klausuren, perspektivisch Konferenzen/Sondertermine) mit Details und Sprungmöglichkeit in die jeweilige Ansicht. Sinnvoll erst, wenn weitere Terminarten existieren — Abhängigkeit zu Kapitel 4 (Unterrichtsplanung/Termine) sowie ggf. einem neuen Termine-Modell. --- ## 10. Sync & Server Grundgerüst existiert in [LehrerApp.Sync](LehrerApp.Sync/) und [LehrerApp.Api](LehrerApp.Api/), ist aber nur aktiv, wenn eine Server-URL konfiguriert ist. ### 10.1 Client - [ ] **10.1.1** Sync-Einrichtung in den Einstellungen: Server-URL, Login, Token speichern. - [ ] **10.1.2** Verbindungstest mit klarer Fehlermeldung (nicht erreichbar / Token ungültig). - [ ] **10.1.3** Konfliktanzeige in der UI — was `ConflictResolver` entscheidet, muss sichtbar sein. - [ ] **10.1.4** Manuelles Auslösen einer vollständigen Synchronisation. - [ ] **10.1.5** Statusanzeige erweitern: letzter Sync, Anzahl wartender Events, Fehlerzustand. - [ ] **10.1.6** Lokale Schreibvorgänge atomar an die Outbox (`EventQueue`) anbinden — aktuell ist das Sync-Grundgerüst registriert, die Repositories erzeugen aber noch keine Sync-Ereignisse. ### 10.2 Server - [ ] **10.2.1** Benutzerverwaltung/Registrierung prüfen und absichern ([Endpoints.cs](LehrerApp.Api/Endpoints/Endpoints.cs)). - [ ] **10.2.2** Rate Limiting und Request-Größenbegrenzung. - [ ] **10.2.3** Serverseitiges Backup der Event-/Snapshot-Dateien. - [ ] **10.2.4** Docker-Setup in [docker/](docker/) verifizieren und dokumentieren. ### 10.3 Verschlüsselung - [ ] **10.3.1** Schlüsselübertragung auf ein zweites Gerät (QR-Code oder Passphrase). - [ ] **10.3.2** Warnung und Wiederherstellungspfad bei verlorenem Schlüssel. - [ ] **10.3.3** Prüfen, welche Daten unverschlüsselt über `PlainEventStore` laufen — personenbezogene Daten dürfen das nicht. --- ## 11. Export, Druck & Berichte Bisher nicht vorhanden — komplett neu. - [ ] **11.1** Basisinfrastruktur: Export-Service mit Formatwahl und Speicherdialog. - [ ] **11.2** CSV-Export für Notenlisten, Klausurauswertung, Arbeitszeit, Fehlzeiten. - [ ] **11.3** PDF-Erzeugung (Bibliothek auswählen — z.B. QuestPDF) mit einheitlichem Layout. - [ ] **11.4** Druckvorlagen: Notenliste, Klausur-Notenspiegel, Sitzplan, Kompetenzbericht, Schülerdokumentation. - [ ] **11.5** Serienbrief/Elternbrief aus Kontaktdaten (Abhängigkeit zu 7.1.4). - [ ] **11.6** Vollständiger Datenexport eines Schuljahres (Archivierung). --- ## 12. Einstellungen & Stammdaten Fächer- und Kompetenzverwaltung existiert bereits in [SettingsView.axaml](LehrerApp.Desktop/Views/Settings/SettingsView.axaml), ebenso (neu, im Zuge von 4.2.2) der Tab "Kürzel-Katalog" für die Von/Nach-Kürzel des Stundenverlaufsplans. - [ ] **12.1** Lehrerprofil: Name, Kürzel, Schule, Pflichtstundenzahl. - [ ] **12.2** Schuljahr-Einstellungen: Beginn/Ende, Halbjahresgrenze, Ferien (`SchoolYearService` erweitern). - [ ] **12.3** Standard-Notenschlüssel und Standard-Gewichtungsschema hinterlegen (2.3.3, 1.3.2). - [ ] **12.4** Darstellung: Hell/Dunkel-Modus, Schriftgröße. - [ ] **12.5** Speicherort der Datenbank anzeigen und ändern. - [ ] **12.6** Backup-Verwaltung (siehe 13.3) in den Einstellungen zugänglich machen. --- ## 13. Technische Basis ### 13.1 Tests - [x] **13.1.1** Testprojekt `LehrerApp.Tests` angelegt (referenziert `LehrerApp.Core`, analog zu [LehrerApp.Data.Tests](LehrerApp.Data.Tests/LehrerApp.Data.Tests.csproj) für die Datenschicht). Noch ohne Testfälle — folgt mit 13.1.2ff. - [x] **13.1.2** Unit-Tests für `GradingService` (Notenschlüssel-Grenzfälle, gewichteter Schnitt) — 41 Tests in [GradingServiceTests.cs](LehrerApp.Tests/GradingServiceTests.cs), deckt `CalculateGrade`, `ValidateGradingKey`, `WeightedAverage`, `RoundToGrade`, `ParticipationGrade`, `ValidateGradingScheme` und `CalculateReportGrade` ab. - [x] **13.1.3** Unit-Tests für `SchoolYearService` (Jahreswechsel, Schuljahresgrenze) — 13 Tests in [SchoolYearServiceTests.cs](LehrerApp.Tests/SchoolYearServiceTests.cs). Dafür `CurrentSchoolYear`/`RecentSchoolYears` um ein optionales `today`-Parameter erweitert (Default weiterhin `DateTime.Today`), um den 1.-August-Wechsel deterministisch zu testen, ohne bestehende Aufrufer zu ändern. - [x] **13.1.4** Repository-Tests gegen eine In-Memory-LiteDB — `LiteDbContext` um einen `Stream`-Konstruktor erweitert (`new LiteDatabase(stream)`, kein Datei-I/O nötig), 19 Tests in [RepositoryTests.cs](LehrerApp.Data.Tests/RepositoryTests.cs): u.a. Kaskadenlöschung bei `GroupRepository.Delete`/`ExamRepository.Delete`/ `ParticipationSessionRepository.Delete`, Eindeutigkeitsprüfungen (`GroupMembership`, `ParticipationEntry`), Fach-Validierung (Trimmen, Duplikate, Löschsperre bei Verwendung), `GradingScheme`-Auflösung gruppenspezifisch vs. Voreinstellung. - [x] **13.1.5** Tests für die Mitarbeits-Aggregation (3.2) und Zeugnisnotenberechnung (2.4) — neues Testprojekt `LehrerApp.Desktop.Tests` (referenziert `LehrerApp.Desktop`, damit ViewModel-Logik ohne echtes UI getestet werden kann), gemeinsame Fakes in [Fakes.cs](LehrerApp.Desktop.Tests/Fakes.cs). 9 Tests für [ParticipationGradeAggregationTests.cs](LehrerApp.Desktop.Tests/ParticipationGradeAggregationTests.cs) (gewichtetes Mittel, "nicht bewertet" ≠ schlechte Note, Trend, Aspektgewicht 0, Halbjahresfilter, Übernehmen-Update-statt-Duplikat) und 9 für [ReportGradeCalculationTests.cs](LehrerApp.Desktop.Tests/ReportGradeCalculationTests.cs) (Schema-Auflösung gruppenspezifisch/Voreinstellung/Fallback, Pflicht-Begründung beim Übersteuern, Festschreiben friert den Stand ein, Rundungsregel). - [x] **13.1.6** Tests für `ConflictResolver` — neues Testprojekt `LehrerApp.Sync.Tests`, 10 Tests in [ConflictResolverTests.cs](LehrerApp.Sync.Tests/ConflictResolverTests.cs) (Desktop schlägt Companion immer, Gleichstand nach Zeitstempel, kein Konflikt bei unterschiedlicher Entität/gleichem Gerät). Dabei zwei echte Fehler gefunden und behoben: (1) `SyncEvent` hatte keine `[BsonId]`-Markierung auf `EventId` — LiteDB vergab dadurch einen eigenen, unabhängigen `_id`, wodurch `EventQueue.Acknowledge()` nie etwas aus der Queue löschte (verlorene Konflikte blieben für immer offen). (2) `ConflictResolver` verglich `local.Timestamp` (aus LiteDB, `Kind=Local` mit verschobenen Ticks) direkt mit `remote.Timestamp` (`Kind=Utc`) — `DateTime`-Vergleiche ignorieren `Kind` und vergleichen nur rohe Ticks, wodurch die Gleichstand-Regel außerhalb von UTC+0 falsch entschied. Fix: `.ToUniversalTime()` auf beiden Seiten vor dem Vergleich. ### 13.2 Fehlerbehandlung & Logging - [x] **13.2.1** Zentrale Exception-Behandlung mit verständlicher Fehlermeldung statt Absturz — [GlobalExceptionHandler.cs](LehrerApp.Desktop/Services/GlobalExceptionHandler.cs). `Dispatcher.UIThread.UnhandledException` protokolliert Fehler aus Befehlen/Ereignis-Handlern. Nur als wiederherstellbar eingestufte I/O-, Netzwerk-, Timeout- und Abbruchfehler werden mit `Handled = true` behandelt und als Toast angezeigt. Unbekannte Programmier-/Zustandsfehler dürfen die Anwendung kontrolliert beenden, statt mit möglicherweise beschädigtem Zustand weiterzulaufen. `AppDomain.UnhandledException` und `TaskScheduler.UnobservedTaskException` sind Sicherheitsnetze für Fehler außerhalb des UI-Threads — dort kann ein bereits "IsTerminating"-Fehler nicht mehr verhindert werden, wird aber vollständig protokolliert. - [x] **13.2.2** Logging in Datei im App-Datenverzeichnis, mit Rotation — [AppLogger.cs](LehrerApp.Core/Services/AppLogger.cs), tägliche Datei unter `/LehrerApp/logs/`, Dateien älter als 14 Tage werden beim Start gelöscht. 6 Tests in [AppLoggerTests.cs](LehrerApp.Tests/AppLoggerTests.cs). - [x] **13.2.3** Einheitliche Benachrichtigungen (Toast/Snackbar) für Erfolg und Fehler — [NotificationService.cs](LehrerApp.Desktop/Services/NotificationService.cs), Overlay unten rechts in [MainWindow.axaml](LehrerApp.Desktop/Views/MainWindow.axaml), blendet sich nach 3 s (Erfolg) bzw. 6 s (Fehler) automatisch aus. Aktuell an den globalen Exception-Handler angebunden; bestehende Dialoge zeigen Erfolg/Fehler weiterhin über ihre eigenen Statuszeilen (`StatusMessage`/`ValidationMessage`) — eine Umstellung dieser bestehenden Stellen auf Toasts wäre ein eigener, größerer Umbau über viele Dateien hinweg und ist bewusst nicht Teil dieser Aufgabe. - [x] **13.2.4** Validierungsmeldungen einheitlich an den Eingabefeldern statt in Sammel-Labels. Alle Dialoge mit Formularfeldern umgestellt: `AddStudentDialog`, `ContactEditDialog`, `AddGroupDialog`, `StudentGradesDialog` (`GradeEditItem`), `CollectiveGradeDialog`, `ExamDialog`, `AddSessionDialog`, `ParticipationWizardDialog` (Abschnitt-Formular), Einstellungen (Fach anlegen, Notenschlüssel-Vorlage anlegen, Notenschlüssel-Editor). Muster: pro Feld eine `{Feld}Error`-Property, `Save()` leert alle Fehler-Properties am Anfang, sammelt alle Verstöße über eine lokale `valid`-Variable statt beim ersten Fehler zurückzukehren, und bricht erst am Ende mit `if (!valid) return;` ab — so werden mehrere Fehler gleichzeitig angezeigt. Bewusst als Sammel-Meldung belassen, wo die Meldung sich auf eine Kombination mehrerer Felder bezieht statt auf ein einzelnes Feld: `GradingKeyValidation` (Notenschlüssel-Tabelle als Ganzes), `GradingSchemeEditItem.ValidationMessage` (Summe der drei Prozent-Felder muss 100 ergeben), `ReportGradeRow.ValidationMessage` (Override-Wert + Begründung gehören zusammen), `CatalogValidation` (Kompetenzkatalog-Panel: Fachauswahl, Bereichsname und JSON-Import teilen sich einen Status-Bereich), `AddStudentToGroupDialogViewModel.ValidationMessage` (einzige Prüfung "Schüler ausgewählt?", kein Textfeld zum Andocken vorhanden). ### 13.3 Datensicherheit - [x] **13.3.1** Automatisches lokales Backup der LiteDB beim Start (rollierend, letzte 10) — [BackupService.cs](LehrerApp.Core/Services/BackupService.cs). Reine Dateikopie nach `/LehrerApp/backups/`, läuft in `AppBootstrapper.BuildServices()` **vor** dem Öffnen der Datenbank (unabhängig von Verschlüsselung, kein LiteDB-Handle nötig). Behält standardmäßig die letzten 10 Backups, ältere werden entfernt. 6 Tests in [BackupServiceTests.cs](LehrerApp.Tests/BackupServiceTests.cs). - [x] **13.3.2** Wiederherstellung aus einem Backup über die Einstellungen — neuer Tab "Sicherheit" in [SettingsView.axaml](LehrerApp.Desktop/Views/Settings/SettingsView.axaml) listet vorhandene Backups mit Zeitstempel/Größe, "Wiederherstellen" fragt über einen neuen generischen [ConfirmDialog](LehrerApp.Desktop/Views/Shared/ConfirmDialog.axaml) nach, kopiert das Backup über die aktive Datenbankdatei und startet die App danach automatisch neu (`AppBootstrapper.RestartApplication()`) — ein laufender LiteDB-Verbindung kann nicht sicher "heiß" auf eine andere Datei umgehängt werden. - [x] **13.3.3** Schema-Migration mit Versionsnummer — `LiteDbContext` schreibt die Schema-Version in eine `meta`-Collection und führt Migrationsschritte nur noch aus, wenn die gespeicherte Version dahinter liegt (`RunVersionedMigrations`), statt wie bisher bei jedem Start erneut über alle Daten zu laufen. Die bestehenden (bereits idempotenten) Migrationsschritte wurden als Version-1-Schritt gebündelt, für zukünftige Schema-Änderungen ergänzt man einen weiteren `if (version < N)`-Block. 2 Tests in [LiteDbContextTests.cs](LehrerApp.Data.Tests/LiteDbContextTests.cs). - [x] **13.3.4** Optionale Verschlüsselung der lokalen Datenbank — [DatabaseEncryptionService.cs](LehrerApp.Data/DatabaseEncryptionService.cs). Passwort setzen/ändern/entfernen läuft über eine Kopie (neue Datei mit Zielpasswort anlegen, alle Collections umkopieren, Datei austauschen) statt über `LiteDatabase.Rebuild(...)` mit Passwort — das ist in LiteDB 5.0.21 nachweislich fehlerhaft (per Skript verifiziert: wirft "this data file is encrypted" beim Rebuild einer unverschlüsselten Datei). Ist die Datenbank verschlüsselt, fragt ein eigenes Fenster ([DbPasswordPromptWindow](LehrerApp.Desktop/Views/DbPasswordPromptWindow.axaml)) das Passwort ab, **bevor** `AppBootstrapper.BuildServices()` (und damit das Öffnen der Datenbank) läuft — siehe `App.axaml.cs`. Ändern/Entfernen des Passworts läuft über Einstellungen → Sicherheit, jeweils mit Neustart der App danach. 4 Tests in [DatabaseEncryptionServiceTests.cs](LehrerApp.Data.Tests/DatabaseEncryptionServiceTests.cs). - [x] **13.3.5** App-Sperre nach Inaktivität — [AppLockService.cs](LehrerApp.Core/Services/AppLockService.cs) (eigenes, gesalzenes PBKDF2-Passwort, unabhängig von einer eventuellen Datenbank-Verschlüsselung) + [AppLockViewModel.cs](LehrerApp.Desktop/ViewModels/AppLockViewModel.cs) (Inaktivitäts-Timer, Sperrbildschirm-Logik). Maus-/Tastatureingaben im Hauptfenster setzen den Timer zurück ([MainWindow.axaml.cs](LehrerApp.Desktop/Views/MainWindow.axaml.cs)); läuft er ab, blendet ein Overlay in [MainWindow.axaml](LehrerApp.Desktop/Views/MainWindow.axaml) die gesamte Oberfläche aus, bis das Passwort stimmt. Einstellbar (aktiv/inaktiv, Zeit, Passwort) über Einstellungen → Sicherheit, wirkt sofort ohne Neustart. 2 Tests in [AppLockViewModelTests.cs](LehrerApp.Desktop.Tests/AppLockViewModelTests.cs) (reine Unlock-Logik; der zeitbasierte Inaktivitäts-Timer selbst ist nicht automatisiert getestet). **Hinweis:** `RestartApplication()` startet den Prozess über `Environment.ProcessPath` neu — im veröffentlichten Programm korrekt, im Entwicklungsbetrieb über `dotnet run` zeigt `ProcessPath` auf den `dotnet`-Host statt auf die App, ein Neustart über die Einstellungen ist dort also nur in einer veröffentlichten Build (`dotnet publish`) sinnvoll zu testen. - [x] **13.3.6** Sauberer Desktop-Lifecycle — beim Beenden wird ein LiteDB-Checkpoint ausgeführt und anschließend der DI-Container samt Singleton-Datenbankverbindung entsorgt. Das initiale Hauptfenster wird vom Avalonia-Desktop-Lifetime angezeigt; ein explizites `Show()` erfolgt nur beim späteren Wechsel vom Passwortfenster zur Hauptansicht. ### 13.4 Codepflege - [x] **13.4.1** `CLAUDE.md` mit Projektkonventionen anlegen (`/init`) — [CLAUDE.md](CLAUDE.md). - [ ] **13.4.2** `AllRepositories.cs` und `IRepositories.cs` in Themendateien aufteilen, sobald weitere Repositories dazukommen. Aktuell (319 bzw. 154 Zeilen für ~20 Repositories) noch nicht unübersichtlich genug, um die Bedingung auszulösen — bewusst zurückgestellt. - [x] **13.4.3** Wiederkehrende UI-Muster als wiederverwendbare Controls/Styles. Bestandsaufnahme vor der Umsetzung ergab drei echte Duplikate (Suchleiste dagegen nur 3× und jedes Mal eine simple `TextBox` ohne gemeinsames Chrome — Extraktion lohnt sich dort nicht): - Seiten-Kopfzeile (Titel 22px SemiBold + optionaler Untertitel) war identisch in `GroupListView`, `StudentListView`, `GroupDetailView`, `StudentDetailView`, `SettingsView` nachgebaut → neue [PageHeader](LehrerApp.Desktop/Views/Shared/PageHeader.axaml)-Control, dort eingesetzt. - Dialog-Titel (`FontSize="18" FontWeight="SemiBold"` als erstes Element) kam in 16 Dialogen jeweils inline vor → globale Style-Klasse `TextBlock.dialogtitle` ([App.axaml](LehrerApp.Desktop/App.axaml)). - Leerlisten-Hinweis ("Noch keine …") kam an 10 Stellen vor, dabei war Opacity/FontSize bereits leicht auseinandergedriftet (0.35 vs. 0.4, 12 vs. 13) → globale Style-Klasse `TextBlock.emptyhint`, normalisiert alle Stellen auf einen Wert. Absichtlich nicht angefasst: die vier Views mit eigenen lokalen `