docs: describe the meal wishlist in ADR-0013, architecture and roadmap

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
JannisandClaude Sonnet 5.5 committed 2026-10-10 18:56:58 +02:00
1 parent 5ce407f401
commit 19269277e2
3 files changed
+26 -2

No files matched your search

+1 -1
View File
@@ -82,7 +82,7 @@ Alle Zeitpunkte werden als UTC (`DateTimeOffset`/`DateTime` UTC) gespeichert und
| Identity ✅ | `AppUser` (DisplayName, Color, AvatarUrl, MustChangePassword, IsActive, ExpiresAt, PinHash, LastLoginAt, Soft Delete), `AppRole` (Admin, Familie, Kind, Gast), `UserAvatar` (Bild ≤ 1 MB) |
| Einstellungen ✅ | `FamilySettings` (FamilyName, TimeZoneId, MealPlanDays (7–10), MealTypes, TaskCategories, ChorePointsEnabled, ChildTasksRequireApproval, GuestsCanEditShoppingList, GuestChatEnabled) |
| Einkauf ✅ | `ShoppingList` (Name, IsDefault, SortOrder, Soft Delete), `ShoppingItem` (Client-Id, Name, Quantity, Category, IsDone, DoneAt, DoneBy, RowVersion, Soft Delete), `ShoppingSuggestion` (Name, Category, CategoryIsManual, UseCount, LastUsedAt) |
| Essen ✅ | `MealPlanEntry` (Date als `DateOnly`, MealType, DishName, Note, RecipeUrl, Ingredients, WishId, RowVersion, Soft Delete; eindeutig je Tag + Mahlzeit), `Dish` (Name, RecipeUrl, Ingredients, UseCount – für Autovervollständigung), `MealWish` (DishName, Note, Wunschtag/-mahlzeit, Status offen/übernommen/abgelehnt, Soft Delete) |
| Essen ✅ | `MealPlanEntry` (Date als `DateOnly`, MealType, DishName, Note, RecipeUrl, Ingredients, WishId, RowVersion, Soft Delete; eindeutig je Tag + Mahlzeit), `Dish` (Name, Note, RecipeUrl, Ingredients, UseCount = Planungen, WishCount, WishedBy, LastPlannedAt, Soft Delete; eindeutiger NormalizedName – dauerhafte Wunschliste und Autovervollständigung, `/api/meals/wishlist`), `MealWish` (DishName, Note, Wunschtag/-mahlzeit, Status offen/übernommen/abgelehnt, Soft Delete) |
| Aufgaben ✅ | `TodoTask` (Title, Notes, DueDate + DueTime → DueAt, ReminderMinutesBefore → RemindAt, Priority, Status inkl. „wartet auf Bestätigung“, Category, IsPrivate, IsChore, Points, NeedsApproval, AssignedToFamily, RecurrenceRule + RecurrenceMode, SeriesId/SeriesStart/SeriesIndex, CompletedBy/At, ApprovedBy/At, RowVersion, Soft Delete), `TaskAssignment`, `TaskChecklistItem`, `TaskHistoryEntry` (Verlauf), `PointsLedgerEntry` (Punktebuch). Kategorien kommen aus `FamilySettings.TaskCategories`; „wer/wann/genehmigt“ steht an der Aufgabe und im Verlauf (ADR-0014) |
| 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 |
+3 -1
View File
@@ -140,6 +140,9 @@ Legende: `[x]` erledigt, `[ ]` offen. Nach jeder Phase: Build ohne Warnungen, Te
- [ ] Tests vervollständigen (Policies, ICS, Wiederholungen, Integration)
- [ ] Barrierefreiheit (WCAG 2.1 AA), Performance (AOT/Trimming prüfen, Lazy Loading)
## Phase 11d – Essen: Wunschliste
- [x] Essen: Wunschliste – Wünsche und bereits hinterlegte Gerichte landen in einer dauerhaften, durchsuchbaren Wunschliste und lassen sich jederzeit wieder in den Plan übernehmen (Migration `Phase11dMealWishlist`, ADR-0013)
## Phase 12 – Deployment
- [ ] Finale `docker-compose.yml` (inkl. optionalem Caddy), `.env.example`
- [ ] Backup-/Restore-Skripte
@@ -162,7 +165,6 @@ Legende: `[x]` erledigt, `[ ]` offen. Nach jeder Phase: Build ohne Warnungen, Te
- Chat: GIF-/Meme-Suche (Anbieter und Datenschutz klären, z. B. nur über den Server abfragen, keine Weitergabe von Kinderdaten)
- Chat: Emoji-Auswahl (Button neben „Bild senden“)
- Chat: KI-Chat als zusätzlicher Kanal (z. B. „KI-Chat“ unter „Familienchat“): Chattext wird zum Prompt, die Antwort erscheint im Verlauf; Admin schaltet ihn ein/aus und legt fest, welche Anbieter/Modelle auswählbar sind (neuer `AiPurpose`, Tageslimit und Datenschutz-Opt-in aus ADR-0020; Kinder-Schutz: Rechte, Inhaltsfilter, Protokoll ohne Inhalt klären)
- Essen: Wunschliste – Wünsche und bereits hinterlegte Gerichte landen in einer dauerhaften, durchsuchbaren Wunschliste und lassen sich jederzeit wieder in den Plan übernehmen
- Lernen: tolerantere Antwort-Auswertung für Zahlen mit Einheiten und Schreibweisen (z. B. „1€ 30 Cent“ = „1,30“, „2 Euro 50“); unklare Fälle optional zur Gegenprüfung an die KI (Purpose und Opt-in aus ADR-0020), Ergebnis bleibt Vorschlag, Eltern bestätigen
- Lernen: Kind sieht die Note auch auf dem Lernzettel selbst (Kopfbereich des Blatts/Ergebnisansicht), nicht nur in der Liste
- Lernen: Übungsblätter automatisch erzeugen (Zeitplan je Kind, z. B. täglich/wöchentlich 10 neue Aufgaben, Schwierigkeit steigt schrittweise; Hintergrunddienst, nur Eltern konfigurieren, Tageslimit der KI beachten, Entwürfe bleiben prüfbar oder werden nach Eltern-Einstellung direkt zugewiesen)
+22
View File
@@ -58,3 +58,25 @@ Verbindungsverlust zeigt die Seite den Offline-Status und lädt nach dem Wiederv
* Tauschen statt Ablehnen macht Drag & Drop ohne Rückfragen nutzbar; ein Tausch erzeugt zwei Live-Ereignisse.
* Wünsche sind ein eigener, einfacher Workflow (offen → übernommen/abgelehnt) ohne Abstimmungen oder Kommentare.
* Eine Rezeptdatenbank bleibt im Backlog; der Gerichtekatalog merkt sich nur die letzten Angaben je Gericht.
## Nachtrag Phase 11d: dauerhafte Wunschliste
* **Datenmodell:** Der Gerichtekatalog `Dish` wird zur dauerhaften Wunschliste. Der eindeutige `NormalizedName` (kleingeschrieben,
getrimmt) dedupliziert; neu sind `Note`, `WishedBy` (letzter Wünscher), `WishCount` (Anzahl Wünsche), `LastPlannedAt` (nullable,
`null` = nie geplant) und Soft Delete (`ISoftDeletable`). `UseCount` zählt weiterhin die Planungen. Der eindeutige Index auf
`NormalizedName` ist bewusst **nicht gefiltert**: Ein gelöschtes Gericht wird bei erneutem Wunsch oder Planen per
`IgnoreQueryFilters()` gefunden und reaktiviert (`Dish.Restore()`), statt ein Duplikat anzulegen.
* **Migration `Phase11dMealWishlist`:** ergänzt die Spalten, füllt `LastPlannedAt` aus `LastUsedAt` (wo `UseCount > 0`), trägt
geplante Einträge nach, die im Katalog fehlen, und legt offene/übernommene Essenswünsche als Gerichte an (dedupliziert über
`lower(trim(DishName))`, `WishCount` = Anzahl der Wünsche). Alles reines T-SQL, ohne Daten lauffähig.
* **Api:** `POST /api/meals/wishes` legt das Gericht zusätzlich an bzw. erhöht `WishCount` (Fehler dabei brechen den Wunsch nicht ab).
`GET /api/meals/wishlist?q=&sort=lastPlanned|mostPlanned|name` (`MealPlanRead`; Familie, Admin und Kinder, Gäste 403;
unbekannte Sortierung = `lastPlanned`, nie Geplantes steht hinten). `POST /api/meals/wishlist/{id}/plan` (Tag + Mahlzeit,
optional `Replace`, 409 bei belegtem Platz; `MealPlanEdit` + `CanEditPlan`, Kinder 403) erzeugt den Plan-Eintrag mit Rezeptlink,
Zutaten und Notiz des Gerichts und zählt `UseCount`/`LastPlannedAt` hoch. `DELETE /api/meals/wishlist/{id}` (Soft Delete,
idempotent): Familie/Admin alles, Kinder nur selbst gewünschte Gerichte, die nie geplant wurden
(`MealPlanRules.CanDeleteWishlistEntry`, objektbezogen geprüft und getestet). Änderungen melden `MealWishesChanged`.
* **Oberfläche:** Abschnitt „Wunschliste“ auf der Essenplan-Seite mit Suchfeld, Sortierung (zuletzt geplant / am häufigsten / A–Z)
und „In den Plan“-Dialog (`MealSlotPicker`, Ersetzen nur nach Rückfrage).
* **Offen:** Ein offener Essenswunsch bleibt offen, wenn dasselbe Gericht direkt aus der Wunschliste geplant wird; die Wunschliste
hat keine Seitenblätterung (höchstens 500 Treffer, Standard 200).