#93 — Neuer Listentyp "Masterpackliste" mit Checkout zu Todo-Liste #93

Closed
opened 2026-08-18 13:13:53 +02:00 by lena · 1 comment
lena commented 2026-08-18 13:13:53 +02:00 (Migrated from git.butzei.de)

Story: Neuer Listentyp "Masterpackliste" mit Checkout zu Todo-Liste

As a Vielreisende(r),
I want to eine wiederverwendbare, getaggte Packlisten-Referenzdatenbank pflegen und daraus bei Bedarf gezielt
eine konkrete Packliste für eine bevorstehende Reise generieren,
so that ich nicht bei jeder Reise von Neuem überlegen muss, was ich mitnehmen will, sondern nur die
relevanten Eigenschaften der Reise auswähle.

Depends on: #89 (Listentyp-Vereinheitlichung — "Masterpackliste" ergänzt dessen Typenliste); erweitert
außerdem das bestehende Label-System (#19) um ein neues "Label-Gruppen"-Konzept (siehe unten).

Acceptance criteria:

Masterpackliste (Referenz-Datenmodell)

  • Neuer Listentyp "Masterpackliste" wählbar bei Listenerstellung.
  • Jedes Item einer Masterpackliste hat: Name, Category (z. B. Clothing/Bathroom/Misc/Electronics/Food),
    Climate (Mehrfachwert möglich, z. B. "Cold, Raining"), Prio (Essential/Not Essential/Info), Quantity
    (optional, numerisch), Travel Type (Mehrfachwert möglich, z. B. "Camping, Schweigekloster").
  • Masterpackliste-Items unterstützen die bestehende Kommentar-Funktion (#27) — wird für den
    Import-Sonderfall "Ohne Crew" unten benötigt, ist aber auch allgemein nützlich (z. B. "hier lieber die
    Bio-Variante").
  • Climate und Travel Type werden nicht als zwei neue, dedizierte Felder modelliert, sondern durch eine
    Erweiterung des bestehenden Label-Systems (#19) um ein neues "Label-Gruppen"-Konzept: Labels können ab
    sofort optional einer benannten Gruppe zugeordnet werden (z. B. Gruppe "Climate", Gruppe "Travel Type"),
    wiederverwendbar auch für künftige ähnliche Fälle statt einer Einmal-Lösung nur für diese Story.
  • Items sind editierbar und löschbar, haben aber keine Abhak-/Erledigt-Funktion — die Masterpackliste
    ist reine Referenzdaten, kein Erledigungs-Workflow.
  • Masterpacklisten sind teilbar (einheitliches Sharing-Modell aus #89).
  • Es können mehrere unabhängige Masterpacklisten angelegt werden, jede mit eigenen Items (keine geteilte
    globale Datenbank wie bei #90's Produktkatalog — jede Masterpackliste ist in sich geschlossen).
  • Eine erste Masterpackliste wird beim Rollout dieses Features automatisch aus
    input/Packliste_template.csv importiert (Spalten Eigenschaft/Category/Climate/Prio/Quantity/Travel Type,
    ca. 87 Items), damit der bestehende Bestand nicht manuell neu eingegeben werden muss. Wichtig: Dieser
    Import ist ausschließlich für den Account des Menschen (lenny-lennox@hotmail.de), der diese CSV gepflegt
    hat — kein generisches Seed-Verhalten für alle Accounts wie beim Demo-Seeding-Muster aus #80. Die
    Daten sind persönlich, die App unterstützt beliebige registrierte Nutzer über Einladungslinks, ein
    globaler Seed würde fremden Accounts ungefragt private Reisedaten unterschieben.
  • Sonderfall "Ohne Crew" beim Import: 8 Zeilen der Quelldatei führen im Climate-Feld einen zusätzlichen
    Wert "Ohne Crew" (z. B. "All Climate, Ohne Crew"). Das ist inhaltlich keine Klimaangabe, sondern bezieht
    sich darauf, ob die Reise ohne Verpflegung/Küche durch eine Gruppe stattfindet. Beim Import wird "Ohne
    Crew" nicht als Climate-Wert übernommen — stattdessen wird der Text "Ohne Crew" als Kommentar (siehe
    oben) am jeweiligen Item gespeichert. Der Checkout-Dialog bietet "Ohne Crew" folglich nicht als
    Climate-Filteroption an; betroffene Items behalten nur "All Climate" als Climate-Wert.

Checkout → Todo-Liste

  • Aus einer Masterpackliste heraus gibt es eine "Checkout"-Aktion, die eine neue Standard-Todo-Liste
    erzeugt (normales Verhalten: Abhaken, Bearbeiten etc. — keine Sonderfunktionen).
  • Checkout fragt zunächst die Reise-Eigenschaften ab, mit Mehrfachauswahl pro Dimension:
    • Climate: z. B. "Warm", "Kalt", oder beides wählbar. Items mit "All Climate" werden unabhängig von der
      Auswahl immer übernommen.
    • Travel Type: die in der Masterpackliste vorkommenden Reise-Typen (z. B. Camping, Ausland, Wochenende)
      sind mehrfach auswählbar. "Immer" wird nicht zur Auswahl angeboten — Items mit diesem Tag werden
      automatisch immer übernommen.
  • "Essential"-Items werden — wie "All Climate"/"Immer" — nie abgefragt, sondern automatisch immer
    übernommen. "Not Essential" ist eine zusätzliche, separate Auswahl beim Checkout (z. B. Checkbox "auch
    optionale Artikel mit aufnehmen").
  • Die zwei reinen Info-Hinweis-Zeilen der CSV (kein Packartikel, z. B. "Hinweis: Fingernägel vorher kurz
    schneiden") erscheinen nicht als abhakbarer Artikel, sondern als Notiz/Kommentar auf der generierten
    Todo-Liste.
  • Quantity wird in den Titel des generierten Todos geschrieben (z. B. "Paar Socken (2x)") — kein neues
    Mengenfeld auf TodoEntity.
  • Category wird 1:1 auf die bestehende Todo-Kategorien-/Sektionsfunktion (#80) abgebildet, sodass die neue
    Liste automatisch nach Clothing/Bathroom/etc. gruppiert ist.
  • Nach Bestätigen (OK) wird eine neue Todo-Liste erzeugt, vorbefüllt mit allen Items, die auf mindestens
    eine der gewählten Kombinationen passen.
  • Die generierte Todo-Liste ist unabhängig von der Masterpackliste — keine laufende Synchronisation danach
    (einmalige Momentaufnahme beim Checkout).

Out of scope for this story:

  • Rückschreiben von Änderungen aus der generierten Todo-Liste in die Masterpackliste.
  • Automatisches Löschen/Archivieren der generierten Liste nach der Reise.

Verified against code (2026-08-07): input/Packliste_template.csv enthält 87 Datenzeilen mit den Spalten
Eigenschaft,Category,Climate,Prio,Quantity,Travel Type (Spaltenname "Eigenschaft" statt "Name" — inhaltlich
identisch mit der obigen Beschreibung). 8 dieser Zeilen enthalten "Ohne Crew" im Climate-Feld (siehe
Import-Sonderfall oben); die zwei reinen Info-Hinweis-Zeilen wurden korrekt über Prio = "Not needed / Info"
identifiziert (Zeilen "Nicht gebraucht: Buch, Spielsachen …" und "Hinweis: Fingernägel vorher kurz schneiden").

# Story: Neuer Listentyp "Masterpackliste" mit Checkout zu Todo-Liste **As a** Vielreisende(r), **I want to** eine wiederverwendbare, getaggte Packlisten-Referenzdatenbank pflegen und daraus bei Bedarf gezielt eine konkrete Packliste für eine bevorstehende Reise generieren, **so that** ich nicht bei jeder Reise von Neuem überlegen muss, was ich mitnehmen will, sondern nur die relevanten Eigenschaften der Reise auswähle. **Depends on:** `#89` (Listentyp-Vereinheitlichung — "Masterpackliste" ergänzt dessen Typenliste); erweitert außerdem das bestehende Label-System (`#19`) um ein neues "Label-Gruppen"-Konzept (siehe unten). **Acceptance criteria:** *Masterpackliste (Referenz-Datenmodell)* - [ ] Neuer Listentyp "Masterpackliste" wählbar bei Listenerstellung. - [ ] Jedes Item einer Masterpackliste hat: Name, Category (z. B. Clothing/Bathroom/Misc/Electronics/Food), Climate (Mehrfachwert möglich, z. B. "Cold, Raining"), Prio (Essential/Not Essential/Info), Quantity (optional, numerisch), Travel Type (Mehrfachwert möglich, z. B. "Camping, Schweigekloster"). - [ ] Masterpackliste-Items unterstützen die bestehende Kommentar-Funktion (`#27`) — wird für den Import-Sonderfall "Ohne Crew" unten benötigt, ist aber auch allgemein nützlich (z. B. "hier lieber die Bio-Variante"). - [ ] Climate und Travel Type werden **nicht** als zwei neue, dedizierte Felder modelliert, sondern durch eine Erweiterung des bestehenden Label-Systems (`#19`) um ein neues "Label-Gruppen"-Konzept: Labels können ab sofort optional einer benannten Gruppe zugeordnet werden (z. B. Gruppe "Climate", Gruppe "Travel Type"), wiederverwendbar auch für künftige ähnliche Fälle statt einer Einmal-Lösung nur für diese Story. - [ ] Items sind editierbar und löschbar, haben aber **keine** Abhak-/Erledigt-Funktion — die Masterpackliste ist reine Referenzdaten, kein Erledigungs-Workflow. - [ ] Masterpacklisten sind teilbar (einheitliches Sharing-Modell aus `#89`). - [ ] Es können mehrere unabhängige Masterpacklisten angelegt werden, jede mit eigenen Items (keine geteilte globale Datenbank wie bei `#90`'s Produktkatalog — jede Masterpackliste ist in sich geschlossen). - [ ] Eine erste Masterpackliste wird beim Rollout dieses Features automatisch aus `input/Packliste_template.csv` importiert (Spalten Eigenschaft/Category/Climate/Prio/Quantity/Travel Type, ca. 87 Items), damit der bestehende Bestand nicht manuell neu eingegeben werden muss. **Wichtig:** Dieser Import ist ausschließlich für den Account des Menschen (lenny-lennox@hotmail.de), der diese CSV gepflegt hat — **kein** generisches Seed-Verhalten für alle Accounts wie beim Demo-Seeding-Muster aus `#80`. Die Daten sind persönlich, die App unterstützt beliebige registrierte Nutzer über Einladungslinks, ein globaler Seed würde fremden Accounts ungefragt private Reisedaten unterschieben. - [ ] **Sonderfall "Ohne Crew" beim Import:** 8 Zeilen der Quelldatei führen im Climate-Feld einen zusätzlichen Wert "Ohne Crew" (z. B. `"All Climate, Ohne Crew"`). Das ist inhaltlich keine Klimaangabe, sondern bezieht sich darauf, ob die Reise ohne Verpflegung/Küche durch eine Gruppe stattfindet. Beim Import wird "Ohne Crew" **nicht** als Climate-Wert übernommen — stattdessen wird der Text "Ohne Crew" als Kommentar (siehe oben) am jeweiligen Item gespeichert. Der Checkout-Dialog bietet "Ohne Crew" folglich nicht als Climate-Filteroption an; betroffene Items behalten nur "All Climate" als Climate-Wert. *Checkout → Todo-Liste* - [ ] Aus einer Masterpackliste heraus gibt es eine "Checkout"-Aktion, die eine neue **Standard**-Todo-Liste erzeugt (normales Verhalten: Abhaken, Bearbeiten etc. — keine Sonderfunktionen). - [ ] Checkout fragt zunächst die Reise-Eigenschaften ab, mit Mehrfachauswahl pro Dimension: - **Climate:** z. B. "Warm", "Kalt", oder beides wählbar. Items mit "All Climate" werden unabhängig von der Auswahl immer übernommen. - **Travel Type:** die in der Masterpackliste vorkommenden Reise-Typen (z. B. Camping, Ausland, Wochenende) sind mehrfach auswählbar. "Immer" wird **nicht** zur Auswahl angeboten — Items mit diesem Tag werden automatisch immer übernommen. - [ ] "Essential"-Items werden — wie "All Climate"/"Immer" — nie abgefragt, sondern automatisch immer übernommen. "Not Essential" ist eine zusätzliche, separate Auswahl beim Checkout (z. B. Checkbox "auch optionale Artikel mit aufnehmen"). - [ ] Die zwei reinen Info-Hinweis-Zeilen der CSV (kein Packartikel, z. B. "Hinweis: Fingernägel vorher kurz schneiden") erscheinen nicht als abhakbarer Artikel, sondern als Notiz/Kommentar auf der generierten Todo-Liste. - [ ] Quantity wird in den Titel des generierten Todos geschrieben (z. B. "Paar Socken (2x)") — kein neues Mengenfeld auf `TodoEntity`. - [ ] Category wird 1:1 auf die bestehende Todo-Kategorien-/Sektionsfunktion (`#80`) abgebildet, sodass die neue Liste automatisch nach Clothing/Bathroom/etc. gruppiert ist. - [ ] Nach Bestätigen (OK) wird eine neue Todo-Liste erzeugt, vorbefüllt mit allen Items, die auf mindestens eine der gewählten Kombinationen passen. - [ ] Die generierte Todo-Liste ist unabhängig von der Masterpackliste — keine laufende Synchronisation danach (einmalige Momentaufnahme beim Checkout). **Out of scope for this story:** - Rückschreiben von Änderungen aus der generierten Todo-Liste in die Masterpackliste. - Automatisches Löschen/Archivieren der generierten Liste nach der Reise. **Verified against code (2026-08-07):** `input/Packliste_template.csv` enthält 87 Datenzeilen mit den Spalten `Eigenschaft,Category,Climate,Prio,Quantity,Travel Type` (Spaltenname "Eigenschaft" statt "Name" — inhaltlich identisch mit der obigen Beschreibung). 8 dieser Zeilen enthalten "Ohne Crew" im Climate-Feld (siehe Import-Sonderfall oben); die zwei reinen Info-Hinweis-Zeilen wurden korrekt über `Prio = "Not needed / Info"` identifiziert (Zeilen "Nicht gebraucht: Buch, Spielsachen …" und "Hinweis: Fingernägel vorher kurz schneiden").
lena commented 2026-08-18 13:13:54 +02:00 (Migrated from git.butzei.de)

design (93_masterpackliste_list_type_design.md)

Design: Masterpackliste (#93)

Entity shape

Per #89's explicit "no shared table, no ListType enum" ruling, Masterpackliste is a full sibling entity
set, not a bolt-on to TodoListEntity:

  • MasterPackingListEntity / MasterPackingListToUserEntity / MasterPackingListInvitationEntity — mirror
    ShoppingListEntity/ShoppingListToUserEntity/ShoppingListInvitationEntity exactly (full Owner/Member
    sharing + share-link invitations, since the AC explicitly requires "einheitliches Sharing-Modell aus #89",
    unlike Pantry's derived-access model which doesn't apply here — there's no natural parent list to derive
    from).
  • MasterPackItemEntityId, MasterPackingListId, Name, Category (CategoryName, plain field, no FK — see below), Priority (enum Essential/NotEssential/Info), Quantity (int?), SortOrder.
  • MasterPackLabelEntity / MasterPackItemLabelEntity (join) — the "Label-Gruppen" extension applied to a
    new, list-scoped label table rather than generalizing the existing LabelEntity (which is hard-wired to
    TodoListId). Turning that FK polymorphic (nullable TodoListId + nullable MasterPackingListId with an
    exactly-one-set constraint) would touch every existing Label handler/test for a capability the existing Todo
    UI doesn't ask for. MasterPackLabelEntity carries the same shape (Name, Color, plus a new nullable
    Group field) so a future story can lift the group concept into the general LabelEntity unchanged — the
    "reusable for future similar cases" line in the AC is satisfied by an identical, liftable shape, not by a
    shared table today. LabelEntity itself is untouched by this story.
  • MasterPackItemCommentEntity — same reasoning as labels: CommentEntity is keyed on (TodoListId, TodoNr),
    so a structural sibling scoped to MasterPackItemId is added rather than generalizing it.

Category on MasterPackItemEntity is a plain CategoryName value, not a TodoCategoryEntity-shaped
per-list managed entity: the AC gives a closed example set and items don't need per-list reordering/custom
category icons the way Todo/Shopping/Pantry categories do. At checkout, distinct Category values become real
TodoCategoryEntity rows on the generated list via the existing CreateCategoryCommand (same pattern
ImportTodosFromCsvCommandHandler already uses for its own category auto-creation).

Scope cut: no WebSocket live-sync for v1

Every other shared list type got WS broadcasting (ISubject<Change<...>>) as a follow-up story after its
initial build (Shopping's own CreateShoppingListCommandHandler comment: "no dedicated WebSocket broadcast
channel... yet - deferred to a follow-up story", closed later by #99). Masterpackliste follows the same
staging: v1 ships with plain request/response CRUD (frontend refetches after each mutation, same as
Shopping/Pantry did before their own WS stories landed). Given the roadmap's own framing of this feature
("Masterpackliste nur bei Reisen" — infrequent, low-concurrency use), this is a reasonable v1 cut, not a
correctness gap. A follow-up story can add live sync exactly the way #99 did for Shopping, if it turns out to
matter in practice.

Checkout logic (CheckoutMasterPackingListCommand)

Input: MasterPackingListId, selected Climate names, selected TravelType names, IncludeNotEssential: bool.

Inclusion per item (independent gates):

  • Climate gate: passes if the item has no Climate-group label at all, OR has the label "All Climate", OR
    has a label matching one of the selected climates.
  • Travel-Type gate: passes if the item has no Travel-Type-group label at all, OR has the label "Immer", OR
    has a label matching one of the selected travel types.
  • Priority gate: Essential always passes; NotEssential passes only if IncludeNotEssential; Info
    never becomes a todo (see below).

Included items are grouped by Category, and the list is built by composing existing single-item commands
(CreateTodoListCommand, CreateCategoryCommand per distinct category, CreateTodoCommand per item) —
mirrors ImportTodosFromCsvCommandHandler's "seed through the normal pipeline" precedent, so Nr/SortOrder/etc.
all come out correct for free. Title gets a " (Nx)" suffix when Quantity > 1.

Info-priority items that pass the Climate/Travel-Type gates are never turned into todos; instead, if at
least one exists, a single non-actionable " Hinweise" todo is created on the new list and each Info item's
text is attached to it via the existing CreateCommentCommand — reusing #27's comment feature is exactly why
comments are in scope for Masterpack items at all (also needed for the "Ohne Crew" import special-case below).

CSV import — one-time, single-account seed

Not the interactive client-side CSV import from #83 (that parses in the browser and only handles Todo/Shopping
rows) — this is a server-side, startup-time seed gated to one specific, already-registered account
(lenny-lennox@hotmail.de), matching neither the generic DevDataSeeder (runs for every environment) nor a
migration-embedded INSERT (runs for every existing row/account) — both of those are explicitly the wrong
shape per the AC ("kein generisches Seed-Verhalten... ein globaler Seed würde fremden Accounts ungefragt
private Reisedaten unterschieben").

input/Packliste_template.csv is not copied into the Docker build context (Dockerfile only copies
Common/, CqsTodo/, CqsTodo.WebApi/), so the file is copied into CqsTodo/SeedData/masterpackliste.csv
and embedded as a compiled resource — baked into CqsTodo.dll at build time, readable at runtime regardless of
deployment shape (works identically for CqsTodo.WebApi's own migrate-and-seed path and the separate
CqsTodo.MigrationService, since both reference the CqsTodo assembly).

MasterPackingListDemoImporter.SeedAsync(dbContext), called from both Setup.MigrateAndSeedAsync and
CqsTodo.MigrationService/Worker.cs (alongside, not inside, DevDataSeeder.SeedAsync — this seed is
account-specific, the other is generic-environment): no-ops if the target user doesn't exist yet, or already
owns a Masterpackliste (idempotency guard, same shape as DevDataSeeder's own existence check).

Import special-cases (verified against the CSV, see story's "Verified against code" note):

  • A Climate token of exactly "Ohne Crew" is stripped from the item's climate labels and instead becomes a
    MasterPackItemCommentEntity with text "Ohne Crew" on that item.
  • Rows with Prio = "Not needed / Info" map to MasterPackItemPriority.Info.

Frontend

  • Route /masterpacking/:masterPackingListId (mirrors /pantry/:pantryId}), new MasterPackingListPage.tsx,
    MasterPackingListItem.tsx, CreateMasterPackingListDialog.tsx, MasterPackingListCheckoutDialog.tsx.
  • TodoListMenu.tsx's UnifiedListEntry union gets a 'masterPackingList' variant; AddListFlow.tsx gets a
    "Masterpackliste" button.
  • InvitePanel/MembersPanel (already generic two-branch components for 'todo' | 'shopping') get a third
    'masterPacking' branch instead of new components, per their own stated reuse rationale.
  • Store fields added to the single flat store.ts State, mirroring the existing pantries/shoppingLists
    blocks (no per-domain slices in this codebase).
  • Climate/Travel-Type label editing on an item reuses LabelPicker.tsx's toggle-list pattern grouped by
    Group; the checkout dialog's multi-select filters reuse the same toggle-button styling.

Out of scope (explicit, from the story) / deferred

  • Writing changes on the generated todo list back into the Masterpackliste.
  • Auto-archiving the generated list after the trip.
  • WebSocket live-sync (see above) — candidate follow-up story if collaborative use turns out to matter.
  • Lifting the Label-Groups concept into the general LabelEntity/Todo LabelPicker UI — the shape is kept
    identical on purpose so this is a low-risk follow-up, not a redesign.
**design** (`93_masterpackliste_list_type_design.md`) # Design: Masterpackliste (`#93`) ## Entity shape Per `#89`'s explicit "no shared table, no `ListType` enum" ruling, Masterpackliste is a full sibling entity set, not a bolt-on to `TodoListEntity`: - `MasterPackingListEntity` / `MasterPackingListToUserEntity` / `MasterPackingListInvitationEntity` — mirror `ShoppingListEntity`/`ShoppingListToUserEntity`/`ShoppingListInvitationEntity` exactly (full Owner/Member sharing + share-link invitations, since the AC explicitly requires "einheitliches Sharing-Modell aus `#89`", unlike Pantry's derived-access model which doesn't apply here — there's no natural parent list to derive from). - `MasterPackItemEntity` — `Id, MasterPackingListId, Name, Category (CategoryName, plain field, no FK — see below), Priority (enum Essential/NotEssential/Info), Quantity (int?), SortOrder`. - `MasterPackLabelEntity` / `MasterPackItemLabelEntity` (join) — the "Label-Gruppen" extension applied to a **new, list-scoped label table** rather than generalizing the existing `LabelEntity` (which is hard-wired to `TodoListId`). Turning that FK polymorphic (nullable `TodoListId` + nullable `MasterPackingListId` with an exactly-one-set constraint) would touch every existing Label handler/test for a capability the existing Todo UI doesn't ask for. `MasterPackLabelEntity` carries the same shape (`Name`, `Color`, plus a new nullable `Group` field) so a future story can lift the group concept into the general `LabelEntity` unchanged — the "reusable for future similar cases" line in the AC is satisfied by an identical, liftable shape, not by a shared table today. `LabelEntity` itself is untouched by this story. - `MasterPackItemCommentEntity` — same reasoning as labels: `CommentEntity` is keyed on `(TodoListId, TodoNr)`, so a structural sibling scoped to `MasterPackItemId` is added rather than generalizing it. **Category** on `MasterPackItemEntity` is a plain `CategoryName` value, not a `TodoCategoryEntity`-shaped per-list managed entity: the AC gives a closed example set and items don't need per-list reordering/custom category icons the way Todo/Shopping/Pantry categories do. At checkout, distinct `Category` values become real `TodoCategoryEntity` rows on the generated list via the existing `CreateCategoryCommand` (same pattern `ImportTodosFromCsvCommandHandler` already uses for its own category auto-creation). ## Scope cut: no WebSocket live-sync for v1 Every other shared list type got WS broadcasting (`ISubject<Change<...>>`) as a *follow-up* story after its initial build (Shopping's own `CreateShoppingListCommandHandler` comment: "no dedicated WebSocket broadcast channel... yet - deferred to a follow-up story", closed later by `#99`). Masterpackliste follows the same staging: v1 ships with plain request/response CRUD (frontend refetches after each mutation, same as Shopping/Pantry did before their own WS stories landed). Given the roadmap's own framing of this feature ("Masterpackliste nur bei Reisen" — infrequent, low-concurrency use), this is a reasonable v1 cut, not a correctness gap. A follow-up story can add live sync exactly the way `#99` did for Shopping, if it turns out to matter in practice. ## Checkout logic (`CheckoutMasterPackingListCommand`) Input: `MasterPackingListId`, selected `Climate` names, selected `TravelType` names, `IncludeNotEssential: bool`. Inclusion per item (independent gates): - **Climate gate**: passes if the item has no Climate-group label at all, OR has the label "All Climate", OR has a label matching one of the selected climates. - **Travel-Type gate**: passes if the item has no Travel-Type-group label at all, OR has the label "Immer", OR has a label matching one of the selected travel types. - **Priority gate**: `Essential` always passes; `NotEssential` passes only if `IncludeNotEssential`; `Info` never becomes a todo (see below). Included items are grouped by `Category`, and the list is built by composing existing single-item commands (`CreateTodoListCommand`, `CreateCategoryCommand` per distinct category, `CreateTodoCommand` per item) — mirrors `ImportTodosFromCsvCommandHandler`'s "seed through the normal pipeline" precedent, so Nr/SortOrder/etc. all come out correct for free. Title gets a `" (Nx)"` suffix when `Quantity > 1`. `Info`-priority items that pass the Climate/Travel-Type gates are never turned into todos; instead, if at least one exists, a single non-actionable " Hinweise" todo is created on the new list and each Info item's text is attached to it via the existing `CreateCommentCommand` — reusing `#27`'s comment feature is exactly why comments are in scope for Masterpack items at all (also needed for the "Ohne Crew" import special-case below). ## CSV import — one-time, single-account seed Not the interactive client-side CSV import from `#83` (that parses in the browser and only handles Todo/Shopping rows) — this is a server-side, startup-time seed gated to one specific, already-registered account (`lenny-lennox@hotmail.de`), matching neither the generic `DevDataSeeder` (runs for every environment) nor a migration-embedded `INSERT` (runs for every existing row/account) — both of those are explicitly the wrong shape per the AC ("kein generisches Seed-Verhalten... ein globaler Seed würde fremden Accounts ungefragt private Reisedaten unterschieben"). `input/Packliste_template.csv` is not copied into the Docker build context (`Dockerfile` only copies `Common/`, `CqsTodo/`, `CqsTodo.WebApi/`), so the file is copied into `CqsTodo/SeedData/masterpackliste.csv` and embedded as a compiled resource — baked into `CqsTodo.dll` at build time, readable at runtime regardless of deployment shape (works identically for `CqsTodo.WebApi`'s own migrate-and-seed path and the separate `CqsTodo.MigrationService`, since both reference the `CqsTodo` assembly). `MasterPackingListDemoImporter.SeedAsync(dbContext)`, called from both `Setup.MigrateAndSeedAsync` and `CqsTodo.MigrationService/Worker.cs` (alongside, not inside, `DevDataSeeder.SeedAsync` — this seed is account-specific, the other is generic-environment): no-ops if the target user doesn't exist yet, or already owns a Masterpackliste (idempotency guard, same shape as `DevDataSeeder`'s own existence check). Import special-cases (verified against the CSV, see story's "Verified against code" note): - A Climate token of exactly `"Ohne Crew"` is stripped from the item's climate labels and instead becomes a `MasterPackItemCommentEntity` with text "Ohne Crew" on that item. - Rows with `Prio = "Not needed / Info"` map to `MasterPackItemPriority.Info`. ## Frontend - Route `/masterpacking/:masterPackingListId` (mirrors `/pantry/:pantryId}`), new `MasterPackingListPage.tsx`, `MasterPackingListItem.tsx`, `CreateMasterPackingListDialog.tsx`, `MasterPackingListCheckoutDialog.tsx`. - `TodoListMenu.tsx`'s `UnifiedListEntry` union gets a `'masterPackingList'` variant; `AddListFlow.tsx` gets a "Masterpackliste" button. - `InvitePanel`/`MembersPanel` (already generic two-branch components for `'todo' | 'shopping'`) get a third `'masterPacking'` branch instead of new components, per their own stated reuse rationale. - Store fields added to the single flat `store.ts` `State`, mirroring the existing `pantries`/`shoppingLists` blocks (no per-domain slices in this codebase). - Climate/Travel-Type label editing on an item reuses `LabelPicker.tsx`'s toggle-list pattern grouped by `Group`; the checkout dialog's multi-select filters reuse the same toggle-button styling. ## Out of scope (explicit, from the story) / deferred - Writing changes on the generated todo list back into the Masterpackliste. - Auto-archiving the generated list after the trip. - WebSocket live-sync (see above) — candidate follow-up story if collaborative use turns out to matter. - Lifting the Label-Groups concept into the general `LabelEntity`/Todo `LabelPicker` UI — the shape is kept identical on purpose so this is a low-risk follow-up, not a redesign.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#93
No description provided.