Speisekammer — Kategorien mit der verknüpften Einkaufsliste teilen #174
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#174
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: Speisekammer — Kategorien mit der verknüpften Einkaufsliste teilen
As a Nutzer, der eine Speisekammer und ihre verknüpfte Einkaufsliste parallel pflegt,
I want to in beiden dieselben Kategorien mit derselben Zuordnung sehen,
so that ich nicht zwei unabhängige Kategorie-Systeme für dieselben Produkte pflegen muss.
Kontext (verifiziert im Code):
PantryCategoryEntityist per FK anPantryIdgebunden,ShoppingCategoryEntityanShoppingListId— vollständig getrennte Tabellen und ID-Räume (PantryCategoryIdvsShoppingCategoryId), keinerlei Verknüpfung.PantryEntity.TargetShoppingListIdexistiert bereits (FK zur verknüpften Einkaufsliste), wird aber ausschließlich zur Herleitung von Zugriffsrechten genutzt ("access is derived live from TargetShoppingList's own membership") — nicht zum Teilen von Kategorien.GetPantryCategoriesQueryHandler.csliest ausPantryCategoryEntitygefiltert aufPantryId;GetShoppingCategoriesForListQueryHandler.csliest ausShoppingCategoryEntitygefiltert aufShoppingListId— komplett unabhängige Datensätze heute.PantryProductEntity.CategoryIdzeigt nur aufPantryCategoryEntity, nie aufShoppingCategoryEntity.Acceptance criteria:
TargetShoppingListId) — gleiche Namen, gleiche Reihenfolge, gleiche Icons.Out of scope for this story:
Open questions: (escalate to human if unanswered)
PantryCategoryEntity-Zeilen? Werden sie anhand des Namens auf passendeShoppingCategoryEntity-Zeilen der verknüpften Liste gemappt, oder verlieren Produkte mit einer heute nur-Speisekammer-eigenen Kategorie (die es auf der Einkaufsliste nicht gibt) ihre Zuordnung? Braucht vermutlich eine Datenmigration, kein reiner Code-Change — Architect-Entscheidung.PantryCategoryEntitykomplett entfernt, oder bleibt sie (leer/ungenutzt) aus Kompatibilitätsgründen bestehen?Entscheidung (Mensch, 2026-09-08): Migrationspfad geklaert. Beim Umstieg werden bestehende
PantryCategoryEntity-Zeilen per Name auf die passendeShoppingCategoryEntityder verknuepften Einkaufsliste gemappt; nicht matchende Kategorien verlieren ihre Zuordnung (Produkt wird unkategorisiert).PantryCategoryEntitywird danach vollstaendig entfernt, keine Kompatibilitaets-Altlast. Beide offenen Fragen der Story sind damit beantwortet - Umsetzung kann ohne weitere Eskalation starten.Claimed for this go-cycle (2026-09-08). Migration path is already resolved per the human decision comment above - implementation plan: (1) EF Core migration to drop PantryCategoryEntity/PantryProductEntity.CategoryId's FK to it, repoint PantryProductEntity.CategoryId at ShoppingCategoryEntity (or add a new column and drop the old, whichever is the cleaner EF migration), (2) one-time data migration mapping existing PantryCategoryEntity rows to the linked ShoppingList's ShoppingCategoryEntity rows by name (unmatched -> product left uncategorized, per the human decision), (3) update GetPantryCategoriesQueryHandler/PantryCategoryPicker.tsx and all Pantry category CRUD handlers (Create/Rename/Delete/Reorder) to operate on ShoppingCategoryEntity scoped by the pantry's TargetShoppingListId instead of PantryCategoryEntity, (4) remove PantryCategoryEntity and PantryCategoryId entirely once nothing references them, (5) frontend: PantryProductItem's category picker/select and PantryPage's category filter switch from PantryCategoryDto/PantryCategoryId to the shopping-list's own CategoryDto/CategoryId types.
Done - merged to master as
96f9d545(feature) +838eccaf(coverage report).Scope delivered (both AC bullets from the human's migration decision comment included):
Backend: 6 Pantry-only category CRUD/query handlers + PantryCategoryId/PantryCategoryDto deleted. PantryProductEntity.CategoryId repointed at ShoppingCategoryId. Every handler that validated "does this category belong to my pantry" (CreatePantryProductCommandHandler, MovePantryProductCommandHandler, ScanPantryProductBarcodeCommandHandler, ImportPantryProductsFromCsvCommandHandler) now fetches the pantry's TargetShoppingListId server-side and validates against that list's own categories - never trusts client input for the scope. DuplicatePantryCommandHandler's category-copy logic became unnecessary (a duplicated pantry already shares the source's TargetShoppingListId, so it already sees the same categories) and was removed. New SetDefaultShoppingCategoryCommand (mirrors the deleted Pantry-only equivalent) added to the Shopping side and wired into both category managers, so Shopping gains the "set default" control Pantry already had, rather than either side losing a capability. One combined EF migration: raw-SQL name-based remap first, then the schema drop/FK repoint, following this repo's existing data-merge-migration pattern.
Frontend: PantryCategoryManager.tsx/PantryCategoryPicker.tsx kept as their own thin components (consistent with this codebase's existing "mirrors X.tsx" sibling-component convention elsewhere) but retargeted to call the Shopping category commands/types directly instead of Pantry-only ones.
Testing: dotnet test 1028/1028 green,
pm run coverage 1244/1244 green (the only failure seen across two full-suite runs this cycle was the already-known-flaky #175 burst-scan timing test, unrelated to this diff - separately flagged). Self-review + the security-review skill (plus a dedicated sub-agent IDOR check: can a caller reference a category from a shopping list other than the pantry's own linked one?) both came back clean. Live end-to-end verification against the rebuilt local review container (registered a real user, created a real shopping list + linked pantry, created categories from both the Shopping and Pantry sides via the real API, confirmed each showed up on both sides immediately, and created a pantry product assigned to a category created from the Pantry side, confirmed correctly filed) - not just automated tests.
Known, deliberately out-of-scope: behavior when a pantry's linked shopping list is deleted while the pantry still references it - explicitly called out as out of scope in the original story.