Files
LehrerApp/TODO.md
T
admin 0800832ae5 Klausurtermine im Kalender (4.4.3) + Stundenplan: Ausnahme eintragen, Zahnrad-Settings-Link
- 4.4.3: Box "ANSTEHENDE KLAUSUREN" im Heute-Tab, gruppenübergreifend, nächste 21 Tage.
  IExamRepository um GetAll() erweitert.
- Nutzer-Feedback: "Vertretung eintragen" deckt auch Ausfall/Sondereinsatz ab, daher
  umbenannt in "Ausnahme eintragen". "Stundenplan bearbeiten" (redundant zum Bearbeiten-Tab)
  ersetzt durch Zahnrad-Button, der direkt in die Einstellungen springt.
2026-08-15 22:24:04 +02:00

1188 lines
86 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 16 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 47 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: <Bezeichnung>"`), 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.
- [x] **4.2.5** Stunden serienweise aus dem Stundenplan (4.3) erzeugen — neuer Button
"Serie erzeugen" in der Stunden-Toolbar der Planung
([GenerateLessonSeriesDialog.axaml](LehrerApp.Desktop/Views/Groups/GenerateLessonSeriesDialog.axaml),
`GenerateLessonSeriesDialogViewModel` in
[PlanningViewModels.cs](LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs)). Legt für
jeden Wochentag/Stunde, den die Gruppe laut `TimetableSlot` (4.3) hat, im gewählten Zeitraum
eine `Lesson` an; Zeitraum ist standardmäßig `Unit.StartDate``Unit.EndDate`, falls gesetzt.
Schulferien/Feiertage werden übersprungen (dieselbe Prüfung wie im Stundenplan-Wochenraster),
bereits vorhandene Termine (gleiches Datum + gleiche Stundennummer der Gruppe, unabhängig von
der Einheit) nicht doppelt angelegt. Ergebnis ("3 Stunde(n) angelegt, 1 durch Ferien/Feiertage
übersprungen, ...") kommt als Toast (erste tatsächliche Nutzung von
`NotificationService.ShowSuccess`, bis dahin nur `ShowError` im Einsatz). Neue Stunden haben
bewusst kein Thema (Platzhalter zum Ausfüllen) — die "Thema erforderlich"-Pflicht des
manuellen " Stunde"-Dialogs gilt hier nicht.
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<LessonPhaseStep>` (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.
**Nachtrag zu 4.2.2 (Stundenraster + Zeitbedarf-Rückmeldung):** Der Verlaufsplan-Editor kannte bis
dahin nur die geplante Gesamtdauer, nicht wie viel Zeit die Stunde laut Stundenplan tatsächlich
hat. Neuer Tab "Stundenraster" in den Einstellungen pflegt Beginn/Ende je Stundennummer (1.10.
Stunde, `PeriodScheduleService` — JSON-Datei, gleiches Muster wie
`SchoolCalendarSettingsService`/`PrivacySettingsService`). Nicht jede Stunde muss eingetragen sein.
- **Doppelstunden-Erkennung:** Ausgehend von der eingetragenen Stundennummer wird so lange die
jeweils nächste Periode addiert, wie der Stundenplan (4.3, `TimetableSlot`) für dieselbe Gruppe
am selben Wochentag *dort ebenfalls* einen Slot hat — eine Lesson mit Stundennummer 3 bekommt
bei einer Doppelstunde 3./4. also automatisch 90 statt 45 Minuten als Vergleichsbasis, ohne dass
das irgendwo separat markiert werden muss. Gehört die Folgeperiode einer anderen Gruppe, wird sie
korrekt nicht mitgezählt.
- **Farbskala** (`LessonDialogViewModel.TimeBudgetColor`, Nutzer-Vorgabe): 9396 % Auslastung ist
der Zielbereich (grün) — ein kleiner Puffer, da 100 % laut Nutzer "meist schon knapp" ist. Von
dort Richtung 100 % wird es zunehmend orange, darüber (überplant) kräftiger rot. Für "deutlich zu
wenig geplant" (unter 70 %) hatte der Nutzer noch keine feste Vorstellung — hier bewusst ein
neutrales Blaugrau statt Rot gewählt (kein Fehler, nur "hier geht noch was"); Grenzwerte/Farben
sind über die switch-Ausdrücke leicht nachjustierbar.
- **Beginn wird beim Setzen der Stundennummer automatisch aus dem Stundenraster übernommen**,
sofern noch keiner eingetragen ist (überschreibt nie einen bereits vorhandenen Wert) — damit
entfällt die bisher manuelle Pflege des "Beginn"-Felds für Stunden, die im Stundenraster
hinterlegt sind, ganz von selbst.
- Ohne Stundennummer/gültiges Datum oder ohne im Stundenraster hinterlegte Zeiten für die
betroffene(n) Periode(n) bleibt die Rückmeldung schlicht ausgeblendet statt eine erfundene Dauer
vorzutäuschen.
**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). MoFr ×
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 20232027 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 (MoFr × 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.
**Nachtrag zu 4.3, fünfte Iteration (Aufsichten + Vertretung):** Nutzer-Feedback: zwischen manchen
Stunden ist auch Pausenaufsicht zu erledigen, und gelegentlich kommen Sonderfälle vor — eine
Vertretungsaufsicht für einen erkrankten Kollegen, oder eine Vertretungsstunde in einer eigenen
oder fremden Lerngruppe.
- **Neue Modelle** ([Planning.cs](LehrerApp.Core/Models/Planning.cs)): `SupervisionDuty`
(wiederkehrend, Wochentag + "Pause nach Stunde X" + Ort — `AfterPeriod = 0` heißt Frühaufsicht
vor der 1. Stunde) und `SubstitutionEntry` (einmalig, an einem konkreten Datum — entweder
`Kind = Supervision` oder `Kind = Lesson`). Bewusst getrennt von `TimetableSlot`/`Lesson`: die
wiederkehrende Aufsicht hat keinen Gruppenbezug, und die meisten Vertretungsstunden sind keine
durchgeplanten Einheiten-Stunden.
- **Wiederkehrende Aufsicht wird nur in den Einstellungen gepflegt** (neuer Tab "Aufsichten",
analog zum Kürzel-Katalog: Liste + Formular, kein Klick-Dialog im Stundenplan-Raster selbst —
anders als bei `TimetableSlot`, weil eine kleine, seltene Liste hier ergonomischer ist als ein
Klick durchs ganze Raster). Pro Wochentag/Pause höchstens eine Aufsicht (eindeutiger Index,
freundliche Fehlermeldung wie bei `TimetableSlot`).
- **Anzeige im Stundenplan:** Aufsicht-Zeilen werden zwischen den betroffenen Stundenzeilen sowohl
im Bearbeiten-Raster als auch im Wochenraster eingefügt (nur wenn für die jeweilige Pause
tatsächlich etwas hinterlegt ist, sonst bleibt die Zeile weg) — `TimetableCellItem`/`WeekCellItem`
bekamen dafür `IsSupervisionRow`/`IsSupervisionCell` als weitere, sich gegenseitig ausschließende
Zellenarten (gleiches Muster wie die bestehenden `IsHeader`/`IsPeriodLabel`/`IsSlotCell`), statt
eine zweite `ItemsControl` neben das bestehende `UniformGrid` zu setzen.
- **"Vertretung eintragen"**-Dialog (neuer Button neben "Stundenplan bearbeiten" im "Heute"-Tab,
[SubstitutionEntryDialogViewModel.cs](LehrerApp.Desktop/ViewModels/Planning/SubstitutionEntryDialogViewModel.cs))
deckt beide Sonderfälle ab. Eine Vertretungsaufsicht/-stunde für ein konkretes Datum überschreibt
in Wochenraster, Bearbeiten-Zeile bzw. Tagesliste die sonst dort angezeigte reguläre Information
für diese eine Stunde/Pause — sie beschreibt ja, was an dem Tag tatsächlich passiert.
Vertretungsstunden ohne passenden `TimetableSlot` (z.B. fremde Gruppe zu einer Zeit, zu der man
sonst frei hat) werden trotzdem ergänzt, nicht verworfen.
- **Entscheidung zur eigenen-Gruppe-Frage** (mit dem Nutzer abgestimmt): Standard bleibt der
einfache Weg — nur ein `SubstitutionEntry` mit Thema, wie bei einer fremden Gruppe. Nur wenn die
gewählte eigene Gruppe mindestens eine `Unit` hat, erscheint zusätzlich eine Checkbox "Direkt als
Stunde in der Einheit übernehmen" (mit Einheiten-Auswahl) — dann entsteht *zusätzlich* eine
echte `Lesson` in dieser Einheit. Der `SubstitutionEntry` bleibt in beiden Fällen bestehen (er
ist die Anzeige-Quelle für den Plan), die `Lesson` ist rein für die Fortschritts-/Reihenfolge-
Bilanz der Einheit gedacht und wird im Stundenplan nicht separat angezeigt.
**Nachtrag zu 4.3, sechste Iteration (Sondereinsätze):** Nutzer-Feedback: neben Vertretung gibt es
auch Sondereinsätze wie Ausflüge oder Berufsmessen, die einen Teil des Tages oder den ganzen Tag
blockieren, ohne dass jemand vertreten wird.
- `SubstitutionKind` um `SpecialAssignment` erweitert; `SubstitutionEntry` bekam `FromPeriod`/
`ToPeriod` (Stundenbereich) und `IsAllDay` (ganztägig statt Stundenbereich). Dieselbe dritte Art
im "Vertretung eintragen"-Dialog (`SubstitutionKindDisplay` jetzt mit drei statt zwei Optionen).
Bewusst **kein** "Als Stunde in der Einheit übernehmen" für Sondereinsätze — ein Ausflug ist
inhaltlich kein Verlaufsplan-Eintrag, anders als eine Vertretungsstunde.
- **Anzeige im Wochenraster:** ein Sondereinsatz überdeckt für seinen Wochentag jede Perioden-Zelle
im belegten Bereich (bei `IsAllDay` alle 10 Stunden) mit derselben Kachel (Farbe `#00838F`,
deutlich von Vertretung-Lila unterscheidbar) — dieselbe Überschreiben-Logik wie bei
Vertretungsstunden, nur über mehrere Perioden statt einer einzelnen.
- **Anzeige in der Tagesliste:** eigener Abschnitt `TodaySpecialAssignments` (wie bei den
Aufsichten) statt Wiederholung über mehrere Zeilen — ein ganztägiger Sondereinsatz würde sonst
zehnmal in der Liste auftauchen.
- **Mehrtägige Sondereinsätze (Klassenfahrt) bewusst nicht als Datumsbereich modelliert** — mit
dem Nutzer abgestimmt: `SubstitutionEntry.Date` bleibt ein einzelnes Datum. Klassenfahrten dauern
laut Nutzer höchstens ~5 Tage und kommen alle ein bis zwei Jahre vor — dafür lohnt sich kein
eigener Datumsbereich mit den nötigen Änderungen an `GetByDate`/Wochenraster-Abfragen; ein
Sondereinsatz über mehrere Tage wird einfach als mehrere Einzeleinträge (einer pro Tag) erfasst.
**Nachtrag zu 4.3, siebte Iteration (Stundenausfall):** Nutzer-Feedback: es kann auch sein, dass
eine Stunde schlicht ausfällt, ohne dass die eigene Abwesenheit der Grund ist — z.B. fällt der
NAT-Unterricht der 6a aus, weil die 6a selbst auf Klassenfahrt ist. Kein Vertretungsfall (niemand
übernimmt), kein Sondereinsatz (die eigene Zeit ist nicht belegt).
- `SubstitutionKind` um `Cancelled` erweitert, vierte Option im "Vertretung eintragen"-Dialog.
Braucht nur Datum + Stundennummer + optionalen Grund — Fach und Gruppe werden beim Anzeigen aus
dem an der Stelle regulär eingetragenen `TimetableSlot` abgeleitet, nicht beim Anlegen manuell
erfasst (die Information steht ja schon im Stundenplan).
Bewusst kein "Als Stunde übernehmen" — ein Ausfall ist per Definition keine gehaltene Stunde.
- **Anzeige:** ersetzt im Wochenraster und in der Tagesliste die normale Stunden-Kachel/-Zeile für
die betroffene Stunde (Grau `#757575`, Aufschrift "Ausfall") — dieselbe Überschreiben-Logik wie
bei Vertretungsstunden und Sondereinsätzen, nur dass hier nichts an die Stelle tritt.
**Nachtrag zu 4.3, achte Iteration (Button-Umbenennung + Zahnrad statt "bearbeiten"):**
Nutzer-Feedback: Der Button "Vertretung eintragen" deckt nach der fünften bis siebten Iteration
auch Sondereinsatz und Ausfall ab, der Name passt nicht mehr. Der Button "Stundenplan bearbeiten"
war zudem redundant (das Bearbeiten-Tab ist direkt anklickbar) und fühlte sich unzuverlässig an.
- "Vertretung eintragen" → "Ausnahme eintragen" (Button und Dialogtitel in
`SubstitutionEntryDialog.axaml`) als neutraler Oberbegriff für alle vier `SubstitutionKind`-Fälle.
- "Stundenplan bearbeiten" ersetzt durch einen kleinen Zahnrad-Button ("⚙️"), der in die
Einstellungen springt, direkt auf den Tab "Ferien & Feiertage" (Nachbar-Tabs "Stundenraster" und
"Aufsichten" sind von dort ein Klick entfernt) — dieselbe Navigate-mit-Zieltab-Konvention wie
`NavigateToGroupDetail`. Dafür `SettingsViewModel.ActiveTabIndex` (an `TabbedPage.SelectedIndex`
gebunden) sowie `MainWindowViewModel.NavigateToSettings(int initialTab = 0)` neu eingeführt.
- `TimetableViewModel.ShowEditorCommand` entfernt (kein Aufrufer mehr) statt umbenannt — es tat
ohnehin nur `ActiveTabIndex = 1`, was jetzt nirgends mehr gebraucht wird.
### 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).
- [x] **4.4.3** Anzeige anstehender Klausurtermine im Kalender — neue Box "ANSTEHENDE KLAUSUREN"
im "Heute"-Tab, gruppenübergreifend, nächste 21 Tage (max. 10 Einträge), unabhängig vom
`WeekOffset` des Wochenrasters. `IExamRepository` brauchte dafür ein `GetAll()` (bisher nur
`GetByGroup`). **Abgabefristen bewusst nicht enthalten:** es gibt im Datenmodell noch kein
Frist-/Deadline-Konzept (nur `Exam.Date`) — das bräuchte ein neues Modell, siehe auch 9.8
("ggf. einem neuen Termine-Modell"). Kein Aufschub aus Unklarheit, sondern weil das über den
angefragten Umfang hinausginge.
### 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.
**Architekturentscheidung (Nachtrag, Konzeptgespräch):** Diskutiert wurde, ob eine eigene
Multiplattform-App für die Einheiten-/Stundenplanung sinnvoll ist — analog zum separaten
Tafelbilder-Vorhaben (eigene App, nur eine Schnittstelle zur LehrerApp, weil dort die
Interaktionsform — Zeichnen/Präsentationsmodus — grundsätzlich anders ist als CRUD). Für die
Unterrichtsplanung gilt das **nicht**: Planung findet zu 99,9 % am Desktop-PC oder MacBook statt
(Avalonia läuft dort bereits nativ), es besteht also kein Plattformzwang für eine separate App.
Entscheidung: **kein** eigenes Domainmodell/eigene App für Einheiten-/Stundenplanung — die
folgenden Punkte gehören direkt in `LehrerApp.Desktop`:
- [ ] **4.5.7** Graph über Aktivitätsphasen und Anspruchsniveau im zeitlichen Verlauf einer
Lesson/Einheit (baut auf `LessonPhaseStep`/`Niveau` auf), um die Stundenverteilung besser
einschätzen zu können.
- [ ] **4.5.8** Kompetenzen je Aufgabe/Phase verknüpfen — nutzt den bestehenden
`CompetencyDomain`/`CompetencyItem`-Katalog (siehe Kompetenzen-Tab in den Einstellungen),
bisher nur für Klausuraufgaben (`ExamTask.CompetencyCodes`) verknüpft, nicht für
Verlaufsplan-Phasen.
- [ ] **4.5.9** KI-gestützte Planungsunterstützung über eine Schnittstelle zu einer LLM-API, um
Einheiten/Stunden mit Hilfe vorzuschlagen und weiterzuentwickeln. Bedarf eines abgesicherten
Zwischenelements auf dem eigenen Server (Ablösung/Verbesserung des bisherigen
PHP-Zwischenelements für Elternbriefe) mit interner Abrechnung/Nutzungskontrolle, damit der
API-Schlüssel nicht im Client landet.
- [ ] **4.5.10** Falls doch ein schlanker Companion-/WebApp-Client entstehen soll: bewusst
**minimaler** Funktionsumfang — nur Wochenraster ansehen, eine Stunde verschieben, oder eine
Stunde als "Umplanung nötig" flaggen. Kein Editor für Einheiten/Kompetenzen/KI-Planung dort.
Technisch schon vorbereitet: `LehrerApp.Sync`/`LehrerApp.Api` haben mit `PlainSyncEvent` und
`DeviceType.Companion` bereits eine Klartext-Sync-Schiene für genau diese Art von leichtem,
nicht-Desktop-Client (siehe `PlainEventStore`, `MapPlainSyncEndpoints`) — ein "Umplanung
nötig"-Flag käme darüber rein und würde nach dem Sync als Hinweis/Badge an der betroffenen
Stunde bzw. im Dashboard erscheinen, bis es am Desktop bearbeitet oder bewusst abgehakt wird.
---
## 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<string>`, 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, VonBis 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
`<AppData>/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
`<AppData>/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 `<Style Selector=>`-Blöcken
(MainWindow, DashboardView, StudentDetailView, ExamEvaluationDialog) sind jeweils
einzigartige Spezial-Visualisierungen (Kalenderzellen, Sparkline, Balkendiagramm,
Toast/Drawer) ohne Duplikate untereinander.
- [x] **13.4.4** Konverter und Styles zentralisieren. Bei der Bestandsaufnahme für 13.4.3 zeigte
sich: es gibt keine einzige eigene `IValueConverter`-Implementierung im Projekt — überall
werden bereits konsistent Avalonias eingebaute statische Konverter (`StringConverters`,
`BoolConverters`, `ObjectConverters`) verwendet. Nichts zu zentralisieren; die
Style-Duplikate wurden im Zuge von 13.4.3 behoben (siehe oben).
---
## 14. UX-Querschnitt
- [ ] **14.1** Tastaturbedienung durchgängig: alle Hauptfunktionen ohne Maus erreichbar
(Vorbild: Mitarbeit-Schnelleingabe).
- [ ] **14.2** Globale Suche (Schüler, Gruppe, Klausur) über Tastenkürzel.
- [ ] **14.3** Rückgängig-Funktion für Löschvorgänge (mindestens Bestätigungsdialog überall).
- [ ] **14.4** Ladeanzeigen bei längeren Operationen (Import, Sync, Export).
- [ ] **14.5** Leere Zustände mit Handlungsaufforderung statt leerer Tabellen.
- [ ] **14.6** Fenstergröße und Spaltenbreiten über Sitzungen hinweg merken.
- [ ] **14.7** Bedienung auf Touch-Geräten prüfen (Tablet im Unterricht).
- [ ] **14.8** Responsive Layout und Windows-DPI prüfen (kleine Notebook-Auflösungen sowie
125/150/200 % Skalierung; starre Master-Detail-Spalten bei Bedarf stapeln). Der kompakte
Drawer berücksichtigt bereits die schmalere verfügbare Breite mit reduziertem Außen-/
Innenabstand und einer eigenen Iconfläche, damit Windows-Emoji nicht abgeschnitten werden.
- [ ] **14.9** Barrierefreiheit prüfen: Automation-Namen für Icon-Buttons, sichtbare Fokusrahmen,
Kontraste und Status nicht ausschließlich über Farbe/Emoji vermitteln.
- [ ] **14.10** Plattformübergreifend konsistentes SVG-/`PathIcon`-Set statt systemabhängiger
Emoji-Darstellung einführen.
- [x] **14.11** Aktiven Navigationspunkt in der Seitenleiste sichtbar hervorheben; Zustand wird
über `MainWindowViewModel.ActiveNavItem` gesteuert.
---
## 15. Auslieferung
- [ ] **15.1** Release-Build und Signierung für macOS.
- [ ] **15.2** Windows-Build prüfen (Zielplattform klären).
- [ ] **15.3** Versionierung und Changelog-Pflege.
- [ ] **15.4** Update-Mechanismus oder zumindest Versionsprüfung beim Start.
- [ ] **15.5** Kurze Bedienanleitung für den Eigengebrauch.
---
## 16. Datenmodell- und Architekturqualität
- [ ] **16.1** Referenzielle Integrität für alle Modellbeziehungen dokumentieren und je Beziehung
explizit `Cascade`, `Restrict`, `SetNull` oder Archivierung festlegen; Löschpfade mit
Transaktions- und Vollständigkeitstests absichern.
- [ ] **16.2** Domain-Validierung aus den Dialog-ViewModels in gemeinsam nutzbare Regeln/Services
überführen, damit Import, Sync und API dieselben Regeln durchsetzen.
- [ ] **16.3** Prüfen, ob Punkte, Gewichtungen und Prozentgrenzen von `double` auf `decimal` oder
skalierte Ganzzahlen migriert werden sollen; Rundungs- und Migrationsstrategie festlegen.
- [ ] **16.4** Redundant gespeicherte Bewertungswerte (`ExamResult.TotalPoints`, berechnete Note)
entweder ableiten oder zusammen mit einer unveränderlichen Version des verwendeten
Notenschlüssels als historischen Snapshot speichern.
- [ ] **16.5** Kompetenzzuordnungen auf stabile `CompetencyItem.Id` umstellen; Code/Beschreibung bei
Bedarf zusätzlich als historischen Snapshot speichern, damit Umbenennungen keine alten
Klausur- oder Sitzungsreferenzen brechen.
- [ ] **16.6** Navigation und manuelle Callback-Verdrahtung in `App.axaml.cs` langfristig durch
einen testbaren Navigationsdienst oder Messenger ersetzen; statischen Servicezugriff abbauen.
---
## Empfohlene Reihenfolge
Die Abschnitte sind thematisch, nicht chronologisch nummeriert. Sinnvolle Bearbeitungsreihenfolge:
1. ~~**Kapitel 1** (Klausuren)~~ — erledigt.
2. ~~**Kapitel 3.2** (Mitarbeit-Aggregation)~~ — erledigt.
3. ~~**Kapitel 2** (Noten & Zeugnisnoten)~~ — erledigt.
4. ~~**Kapitel 13** (Technische Basis: Tests, Fehlerbehandlung, Datensicherheit, Codepflege)~~
erledigt (13.113.4 vollständig; 13.4.2 bewusst zurückgestellt, siehe dort).
5. ~~**Kapitel 5** (Schülerdokumentation)~~ — erledigt (5.2 als Auswertung des bestehenden
Anwesenheits-Trackings statt zweiter Erfassung, siehe dort).
6. ~~**Kapitel 4.1 + 4.2 + 4.3 + 4.4** (Unterrichtsplanung: Einheiten, Einzelstunden, Stundenplan,
Wochen-/Tagesansicht)~~ — vollständig erledigt, inkl. mehrerer Nachtrag-Iterationen aus
Nutzer-Feedback (Ferien-Pflege in den Einstellungen, Wochenraster mit Wochennavigation,
Ferientage ausgegraut, Serienerzeugung, Stundenraster mit Zeitbedarf-Rückmeldung, Aufsichten,
Vertretung/Sondereinsatz/Ausfall, anstehende Klausuren). Offen bleibt nur **4.5** (engere
Vernetzung Stundenplan ↔ Lesson-Planung — ausdrücklich vom Nutzer zurückgestellt, nicht aus
Unklarheit; Desktop bekommt dort perspektivisch Graph/Kompetenz-Verknüpfung/KI-Planung, ein
möglicher Companion-Client bleibt bewusst minimal).
**→ nächster sinnvoller Schritt: Kapitel 6, 10 oder 11.**
7. **Kapitel 6** (Arbeitszeit), **11** (Export), **10** (Sync) — danach.