Schreibgeschützter LessonViewerDialog (größere Schrift, ohne Bearbeitungs-/Verlängern-/ Verschieben-Funktion) für den Einsatz während des Unterrichtens, erreichbar über "Anzeigen" im Stunden-Toolbar. Alternative Unterrichtsabläufe (z.B. Kurzversion bei Zeitmangel) laufen jetzt über einen echten Katalog (neues Modell AlternativeLessonPath: Name + Beschreibung) statt Freitext direkt an der Phase: im Verlaufsplan-Editor eine kompakte, farbig unterstützte Checkbox statt einer durchgehend sichtbaren Eingabespalte, Zuordnung/Neuanlage über einen eigenen Dialog. Der Viewer gruppiert Phasen entsprechend und zeigt die hinterlegte Beschreibung. Schema-Migration v3→v4 führt bestehende Freitextwerte verlustfrei in Katalogeinträge über. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.7 KiB
Datenmodell und Begriffe
Dieses Dokument beschreibt die fachliche Bedeutung der zentralen Datensätze. Es soll verhindern, dass technisch ähnliche Felder als unterschiedliche Sachverhalte interpretiert oder dieselben Informationen mehrfach gespeichert werden.
Lerngruppe (LearningGroup)
Eine Lerngruppe ist die konkrete Unterrichtsgruppe eines Fachs in genau einem Schuljahr. Sie kann als Klasse oder Kurs organisiert sein.
Name: frei gewählte Bezeichnung, zum Beispiel5b NAT (BEN)oderMathe GSubjectId: Verweis auf das unterrichtete FachSchoolYear: Schuljahr dieser konkreten LerngruppeGradeLevel: Klassen- beziehungsweise Jahrgangsstufe
Der Fachname wird ausschließlich im Subject-Stammdatensatz gepflegt. Die
Lerngruppe speichert keine zweite Kopie des Fachnamens.
Gruppenzuordnung (GroupMembership)
Eine Gruppenzuordnung verbindet einen Schüler mit einer Lerngruppe. Sie ist keine Aufnahme oder Einschreibung an der Schule.
StudentId: SchülerGroupId: LerngruppeAddedOn: Tag, an dem die Zuordnung in der App angelegt wurdePeriod: ganzes Schuljahr, erstes Halbjahr, zweites Halbjahr oder eigener ZeitraumJoinedAt/LeftAt: Grenzen eines eigenen TeilnahmezeitraumsNiveau: optionale Niveaudifferenzierung
Das Schuljahr wird über die Lerngruppe ermittelt und deshalb nicht zusätzlich
in der Gruppenzuordnung gespeichert. Für eine spätere echte Schulaufnahme wäre
ein eigenes Feld wie Student.SchoolEntryDate zu verwenden.
Pro Kombination aus Schüler und Lerngruppe darf es höchstens eine Zuordnung geben.
Gewichtungsschema (GradingScheme)
Legt die prozentuale Gewichtung von Klausuren, Mitarbeit und sonstigen Leistungen für die Zeugnisnote fest (Kapitel 2.3/2.4). Ein Datensatz ist entweder:
- gruppenspezifisch (
GroupIdgesetzt,GroupTypeleer), oder - eine Voreinstellung je Gruppentyp (
GroupTypegesetzt,GroupIdleer, in den Einstellungen gepflegt).
Bei der Zeugnisnotenberechnung wird zuerst nach einem gruppenspezifischen Schema gesucht, sonst nach der Voreinstellung des Gruppentyps, sonst greift ein fest codierter Fallback (50/40/10).
Zeugnisnote (ReportGrade)
Eine Zeugnisnote gehört zu genau einem Schüler, einer Lerngruppe und einem Zeitraum
(Period: "Gesamtes Schuljahr" / "1. Halbjahr" / "2. Halbjahr" — freier Text, keine Verknüpfung
zu MembershipPeriod). CalculatedValue ist das zuletzt berechnete Ergebnis, OverrideValue
überschreibt es bei pädagogischem Ermessen und erfordert OverrideReason. Nach dem Festschreiben
(IsLocked) wird der Datensatz bei einer Neuberechnung nicht mehr verändert.
Bewusst gespeicherte Momentaufnahmen
Einige berechnete Werte bleiben absichtlich gespeichert:
ExamResult.TotalPointsundExamResult.Gradehalten das zuletzt berechnete Klausurergebnis fest.Exam.GradingKeyhält den für die konkrete Klausur verwendeten Notenschlüssel fest und ist unabhängig von später geänderten Vorlagen.Exam.Taskshält die Aufgabenstruktur der konkreten Klausur fest.
Änderungen an Aufgaben oder Notenschlüssel müssen die betroffenen Ergebnisse kontrolliert neu berechnen. Diese Werte sind daher fachliche Momentaufnahmen und nicht bloß unkontrollierte Kopien.
Bewusste Denormalisierung
Lesson.GroupId bleibt zusätzlich zu Lesson.UnitId gespeichert. Dadurch kann
der häufige Kalenderzugriff auf alle Stunden einer Lerngruppe direkt indiziert
werden. Beim späteren Ausbau der Unterrichtsplanung muss sichergestellt werden,
dass Lesson.GroupId mit der Lerngruppe der zugehörigen Einheit übereinstimmt.
Umgesetzt in PlanningTabViewModel (Kapitel 4.1/4.2): Beim Kopieren einer Einheit
als Vorlage in eine andere Gruppe (4.1.4) wird Lesson.GroupId auf jeder neu
erzeugten Stunde explizit auf die Zielgruppe gesetzt, nicht von der Quell-Lesson
übernommen. Beim Verschieben einer Stunde inkl. Nachrücken der Folgestunden (4.2.4)
ändert sich ausschließlich Lesson.Date — UnitId/GroupId bleiben unangetastet.
Stundenverlaufsplan (Lesson.Phases)
Eine Stunde hat statt eines einzelnen Phase-Textfelds plus Methoden-/Materialien-Listen eine
geordnete Liste Lesson.Phases: List<LessonPhaseStep> (Name, Dauer in Minuten, Tätigkeit,
Material, Kurzsymbol Shorthand). DurationMinutes ist die primäre, vom Nutzer gepflegte Größe;
die im Editor angezeigte Uhrzeit je Phase ist rein abgeleitet (kumulierte Dauer ab
Lesson.StartTime, sofern gesetzt) und wird nirgends persistiert — es gibt also keine
Konsistenzpflicht zwischen gespeicherter Dauer und einer gespeicherten Uhrzeit, weil Letztere gar
nicht gespeichert wird.
Shorthand ist bewusst ein einzelnes Freitextfeld statt einer erzwungenen Von/Nach-Struktur: in
der Praxis ist es mal ein Materialfluss-Pfeil ("AB001->S"), mal nur eine Sozialform ohne Pfeil
("Plenum", "LDE"). Der Kürzel-Katalog (ShorthandCode, Einstellungen) und bereits in anderen
Stunden verwendete Werte dienen nur als Autovervollständigungs-Vorschläge, erzwingen aber keine
Struktur.
AlternativePathId (Guid?, null = Hauptweg) verweist auf einen Eintrag im eigenständigen
Katalog AlternativeLessonPath (Name + optionale Description, verwaltet über
IAlternativeLessonPathRepository) — anders als Shorthand bewusst kein Freitext direkt am
Phasen-Datensatz: die Zuordnung muss zuverlässig gruppierbar sein (LessonViewerViewModel
gruppiert danach für die Anzeige) und soll eine wiederverwendbare Erklärung tragen können ("wann
nimmt man diesen Weg"), was ein reines Freitextfeld nicht sauber leisten kann. Kein
Fork-Punkt-Bezug zum Hauptweg: jede Gruppe wird beim Anzeigen unabhängig ab Lesson.StartTime
durchgerechnet, nicht ab einer gemeinsamen Verzweigungsstelle.
LiteDbContext-Schema-Version 4 führt drei aufeinanderfolgende, unabhängig versionierte
Migrationsschritte für dieses Feld bzw. seine Vorstufen:
- v1→v2 (
MigrateLessonPhases()): führt bereits gespeicherte alte Stunden (einzelnesPhase-Feld,Methods/Materials-Listen) verlustfrei in eine einzige synthetisierteLessonPhaseStep-Zeile zusammen (Name= altesPhase,Activity= alteMethodsverbunden,Material= alteMaterialsverbunden,DurationMinutes = 0da unbekannt). - v2→v3 (
MigrateLessonShorthand()): das ursprünglich als Von/Nach-Paar (ShorthandFrom/ShorthandTo) modellierte Kurzsymbol wird auf das einzelne Freitextfeld zusammengeführt (beide gesetzt →"Von->Nach", nur eines gesetzt → dieser Einzelwert). - v3→v4 (
MigrateLessonAlternativePaths()): das ursprünglich als Freitext (AlternativePath, string) modellierte Kennzeichen für den alternativen Ablauf wird pro distinktem Namen zu einemAlternativeLessonPath-Katalogeintrag zusammengeführt (derselbe Name über mehrere Stunden hinweg referenziert denselben, wiederverwendeten Eintrag) und die Phase aufAlternativePathIdumgestellt.
Alle drei Migrationen lesen dafür die rohe BsonDocument-Repräsentation der lessons-Collection
statt der typisierten Lessons-Collection — nach jeder Modelländerung kennt die typisierte
Lesson-Klasse die alten Feldnamen nicht mehr, ein Zugriff darüber hätte sie beim Deserialisieren
bereits verworfen, bevor sie gelesen werden können.
Eindeutige Schlüssel
Die Datenbank schützt folgende Kombinationen mit eindeutigen Indizes:
- Gruppenzuordnung:
StudentId + GroupId - Klausurergebnis:
ExamId + StudentId - Mitarbeitseintrag:
SessionId + StudentId - Zeugnisnote:
StudentId + GroupId + Period - Fach: normalisierter Fachname
Altdaten werden beim Öffnen der Datenbank automatisch migriert. Die Migration
verknüpft bisherige Fachtexte mit den Fachstammdaten, benennt die bisherige
enrollments-Collection in group_memberships um und entfernt daraus das
doppelt gespeicherte Schuljahr.