docs: document learning tasks phase 10a in ADR-0021, roadmap, architecture and dashboard ADR

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
JannisandClaude Sonnet 5.5 committed 2026-10-10 14:18:26 +02:00
1 parent d1ff7dd291
commit 8fb34ba6b9
4 files changed
+94 -7

No files matched your search

+6 -1
View File
@@ -87,6 +87,7 @@ Alle Zeitpunkte werden als UTC (`DateTimeOffset`/`DateTime` UTC) gespeichert und
| Kalender ✅ | `FamilyCalendar` (Name, Color, IsDefault, Soft Delete), `CalendarPermission` (Rolle **oder** Benutzer → None/Read/WriteOwn/Write), `CalendarEvent` (Title, Location, Notes, IsAllDay, StartUtc, EndUtc, TimeZoneId, RecurrenceRule, ExceptionDates, Uid, PersonIds, ForWholeFamily, Sequence, RowVersion, Soft Delete; Overrides als eigene Zeile mit `SeriesMasterId` + `RecurrenceId`), `IcsFeed` (Owner, Scope, CalendarId, TaskMode, TokenHash, TokenPrefix, LastAccessAt, RevokedAt) – ADR-0015/0016 |
| KI ✅ | `AiProviderConfig` (Name, Type Ollama/Claude/OpenAiCompatible, BaseUrl, Model, ApiKeyProtected, TimeoutSeconds, IsActive, AllowImages, Purposes, DailyLimitPerUser, RowVersion, Soft Delete), `AiUsage` (Person, Anbieter, Zweck, Dauer, Tokens, Erfolg/Fehlerart – ohne Inhalt) – ADR-0020 |
| Chat ✅ | `ChatChannel` (Family / Direct), `ChatMember` (LastReadAt), `ChatMessage` (Text, HasImage), `ChatAttachment`, `ChatReaction` |
| Lernen ✅ (10a) | `LearningSet` (Titel, Fach Mathe/Deutsch, Klassenstufe 1–6, Zielkind, Fälligkeit, Status, Modus Übung/Prüfung, MaxAttempts, TimeLimitMinutes, ShowSolutionsAfterSubmit, ShuffleItems, TotalPoints, GradeThresholds, Source Manual/Ai + AiPrompt/AiProvider/AiModel für 10b, RowVersion, Soft Delete), `LearningItem` (Frage, Antworttyp Number/Text/SingleChoice, Paper vorgesehen, CorrectAnswer, NumberTolerance, Options, Hint, Explanation, Difficulty, Points, RowVersion, Soft Delete), `LearningAttempt` (Nummer, Status, StartedAt, DeadlineAt, SubmittedAt, AutoSubmitted, ItemOrder, Ergebnis/Note, RowVersion), `LearningAnswer` (Antwort, Verdict Open/Correct/Partial/Wrong, Grader Auto/Ai/Parent, AwardedPoints, Reason); `PointsLedgerEntry.LearningSetId` – ADR-0021 |
| Betrieb | `AuditLogEntry` ✅ (ActorName, Action, TargetType/Id/Name, Details, CreatedAt), `PushSubscription` ✅ (UserId, Endpoint + Hash, P256dh, Auth, LastSuccessAt, FailureCount) |
## 4. Rollen- und Berechtigungsmodell
@@ -114,6 +115,8 @@ oder **None (–)**. Die Api registriert je Permission eine Policy `Permission:<
| `FamilyChat` | F | F | F | – ² | |
| `DirectMessages` | F | F | R | – | nur an Familienmitglieder |
| `AiUse` | F | F | – | – | KI-Funktionen nutzen (ADR-0020) |
| `LearningManage` | F | F | – | – | Übungsblätter anlegen/zuweisen/prüfen/bestätigen (ADR-0021) |
| `LearningSolve` | F | F | R | – | Kind: nur eigene, zugewiesene Blätter lösen; fremde → 404 (ADR-0021) |
| `UserManagement`, `CalendarManagement`, `SettingsManagement`, `AuditLogView` | F | – | – | – | |
¹ `F`, wenn „Gäste dürfen die Einkaufsliste ergänzen/abhaken“ aktiviert ist. ² `F`, wenn „Gäste dürfen den Familienchat nutzen“ aktiviert ist.
@@ -153,8 +156,9 @@ Das UI bekommt die wirksamen Berechtigungen über `/api/auth/me` und blendet anh
| ICS-Feed | `GET /ics/{token}.ics` (öffentlich, Token-gesichert, ETag/Last-Modified) |
| Chat ✅ | `GET /api/chat/channels`, `POST /api/chat/direct`, `GET /api/chat/channels/{id}/messages?before=&take=`, `POST …/messages`, `POST …/images` (Multipart), `POST …/read`, `DELETE /api/chat/messages/{id}`, `PUT /api/chat/messages/{id}/reactions`, `GET /api/chat/attachments/{id}` (ADR-0019) |
| KI ✅ | Admin: `GET/POST /api/admin/ai/providers`, `PUT/DELETE …/{id}`, `POST …/{id}/test`, `GET /api/admin/ai/usage`; Eltern: `GET /api/ai/status` (ADR-0020) |
| Lernen ✅ (10a) | Eltern (`LearningManage`): `GET/POST /api/learning/sets`, `GET/PUT/DELETE …/sets/{id}`, `POST …/sets/{id}/assign`, `POST …/unassign`, `POST …/sets/{id}/items`, `PUT/DELETE …/items/{itemId}`, `POST …/items/order`, `GET /api/learning/review`, `GET /api/learning/attempts/{id}`, `PUT …/attempts/{id}/answers/{itemId}/review`, `POST …/attempts/{id}/confirm`, `POST …/attempts/{id}/reopen`; Kinder (`LearningSolve`): `GET /api/learning/my`, `POST …/my/{setId}/attempts`, `GET …/my/attempts/{id}`, `PUT …/my/attempts/{id}/answers/{itemId}`, `POST …/my/attempts/{id}/submit` (ADR-0021) |
| Dashboard ✅ | `GET /api/dashboard` (alle Kacheln der Rolle in einem Request, ADR-0018) |
| Hubs | `/hubs/live` (Live-Updates: Einkauf ✅, Essenplan ✅, Aufgaben ✅, Termine ✅, Chat ✅ inkl. Hub-Methode `Typing`; das Dashboard lädt bei diesen Ereignissen neu) |
| Hubs | `/hubs/live` (Live-Updates: Einkauf ✅, Essenplan ✅, Aufgaben ✅, Termine ✅, Chat ✅ inkl. Hub-Methode `Typing`, Lernen ✅ (`LearningChanged` ohne Inhalte); das Dashboard lädt bei diesen Ereignissen neu) |
| Betrieb | `/health`, `/alive` |
## 7. Frontend
@@ -173,6 +177,7 @@ SignalR-Hub `/hubs/live` in der Api, vom Web-Host per YARP (WebSockets) durchger
`family` (ohne Gäste), `user:{id}`. Der Chat nutzt keine Kanal-Gruppen, sondern sendet an die `user:{id}` der jeweils aktuell Berechtigten (ADR-0019). Slices senden nach dem Speichern über `IHubContext<LiveHub>`
Ereignisse mit dem vollständigen DTO (z. B. `ShoppingItemChanged`), die Clients aktualisieren gezielt ihre Ansicht.
Aufgaben gehen wegen privater Aufgaben nur an `user:{id}` der Benutzer, die sie sehen dürfen (`TaskChanged`/`TaskRemoved`, ADR-0014).
Lern-Ereignisse (`LearningChanged(setId, kind)`) enthalten **keine Inhalte** und gehen nur an die Zielperson und alle Eltern (`user:{id}`, `LearningNotifier`, ADR-0021); die Clients laden über die geschützten Endpunkte nach.
Der Client (`LiveConnection`) verbindet sich mit unbegrenzten Wiederholungen neu und lädt danach den aktuellen Stand.
## 8a. Offline
+10 -4
View File
@@ -118,10 +118,16 @@ Legende: `[x]` erledigt, `[ ]` offen. Nach jeder Phase: Build ohne Warnungen, Te
- [x] Tests: Unit (Adressen/Heimnetz/Schlüsselpflicht/Limits/Zwecke/Validator, Adapter gegen Fake-Handler inkl. Fehlerübersetzung und JSON-Extraktion), bUnit (Verwaltung, Dialog, Test, Nutzung, Löschen), Integration (Rechte, Validierung, Schlüsselschutz, Zweck-Übernahme, Verbindungstest gegen Fake-Anbieter inkl. Timeout, OpenAI-Format, Tageslimit + Protokoll)
## Phase 10 – Lernaufgaben (ADR-0021)
- [ ] 10a: Übungsblätter manuell anlegen/zuweisen, Kind löst digital (Zahl/Auswahl/Text), automatische Bewertung ohne KI, Elternprüfung, Kinderansicht, Dashboard-Kachel, optional Punkte über das Punktebuch
- [ ] 10b: KI-Erzeugung per Prompt (z. B. „20 Aufgaben Mathe, 3. Klasse, leicht bis schwer“) als Entwurf, Eltern prüfen/ändern vor dem Zuweisen, Mathe-Lösungen serverseitig nachrechnen
- [ ] 10c: Papierlösung per Foto (Upload je Aufgabe/Blatt), Prüfung manuell durch Eltern, danach KI-Prüfung mit Sicherheitsangabe und Eltern-Bestätigung
- [ ] Rechte `LearningManage`/`LearningSolve`: Kinder sehen nur eigene Blätter, nie Musterlösungen oder Prompts (serverseitig); Foto-Aufbewahrungsfrist
- [x] 10a: Übungsblätter manuell anlegen/zuweisen (Entwurf → Zugewiesen → In Arbeit → Abgegeben → Geprüft), Editor für Blatt und Aufgaben (Zahl/Text/Auswahl, Hinweis, Erklärung, Schwierigkeit, Punkte), Versionsprüfung (409), Bearbeitungssperre nach dem ersten Versuch; Migration `Phase10aLearning`
- [x] 10a: Kind löst digital (eigene Blätter, Versuch starten/fortsetzen, Antworten zustandsbasiert speichern, Fortschritt, Abgabe-Bestätigung, Ergebnis mit Lösungen nur nach Regel), automatische Bewertung ohne KI (Zahlenformate mit Komma/Punkt/Tausender, Toleranz, Auswahl, Freitext exakt oder offen), Elternprüfung (Warteschlange, Korrektur, Teilpunkte, Begründung, Bestätigen, erneut öffnen)
- [x] 10a: Wiederholen (`MaxAttempts`, 0 = unbegrenzt), Zeitlimit serverseitig (Frist in der Datenbank, 10 s Toleranz, 409 bei späten Speicherungen, automatische Abgabe lazy und per Hintergrunddienst), Prüfungsmodus (keine Sofort-Rückmeldung/Hinweise/Lösungen bis zur Abgabe, optional gemischt und stabil je Versuch, Countdown nach Serveruhr, Auto-Abgabe), Note nach Notenschlüssel
- [x] 10a: Punkte über das Punktebuch (anteilig, beste Wertung zählt einmal, Differenz wird gebucht, Rückbuchung beim erneuten Öffnen, Audit, Live `PointsChanged`), Dashboard-Kachel „Lernen“ (Kind: offene Blätter, Eltern: zu prüfen), Live `LearningChanged` nur an Zielperson und Eltern
- [x] 10a: Rechte `LearningManage`/`LearningSolve` in der Matrix (Kinder nur eigene Blätter, fremde → 404, nie Musterlösung/Hinweis/Prompt vorab; serverseitig erzwungen), Navigation „Lernen“, Seiten und Komponenten (mobil, Touch-Ziele, ARIA)
- [x] 10a: Tests: Unit (Zahlenformate, Auto-Bewertung, Zeitlimit, Wiederholen, Punkte-Differenz, Noten, Prüfungsregeln, Kinder-DTO-Sichtbarkeit, Matrix, Validatoren), bUnit (Kinderansicht, Prüfungs-Runner mit steuerbarer Uhr, Elternansicht, Editor, Prüfung, Rechte, Dashboard-Kachel), Integration (Rechte je Rolle inkl. 404, Lösungen-Leck, Auto-Bewertung, Zeitlimit-409 mit echtem Warten, Wiederholungen, Punkte-Workflow inkl. Rückbuchung, Live nur an Berechtigte)
- [ ] 10a offen: „Aufgaben aus früheren Blättern wiederverwenden“, Verknüpfung eines Blatts mit einer Familienaufgabe/einem Ämtchen, Standard-Wiederholungen als Familieneinstellung (aktuell Voreinstellung im Editor)
- [ ] 10b: KI-Erzeugung per Prompt (z. B. „20 Aufgaben Mathe, 3. Klasse, leicht bis schwer“) als Entwurf, Eltern prüfen/ändern vor dem Zuweisen, Mathe-Lösungen serverseitig nachrechnen (Spalten für Herkunft/Prompt/Anbieter/Modell am Blatt sind vorhanden)
- [ ] 10c: Papierlösung per Foto (Upload je Aufgabe/Blatt), Prüfung manuell durch Eltern, danach KI-Prüfung mit Sicherheitsangabe und Eltern-Bestätigung (`LearningAnswerType.Paper`, `LearningGrader.Ai` sind als Werte vorgesehen)
- [ ] Foto-Aufbewahrungsfrist (Standard 30 Tage nach Prüfung, einstellbar) – mit 10c
## Phase 11 – Härtung
- [ ] Content-Security-Policy (Basis-Header X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, HSTS sind seit Phase 1 aktiv)
+4 -1
View File
@@ -4,7 +4,7 @@
* Datum: 2026-10-10
## Kontext
Die Startseite zeigt Kacheln aus fünf Fachbereichen (Essenplan, Kalender, Einkauf, Aufgaben, Chat). Rollen sehen unterschiedliche
Die Startseite zeigt Kacheln aus sechs Fachbereichen (Essenplan, Kalender, Einkauf, Aufgaben, Chat, Lernen). Rollen sehen unterschiedliche
Kacheln („Gast: eingeschränkte Kacheln“, Familien-/Kinderaufgaben nur für Eltern). Auf dem Smartphone zählen wenige Requests.
## Entscheidung
@@ -25,6 +25,9 @@ Kacheln („Gast: eingeschränkte Kacheln“, Familien-/Kinderaufgaben nur für
6. **Offline**: Bei Fehlern bleibt der zuletzt geladene Stand mit Hinweis sichtbar; ohne Stand gibt es „Erneut versuchen“.
7. **Chat** (Phase 8, ADR-0019): Die Kachel erscheint für Rollen mit Chat-Rechten und zeigt die Summe der ungelesenen Nachrichten über alle sichtbaren Kanäle
(`ChatAccessService.TotalUnreadAsync`); die Seite lädt bei Chat-Ereignissen (neue Nachricht, gelöscht, gelesen) neu.
8. **Lernen** (Phase 10a, ADR-0021): `DashboardDto.Learning` (letzter Konstruktorparameter, standardmäßig `null`). Eltern (`LearningManage`) sehen die Zahl der abgegebenen, noch nicht bestätigten Versuche und die offenen Blätter der Kinder, die ältesten
Abgaben (höchstens fünf) verlinken direkt auf die Prüfung; Kinder sehen ihre offenen Blätter (zugewiesen oder in Arbeit) mit Fälligkeit, ein laufender Versuch verlinkt auf „Weitermachen“. Gäste und Rollen ohne Recht erhalten keine Kachel. Die Seite lädt
bei `LearningChanged` neu (ohne Inhalte, nur an Zielperson und Eltern).
## Folgen
* Ein Request je Seitenaufruf; Kosten wachsen mit der Familiengröße, nicht mit der Datenmenge (Aufgaben: nicht erledigte, Termine: zwei Tage).
+74 -1
View File
@@ -1,6 +1,6 @@
# ADR-0021: Lernaufgaben – manuell oder per KI, digital oder auf Papier
* Status: akzeptiert (Phase 10; Entscheidungen der Rückfragen am 2026-10-10 eingearbeitet)
* Status: akzeptiert (Phase 10; Entscheidungen der Rückfragen am 2026-10-10 eingearbeitet) – **Phase 10a umgesetzt** (Abschnitt „Umsetzung Phase 10a“), 10b und 10c offen
* Datum: 2026-10-10
## Kontext
@@ -60,6 +60,79 @@ Lernaufgaben sind **kein** Teil der Familienaufgaben (ADR-0014): eigene Entität
Papier-Prüfungen: Foto-Abgabe innerhalb des Zeitfensters.
Im Übungsmodus (`Practice`) gibt es Sofort-Rückmeldung und Hinweise.
## Umsetzung Phase 10a (2026-10-10)
Phase 10a liefert manuell erstellte Übungsblätter, digitales Lösen, automatische Bewertung, Elternprüfung, Punkte und den Prüfungsmodus – **ohne KI (10b) und ohne Foto/Papier (10c)**.
Migration `Phase10aLearning`. Reine Regeln liegen in `FamilyPlanner.Domain/Learning` (identisch in Api und Client), der Slice in `Api/Features/Learning`, DTOs und Validatoren in `Shared/Learning`,
die Oberfläche in `Web.Client/Components/Learning` und `Pages/Learning*.razor`.
### Modell
* `LearningSet` (Soft Delete, `RowVersion`): Titel, Fach als Text aus `LearningSubjects` (Mathe, Deutsch), Klassenstufe 1–6, `TargetUserId` (Rolle Kind, bloße Id ohne Fremdschlüssel wie bei Aufgaben), `DueDate`,
`Status` (Entwurf → Zugewiesen → In Arbeit → Abgegeben → Geprüft), `Mode` (`Practice`/`Exam`), `MaxAttempts` (0 = unbegrenzt), `TimeLimitMinutes` (`null` = keins), `ShowSolutionsAfterSubmit`, `ShuffleItems`,
`TotalPoints` (0 = keine Punkte), `GradeThresholds` (Notenschlüssel, `null` = Standard), `Source` (`Manual`|`Ai`) sowie `AiPrompt`/`AiProvider`/`AiModel` (**für 10b schon angelegt**, vom Client nicht setzbar),
`AssignedAt`, `ItemsRevision` (Zähler, damit Aufgabenänderungen und ein gleichzeitiger Versuchsstart über die `RowVersion` des Blatts kollidieren).
* `LearningItem` (Soft Delete, `RowVersion`): `SortOrder`, `Question`, `AnswerType` (`Number`, `Text`, `SingleChoice`; `Paper` nur als Enum-Wert, der Validator lehnt ihn in 10a ab), `CorrectAnswer`
(Zahl, Text – Varianten mit `|` – oder Index der richtigen Option), `NumberTolerance` (absolut), `Options` (2–6, JSON-Liste), `Hint` und `Explanation` (zwei Felder statt „Hinweis/Erklärung“), `Difficulty` 1–3, `Points` 1–20.
* `LearningAttempt` (`RowVersion`): `Number`, `Status` (Läuft/Abgegeben/Bestätigt), `StartedAt`, `DeadlineAt`, `LastActivityAt`, `SubmittedAt`, `AutoSubmitted`, `ItemOrder` (Aufgaben-Ids dieses Versuchs, ggf. gemischt),
`ReviewedAt/By`, `EarnedPoints`, `TotalItemPoints`, `Grade`, `ReviewNote`. `LearningAnswer`: `Value`, `Verdict` (`Open`/`Correct`/`Partial`/`Wrong`), `Grader` (`Auto`/`Ai`/`Parent`), `AwardedPoints`, `Reason`.
Eindeutige Indizes: (Blatt, Kind, Nummer) und **höchstens ein laufender Versuch** je Blatt und Kind (gefiltert auf `InProgress`) – Doppelklick oder zwei Tabs können weder `MaxAttempts` umgehen noch die Prüfungsuhr zurücksetzen.
`LearningAnswer.ItemId` ist bewusst keine Beziehung (SQL Server erlaubt keine zweiten Kaskadenpfade; Aufgaben ändern sich nach dem ersten Versuch nicht mehr).
* `PointsLedgerEntry.LearningSetId` (neu, nullable): Buchungen zu einem Blatt; der Punktestand bleibt die Summe des Punktebuchs.
### Regeln (alle unit-getestet)
* **Auto-Bewertung** (`LearningGrading`): Zahlen werden kulturunabhängig gelesen (Komma/Punkt als Dezimalzeichen, Punkt/Komma/Leerzeichen als Tausendertrenner, Unicode-Minus); „1.234“ ist mehrdeutig und passt, wenn
**eine** Lesart zur Musterlösung passt; Toleranz absolut; Brüche („1/2“) werden **nicht** erkannt (→ falsch, Eltern können korrigieren). Auswahl vergleicht den Index. Freitext ist nur bei **exakter Übereinstimmung nach Normalisierung**
(Unicode, Leerraum, Groß/Klein, Randzeichen, Varianten mit `|`) automatisch richtig, sonst `Open` für die Elternprüfung – nie automatisch falsch. Leere Antworten sind immer falsch.
* **Zeitlimit serverseitig** (`LearningRules`): `DeadlineAt` = Start + Limit wird beim Start in der Datenbank festgelegt. Speicherungen gelten bis **Frist + 10 s Toleranz**; danach antwortet die Api mit **409**, der Versuch wird automatisch
abgegeben (`SubmittedAt` = Frist, `AutoSubmitted`), nur zuvor gespeicherte Antworten zählen. Die Abgabe selbst ist idempotent und nie ein 409. Automatische Abgabe passiert **lazy** bei jedem Zugriff (Kind: Liste/Versuch/Speichern/Starten,
Eltern: Liste/Warteschlange/Versuch) und per Hintergrunddienst `LearningExpiryService` (alle 30 s), damit verlassene Prüfungen in der Warteschlange landen. Der Client rechnet den Countdown aus `DeadlineAt` und dem Uhrenabgleich (`ServerNow`),
nicht aus der Geräteuhr.
* **Sichtbarkeit** (`LearningRules.VisibilityFor`, einzige Quelle für Kinder-DTOs): Übung – Hinweise und Sofort-Rückmeldung (nur richtig/falsch/offen, **nie** die Lösung) während der Bearbeitung; Prüfung – während der Bearbeitung **nichts**
(Speicherantwort ohne Bewertung, kein Hinweis); nach der Abgabe immer die Bewertung, die Lösung samt Erklärung nur bei „Lösungen nach Abgabe zeigen“, Hinweise nur in der Übung. Kinder-DTOs sind eigene Typen ohne Felder für Prompt, Anbieter
oder Modell; `CorrectAnswer`/`Explanation` stehen nur im optionalen `Feedback`. Kommentare der Eltern erreichen das Kind erst nach der Abgabe, Meldungen der Automatik nie als „Kommentar“.
* **Reihenfolge:** gemischt wird deterministisch aus SHA-256 von Versuchs- und Aufgaben-Id (`string.GetHashCode` wäre je Prozess zufällig) und in `ItemOrder` gespeichert – stabil je Versuch, zwischen Versuchen wechselnd.
* **Status** wird aus den Versuchen abgeleitet (`DeriveStatus`): läuft einer → In Arbeit, sonst wartet einer → Abgegeben, sonst bestätigt → Geprüft, sonst Zugewiesen.
* **Elternprüfung:** Antworten bewerten (`Correct`/`Partial`/`Wrong`, Teilpunkte 1 bis Aufgabenpunkte − 1, Begründung), auch die der Automatik korrigieren; **Bestätigen** erst ohne offene Antworten (409). Auch vollautomatisch bewertete Blätter
werden bestätigt – erst dann gibt es Punkte und Note. „Erneut öffnen“ macht den Versuch wieder prüfbar.
* **Punkte:** Anteil = erreichte Aufgabenpunkte / mögliche; Gutschrift = **beste bestätigte Wertung** × `TotalPoints`, kaufmännisch auf ganze Punkte gerundet (halbe aufwärts, reine Ganzzahlrechnung). Gebucht wird nur die **Differenz zum bisher für das
Blatt gebuchten Stand** (`SyncPointsAsync`): Gutschrift, Verbesserung oder Rückbuchung – dadurch idempotent (zweimal bestätigen bucht nichts), und Erneut-Öffnen fällt auf die nächstbeste Wertung zurück. Audit-Einträge
`learning.points_credited`/`learning.points_reversed`, Live-Ereignis `TaskPointsChanged` an die Familie. Ist `ChorePointsEnabled` aus, wird nichts gebucht. Das Löschen eines Blatts lässt bereits gutgeschriebene Punkte bestehen (wie bei Ämtchen,
ADR-0014); Korrekturen über die Punkteverwaltung.
* **Note** (nur Prüfungen, nach Bestätigung): Schwellen für die Noten 1–5 in Prozent, Standard `92;81;67;50;30`, darunter 6 (ganzzahliger Vergleich ohne Rundungsfehler); einstellbar je Blatt, streng absteigend.
* **Bearbeitungssperre:** Aufgaben lassen sich nur ändern, solange es keinen Versuch gibt; danach sind auch Kind, Modus, Mischen, Gesamtpunkte und Notenschlüssel fest (409). Titel, Fälligkeit, Zeitlimit, Versuche und „Lösungen zeigen“ bleiben änderbar.
### Rechte
`LearningManage` (Admin F, Familie F, Kind –, Gast –) und `LearningSolve` (Admin F, Familie F, Kind R, Gast –). Blätter lassen sich nur **Kindern** zuweisen; gelöst wird ausschließlich von der Zielperson (`LearningRules.CanSolve`) – auch Eltern lösen
nicht für andere: fremde Blätter und Versuche antworten mit **404**, Entwürfe sind für das Zielkind unsichtbar. Kinder auf Verwaltungsendpunkten und Gäste überall erhalten 403 (Policy). Objektbezogene Prüfungen im Slice, nie nur im UI.
### Schnittstellen und Oberfläche
* Eltern (`/api/learning`): `GET/POST /sets` (POST optional mit `Items`), `GET/PUT/DELETE /sets/{id}`, `POST …/assign`, `POST …/unassign`, `POST …/items`, `PUT/DELETE …/items/{itemId}`, `POST …/items/order`, `GET /review` (Warteschlange),
`GET /attempts/{id}`, `PUT /attempts/{id}/answers/{itemId}/review`, `POST …/confirm`, `POST …/reopen`. Versionsprüfung mit 409 und aktuellem Stand bei Blatt und Aufgabe.
* Kinder (`/api/learning/my`): `GET /`, `POST /{setId}/attempts` (startet oder setzt fort), `GET /attempts/{id}`, `PUT /attempts/{id}/answers/{itemId}` (zustandsbasiert, idempotent, 409 bei abgegeben/abgelaufen), `POST /attempts/{id}/submit`.
* Live: `LearningChanged(setId, kind)` **ohne Inhalte** an `user:{id}` der Zielperson und aller Eltern (`LearningNotifier`); Clients laden über die geschützten Endpunkte nach. Dashboard: Kachel „Lernen“ (`DashboardDto.Learning`).
* UI: Navigation „Lernen“ (Admin/Familie/Kind), Routen `/lernen`, `/lernen/neu`, `/lernen/blatt/{id}`, `/lernen/versuch/{id}`, `/lernen/pruefen/{id}`. Kind: Karten, **Prüfungs-Runner** (`AttemptRunner`) mit Countdown, Fortschritt,
Aufgaben-Navigation, serialisiertem Speichern, Abgabe-Bestätigung und Auto-Abgabe (Wiederholung bei Netzfehlern); Eltern: Übersicht, Editor (`SetEditor`, `ItemEditDialog`), Prüfung (`AttemptReview`).
### Abweichungen und bewusste Vereinfachungen
* **Standard-Wiederholungen** sind eine Voreinstellung im Editor (Übung: unbegrenzt, Prüfung: 1 Versuch ohne Lösungen), keine Familieneinstellung – das hätte DTO, Validator, Verwaltung und Tests berührt.
* Kein eigenes Feld „Schwierigkeitsverlauf“ am Blatt (ergibt sich aus den Schwierigkeiten der Aufgaben; relevant für den Prompt in 10b). Keine Verknüpfung mit einer Familienaufgabe/einem Ämtchen: Punkte laufen direkt über das Punktebuch. „Aufgaben aus früheren Blättern
wiederverwenden“ ist nicht umgesetzt.
* Die Elternbestätigung ist immer nötig (auch bei vollautomatischer Bewertung); Punkte und Note gibt es erst danach, das Kind sieht bis dahin ein vorläufiges Ergebnis.
* Sofort-Rückmeldung in der Übung bedeutet: Das Kind kann eine Antwort ändern, bis es abgibt; gewertet wird der letzte Stand. Die Übung ist ein Lernrahmen, keine Prüfung.
* Das Zeitlimit hat mindestens 1 Minute; die Toleranz (10 s) ist fest.
### Erweiterungspunkte für 10b (KI-Erzeugung)
* Die Spalten `Source`, `AiPrompt`, `AiProvider`, `AiModel` am `LearningSet` existieren; `POST /api/learning/sets` setzt immer `Manual`. 10b ergänzt einen eigenen Endpunkt in `Features/Learning` (z. B. `POST /api/learning/sets/ai-draft`, Policy `LearningManage` + `AiUse`),
der über `AiService.RunAsync(…, AiPurpose.LearningGeneration, …)` Aufgaben als strukturiertes JSON holt, jede Aufgabe mit `LearningItemInputValidator` und `LearningItemRules.CheckSolution` prüft, Zahlenlösungen mit `LearningNumbers`/`LearningGrading.Grade`
nachrechnet und das Ergebnis über denselben Pfad wie `LearningManageEndpoints.CreateSetAsync` als **Entwurf** mit `Source = Ai` speichert. Zuweisen bleibt der bestehende Schritt (`assign`).
* UI: ein Assistent-Dialog in `ParentOverview` (Knopf „Mit KI erstellen“, sichtbar anhand `GET /api/ai/status`), Ergebnis öffnet `SetEditor` im Entwurf; `ILearningApi` bekommt eine Methode dafür.
### Erweiterungspunkte für 10c (Papierlösung per Foto)
* `LearningAnswerType.Paper`, `LearningVerdict.Open` und `LearningGrader.Ai` sind vorhanden; `LearningGrading.Grade` liefert für `Paper` bereits `Open`, `LearningItemRules.IsSupported` und `CheckSolution` müssen `Paper` freischalten (Validator und Editor-Auswahl).
* Neue Entität `LearningPhoto` (Bytes in der Datenbank, an Versuch/Aufgabe gebunden, Signaturprüfung, Aufbewahrungsfrist) und Endpunkte unter `/api/learning/my/attempts/{id}/…` (Hochladen) bzw. `/api/learning/attempts/{id}/…` (Abruf nur für Eltern/Kind); `AttemptRunner`
bekommt für `Paper`-Aufgaben ein Upload-Feld statt Texteingabe, `AttemptReview` zeigt das Foto neben Aufgabe und Musterlösung. Die KI-Prüfung (`AiPurpose.LearningImageGrading`) schreibt `Verdict`, `Grader = Ai`, `Reason` und eine Sicherheitsangabe
(neue Spalte) in `LearningAnswer`; bestätigt wird weiterhin über `confirm`. Zeitfenster und Abgabe-Logik (`Submit`, `LearningExpiryService`) bleiben unverändert.
## Bewusst nicht Teil des ersten Schnitts
Offline-Lösen, Sprachausgabe/Diktat, Lernstatistiken über Wochen, Adaptive Schwierigkeit, Formeleditor (Aufgaben bleiben Text), Auswertung mehrerer Kinder im Vergleich,
Überwachung gegen Schummeln (die Emulation ist ein Übungsrahmen, keine Fernprüfung).