feat: Kompetenzzuordnungen von Freitext-Code auf stabile CompetencyItem.Id umgestellt (TODO 16.5)

Unit/Lesson/ExamTask/ParticipationSession referenzierten Kompetenzen bisher per Freitext-Code,
case-insensitiv gegen den Katalog gematcht - fragil bei Umbenennungen und seit der
Bildungsplan-Versionierung nicht mehr eindeutig (zwei Versionen können denselben Code vergeben).
Neuer Werttyp CompetencyReference (ItemId + Code/Description-Momentaufnahme) löst das: solange die
Id noch im Katalog auflösbar ist, zählt die live Fassung (Rename wirkt sofort), sonst bleibt die
gespeicherte historische Fassung sichtbar statt spurlos zu verschwinden.

Migration (Schema-Version 6) löst bestehende Codes gegen den Katalog auf; die zuvor dreifach
duplizierte Kompetenz-Tag-UI ist jetzt in CompetencyTagGroupBuilder konsolidiert.
add_lesson_competency/remove_lesson_competency nehmen jetzt itemId statt code und validieren gegen
den Katalog (vorher ungeprüft).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-19 00:41:54 +02:00
1 parent f97edff2fe
commit dc2f58c4dc
28 files changed
+691 -202

No files matched your search

+12
View File
@@ -98,6 +98,18 @@ Einige berechnete Werte bleiben absichtlich gespeichert:
- `Exam.GradingKey` hält den für die konkrete Klausur verwendeten Notenschlüssel
fest und ist unabhängig von später geänderten Vorlagen.
- `Exam.Tasks` hält die Aufgabenstruktur der konkreten Klausur fest.
- `CompetencyReference` (`Unit.Competencies`, `Lesson.Competencies`, `ExamTask.Competencies`,
`ParticipationSession.Competencies`) verweist über `ItemId` auf ein `CompetencyItem`, hält aber
zusätzlich `Code`/`Description` zum Zuordnungszeitpunkt fest (TODO 16.5, abgelöst von einer reinen
Freitext-Code-Zuordnung). Solange `ItemId` noch im Katalog auflösbar ist, zeigt die Anwendung die
**live** Fassung (ein Rename im Katalog wirkt sich überall sofort aus); wird das Item gelöscht,
bleibt die hier gespeicherte historische Fassung lesbar statt spurlos zu verschwinden.
`ItemId == Guid.Empty` markiert eine nie aufgelöste Referenz (z.B. aus einem
plattformübergreifenden `PlanningExchangeService`-Import, der bewusst keine installationsfremden
IDs überträgt) — Code/Description sind dann die einzige Information.
`CompetencyRating.ItemId` (Mitarbeit, je Schüler) referenziert ebenso per Id, aber ohne eigenen
Snapshot — die Identität kommt aus der Zuordnungsliste der zugehörigen `ParticipationSession`,
die bereits eine Momentaufnahme trägt.
Änderungen an Aufgaben oder Notenschlüssel müssen die betroffenen Ergebnisse
kontrolliert neu berechnen. Diese Werte sind daher fachliche Momentaufnahmen und