- Dashboard: Fehlzeiten-Warnung lädt Mitarbeitssitzungen einmal vorab
statt pro Schüler/Eintrag einzeln nachzuschlagen (N+1 vermieden);
neues IParticipationSessionRepository.GetAll() dafür.
- CI: .gitea/workflows/ci.yml baut und testet bei jedem Push/PR.
Dabei fehlende Release|Any CPU-Konfiguration für 6 Projekte in der
.sln behoben (LehrerApp.Data.Tests wurde bei Release-Builds der
Solution bislang stillschweigend übersprungen). TreatWarningsAsErrors
jetzt aktiv.
- SettingsViewModel (1986 Zeilen) als partial class auf 20 Themen-
dateien aufgeteilt, Verhalten unverändert.
- Backup: optionaler zweiter Sicherungsordner (USB-Stick/Netzlaufwerk,
best-effort) und Integritätsprüfung nach jedem Backup
(DatabaseEncryptionService.CanOpenAndRead).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nutzer-Feedback: Klassenlehrer ist eine Rolle für die ganze Klasse, unabhängig vom
eigenen Unterricht - die Anbindung an ein LearningGroup.IsClassTeacher-Flag mit Tab
in der Gruppendetailansicht war deshalb der falsche Ort. Ersetzt durch:
- Klassenauswahl in den WebUntis-Einstellungen (WebUntisSettingsService.HomeroomClassName),
über den bestehenden WebUntis-Klassenpicker.
- Eigener Sidebar-Bereich "Klassenlehrer" statt Gruppen-Tab.
- Zwei Ebenen: kompakte Roster-Übersicht mit Ampel-Symbolen (Fehlzeiten heute,
Klassenbuch-Badge) und Details (die bisherigen Rohdaten-Listen, jetzt gefiltert
auf einzelne Schüler*innen anspringbar).
Noch nicht mit echtem WebUntis-Zugang gegengeprüft (siehe TODO.md).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Erkennt Vertretungen, Ausfälle und Zusatzaufsichten aus dem persönlichen
WebUntis-iCal-Feed und schreibt sie automatisch als SubstitutionEntry.
Bekannter offener Bug: es tauchen weiterhin falsche Vertretungen für
Stunden auf, die real unverändert sind — wird in einem Folge-Commit
untersucht, deshalb vorerst auf diesem Branch statt main.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dunkelmodus über neuen Einstellungen-Tab "Darstellung" (Systemvorgabe/Hell/Dunkel),
Fenstergröße/Maximiert-Status wird über Sitzungen hinweg gemerkt (bewusst ohne
Fensterposition), und ein generischer Snapshot-basierter Papierkorb (30 Tage) für
Sitzpläne, Noten, Notenschlüssel-Vorlagen, Aufgaben und Zeiteinträge. Details und
bewusste Scope-Entscheidungen (Spaltenbreiten zurückgestellt, Farb-Audit für
Dunkelmodus offen, welche Entitäten der Papierkorb abdeckt) in TODO.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Der Sync-Schlüssel verlässt nie den Server im Klartext - verliert das einzige Gerät sync.key,
erzeugte AppBootstrapper bisher stillschweigend einen neuen, unabhängigen Schlüssel, ohne dass
der Nutzer etwas davon merkt. Bereits synchronisierte Server-Daten werden dadurch dauerhaft
unlesbar.
AppBootstrapper erkennt jetzt, ob ein fehlender Schlüssel bei einem bereits eingeloggten Gerät
auftritt (SyncKeyStatus) - SettingsViewModel zeigt dafür ein Warnbanner im Synchronisation-Tab mit
der Empfehlung, im Zweifel über ein noch intaktes zweites Gerät neu zu koppeln.
Zusätzlich ein komplett offline laufender, selbstverwalteter Wiederherstellungscode (kein neuer
dauerhafter Server-Speicher für ein sicherheitsrelevantes Geheimnis): SyncCrypto bekommt einen
neuen, vom Pairing-Code kryptografisch unabhängigen Recovery-Code (120 Bit, Base32), mit dem der
Sync-Schlüssel lokal verschlüsselt und als Datei durch den Nutzer selbst gesichert werden kann.
Neuer SyncKeyRecoveryService kapselt Erzeugen/Einlösen; Redeem schreibt den wiederhergestellten
Schlüssel und setzt vorsorglich Pull-Cursor/Versionsverfolgung zurück.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RedeemPairingCode() rief nach einem Fehlschlag sofort RestartApplication()
auf, direkt nach dem Setzen von PairingStatus - die Fehlermeldung konnte
nie gerendert werden, und wurde auch nirgends geloggt. Ein Fehlschlag
(falscher/abgelaufener Code, Server nicht erreichbar) wirkte dadurch wie
ein kommentarloser Absturz ohne jede Spur.
- SettingsViewModel loggt den Fehler jetzt über AppLogger und zeigt vor
dem Neustart einen Bestätigungsdialog mit der echten Fehlermeldung an.
- AppBootstrapper.RestartApplication() gibt unter dotnet run/IDE-Debug
(wo ProcessPath auf den dotnet-Host statt die App zeigt) die
ursprünglichen Kommandozeilenargumente beim Neustart mit, statt nur
die dotnet-CLI-Hilfe zu öffnen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Sync-Settings-Tab: neuer Bereich "Gerät koppeln" (10.3.1), nutzt den
bereits vorhandenen, bisher nirgends verdrahteten SnapshotService.
Ein Gerät erzeugt per CreatePairingCode einen verschlüsselten
DB-Snapshot + Einmal-Code, das zweite Gerät übernimmt per
RedeemPairingCode Datenbank und Sync-Schlüssel. Bestätigungsdialog
vor dem Einlösen, da die lokale Datenbank dabei vollständig ersetzt
wird (alter Stand wird automatisch als Backup gesichert).
- Einstellungen: TabPlacement von Top auf Left umgestellt (vertikale
Liste statt langem horizontalem Balken) und die 13 Tabs in drei
logische Gruppen sortiert (Fachliches / Zeitplanung / System).
- Neuer SettingsTab-Enum ersetzt rohe int-Tab-Indizes bei
MainWindowViewModel.NavigateToSettings/
TimetableViewModel.OnNavigateToSettings. Dabei einen bestehenden Bug
gefunden und mitbehoben: das Zahnrad im Stundenplan öffnete über den
hartcodierten Index 7 tatsächlich "Datenschutz" statt des laut
Kommentar/Tooltip beabsichtigten "Ferien & Feiertage".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
KI-Unterstützung: neuer Einstellungen-Tab (Anmeldung, Guthaben) und Button im
Planungs-Tab, der Einheiten+Stunden als JSON an ein neues PHP-Backend (ai-backend/)
sendet und die Antwort als prüfbare Vorschlagsliste zurückbringt. Provider-Aufruf,
Guthabenverwaltung und Abrechnung nach echten Token-Kosten laufen serverseitig, der
Desktop-Client sieht nie einen LLM-API-Key. Zentral abgesichert: eine von der KI
zurückgegebene Stunden-Id, die zu keiner echten Lesson der Einheit passt, wird nie
als Update übernommen, sondern immer als neue Stunde behandelt.
Kompetenzkatalog-Import (8.1.2): JSON-Export/Import für Kompetenzkataloge.
Dokumentationseinträge mit Typwahl (Gespräch, Vorkommnis, Förderplan,
Fehlzeit, Elternanruf, Elternbrief), vertrauliche Einträge nur nach
Bestätigung sichtbar, weiche Löschung mit Nachvollziehbarkeit. Fehlzeiten
als Auswertung des bestehenden Anwesenheits-Trackings statt zweiter
Erfassung, mit Schwellenwert-Warnung im Schülerdetail und Dashboard.
Förderplan-Wiedervorlage als Dashboard-Karte. Datenschutz: Löschfristen
mit manueller Bereinigung und DSGVO-Art.-15-Datenauskunft als Export.
Auf Nutzer-Feedback hin ergänzt: Elternanruf mit begleitendem
Gesprächsprotokoll-Dialog (Punkte abhaken, Eindrücke festhalten),
Elternbrief mit Versand-/Rückmeldungs-Tracking, Datei-Anhänge über
LiteDBs Dateispeicher, frei vergebbare Labels zur Nachverfolgung mit
Dringlichkeits-Farbcodierung, sowie eine sichtbare Farblegende für das
bestehende Notenentwicklungs-Diagramm. Dabei einen Absturz behoben:
leere Textfelder lieferten über das Binding null statt "", was beim
Speichern eine NullReferenceException auslöste.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Automatisches rollierendes Backup der Datenbank beim Start mit
Wiederherstellung über die Einstellungen, versionierte Schema-Migration,
optionale Passwort-Verschlüsselung der LiteDB-Datei und eine App-Sperre
nach Inaktivität mit eigenem Passwort.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Notenschlüssel-Editor im ExamDialog: Stufen (Note/Prozentgrenze)
bearbeitbar, Vorbelegung passend zum GradingSystem der Gruppe,
Live-Anzeige der absoluten Punktegrenze je Stufe, Validierung
(lückenlos, keine Dopplungen) über GradingService.ValidateGradingKey.
- Neues Modell GradingKeyTemplate + Repository: Notenschlüssel als
Vorlage speichern/anwenden, direkt aus dem ExamDialog heraus.
- Einstellungen: Fächer / Kompetenzen / Notenschlüssel-Vorlagen sind
jetzt eigene Tabs statt einer gemeinsam wachsenden Liste. Vorlagen
zeigen nur noch eine kompakte Zeile; die Stufen-Bearbeitung läuft
über ein Popup-Fenster (GradingKeyTemplateDialog).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>