#101 — Vorratsschrank — Labels, Kommentare, Aktivitäts-Feed, CSV-Import/-Export #100
Labels
No labels
priority/could
priority/must
priority/should
priority/wont
status/blocked
status/claimed
status/done-migrated
type/bug
type/feature
type/infra
type/tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/todo#100
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Story: Vorratsschrank — Labels, Kommentare, Aktivitäts-Feed, CSV-Import/-Export
Depends on:
#94(Vorratsschrank Phase 1 — liefert den Listentyp selbst).As a Haushaltsmitglied,
I want to Pantry-Artikel mit Labels versehen, kommentieren können, nachvollziehen können, wer wann
was ein-/ausgecheckt hat, und den Bestand als CSV sichern/importieren können,
so that der Vorratsschrank dieselbe Feature-Tiefe wie Todos/Einkaufsliste erreicht.
Hintergrund:
#94's Architect-Entscheidung hat diese Punkte bewusst aus Phase 1 herausgenommen, daLabelEntity/CommentEntity/ActivityEventEntityin diesem Repo aktuell hart anTodoListId/TodoNrgebunden sind (keine polymorphe Struktur) — für Pantry braucht es strukturelle Kopien nach demselben Muster,
das
#89für Shopping Lists' Sharing-Entities verwendet hat, kein gemeinsames Tabellenschema. CSV-Importbraucht ebenfalls einen komplett neuen Backend-Handler (Export ist client-seitig quasi kostenlos, sobald die
Get-Queries existieren — siehe
#83's Architektur). Siehedocs/features/done/94_pantry_inventory_phase1_design.md's "Scope-Entscheidung".Acceptance criteria:
PantryLabelEntity/Join-Tabelle, wiederverwendet dieselbeLabelColor-Palette wie Todo/Shopping-Kategorien, gleiche UI-Konvention (
LabelPicker). — geliefert als#101b.PantryCommentEntity, gleiche UI-Konvention wie Todo-Kommentare. — geliefert als#101c.PantryActivityEventEntity, Ereignistypen mindestens: Artikel angelegt, ein-/ausgecheckt (inkl. Menge-Delta), Soll-Menge geändert, Mitglied beigetreten/entfernt (über die
gekoppelte Ziel-Einkaufsliste sichtbar, nicht separat verwaltet). — geliefert als
#101d.ImportPantryProductsFromCsvCommand(analog#90'sImportShoppingProductsFromCsvCommand); Export braucht keinen neuen Endpunkt (reine Erweiterung vonCsvExportDialogskind-Union um'pantry', sobaldGetPantryProductsQuery/GetPantryCategoriesQueryaus
#94existieren). — geliefert als#101e.Status: Alle vier Teilbereiche über die Folge-Stories
#101b–#101egeliefert. Siehedocs/features/done/101b_pantry_labels_ui.md,101c_pantry_comments_ui.md,101d_pantry_activity_feed_ui.md,101e_pantry_csv_export_import_ui.md.Out of scope: keine neue Sharing-Infrastruktur — bleibt an die Ziel-Einkaufsliste gekoppelt (
#94'sArchitect-Entscheidung).
design (
101_pantry_labels_comments_activity_feed_design.md)Design:
#101— Vorratsschrank: Labels, Kommentare, Aktivitäts-Feed, CSV-Import/-ExportKernprinzip: Sibling-Entities, keine polymorphe Struktur
Per
#94's Architect-Notiz und#89/#93-Präzedenzfall:LabelEntity/CommentEntity/ActivityEventEntitysind aktuell hart anTodoListId/TodoNrgebunden. Statt sie polymorph zumachen (ein
TodoListId?undPantryId?Feld an derselben Tabelle, mit XOR-Constraint), werdenstrukturelle Kopien angelegt:
PantryLabelEntity/PantryProductLabelEntity(Join) — spiegeltLabelEntity/TodoLabelEntity.PantryProductCommentEntity— spiegeltCommentEntity, keyed aufPantryProductIdstatt(TodoListId, TodoNr).PantryActivityEventEntity— spiegeltActivityEventEntity, keyed aufPantryIdstattTodoListId.Wiederverwendet werden die vorhandenen Value-Objects
LabelName,LabelColor,CommentText.Neu sind nur ID-VOs:
PantryLabelId,PantryProductCommentId,PantryActivityEventId, plusdas Enum
PantryActivityEventKind.Diese Entscheidung matcht exakt das, was
#93für Masterpackliste getroffen hat(
MasterPackLabelEntity+MasterPackItemLabelEntity,MasterPackItemCommentEntity) — keine neueBauweise, sondern die im Repo bereits etablierte.
Etappen (jede eigenständig commit-fähig, jede lässt Build grün)
Tag/Untag-PantryProduct-Commands + GetLabelsForPantryQuery + Migration + Handler-Tests.
Bestehendes DTO-Feld
LabelDtowird für Response wiederverwendet (identische Shape).GetCommentsForPantryProductQuery + Migration + Tests. Bestehendes DTO-Feld
CommentDtowirdwiederverwendet (identische Shape).
PantryActivityEventKind-Enum(
ProductCreated,ProductRenamed,ProductCheckedIn,ProductCheckedOut,ProductTargetQuantityChanged) +CreatePantryActivityEventCommand+ emit-Aufrufe in denbestehenden Pantry-Mutations-Handlern +
GetPantryActivityFeedQuery(Pagination wie beim Todo-Pendant) + Migration + Tests. Analog zu
TodoCreated/TodoChecked/TodoAssignedetc.ImportPantryProductsFromCsvCommandnach demImportShoppingProductsFromCsvCommand-Vorbild — kein neuer CSV-Parser, sondern die bestehendeZeilen-Schleife + Kategorie-Auto-Anlage. Spalten:
Name, Category, Quantity, TargetQuantity, Barcode. Tests inkl. Duplikat-Merge (bestehendes Produkt mit gleichem Namen wird auf dieimportierte Menge gesetzt) und leere/ungültige Zeilen.
PantryLabelPicker-Komponente (nach demLabelPicker-Vorbild, aber mitpantryProductIdstatttodoListId/todoNr) + Anzeige aufPantryProductItem+ Label-Filterin
PantryPage.PantryCommentListanalogCommentList; UI-Zugriff über einen Klick/Icon auf
PantryProductItem.PantryActivityFeedPanelanalog zuActivityFeedPanel, geöffnetvia einen Header-Button auf
PantryPage. Pagination-Verhalten wie beim Todo-Pendant.CsvExportDialogskind-Union um'pantry'erweitert; Import über einenMenü-Eintrag auf
PantryPage(analog Shopping/Todo-CSV-Import). Nutzt die bereits vorhandenengetPantryProductsForList/getPantryCategoriesForList-Queries.Security-Vorprüfung (überall gleiche Regel)
Alle neuen Handler nutzen
AuthorizePantryAccessForCurrentUserQuery(pantryId)— dieselbeMembership-basierte Autorisierung, die
#94für alle bestehenden Pantry-Handler eingeführt hat.Kein Owner-only-Split nötig, da Pantry-Sharing rein Mitgliedschafts-basiert ist (Owner-only wäre
ein neues Konzept und ist nicht von der AC gefordert). Label/Kommentar-Löschung: jeder Mitglied
darf Labels/Kommentare löschen (matcht Todo-Regel — vgl.
DeleteLabelCommand/DeleteCommentCommand,beide member-level).
Aktivitäts-Feed-Zugriff:
GetPantryActivityFeedQueryprüftAuthorizePantryAccessForCurrentUserQuery— Members sehen nur die Feeds ihrer Pantries.CSV-Import: analog
ImportShoppingProductsFromCsvCommand— Mitgliedschafts-Check +ImportSizeLimit(Zeilenanzahl-Obergrenze zur DoS-Absicherung, vom Shopping-Import geerbt).Keine neue Attack Surface: alle Endpunkte spiegeln existierende, bereits geprüfte Muster.
Test-Strategie
Backend: Handler-Tests pro Command wie im Rest des Repos (
CqsTodo.Tests/Features/Pantry/bekommt jeweils einen
*Tests.cs), inkl. Auth-Ablehnung und typischer Fehlerpfade.Frontend: Unit-Tests pro neuer/erweiterter Komponente (Vitest), plus 1 E2E
(
pantry-collaboration.spec.ts) das die vier Sub-Features im Zusammenspiel prüft: Label anlegen +taggen + filtern; Kommentar schreiben; Check-in/-out landet im Activity-Feed; CSV-Export +
Re-Import erzeugt identischen Bestand.
Explizit Nicht-Scope
#94selbst — Pantry hat keinen WS-Kanal, refetch-nach-Mutation reicht für die typische Häufigkeit). Falls sich im Betrieb
Bedarf ergibt, wäre das eine separate Folge-Story analog
#99.PantryLabelEntity(das war#93-spezifisch für dieClimate/Travel-Type-Facets — Pantry-Labels sind gruppenlos wie Todo-Labels).
PantryActivityEventEntity-Broadcast über einen WS-Change-Subject; Refetch-on-Open reichtwie beim Todo-Pendant, das keinen eigenen WS-Kanal hat.