diff --git a/BACKLOG.md b/BACKLOG.md index b4fa163..d570c98 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -15,14 +15,6 @@ Prerequisite for the product catalog and unit catalog work — both rely on a `F - **Bootstrap migration for the existing single-family deployment:** at upgrade time, auto-create one `Family` from the current `FAMILY_CODE` env value, assign all existing rows to it, and migrate the env var off. Flag explicitly in the runbook so deployment isn't a surprise. - Auth changes: JWT carries `FamilyId` claim. `OnTokenValidated` rejects tokens whose user has been removed from the family. -### Toast / notification component (foundational) -- App has no toast system today; current error UX is `alert()` on `stores/+page.svelte` delete failures. Several tracked items depend on this: - - Duplicate store name → toast (Stores section) - - Block create-list when no stores → toast (Lists section) - - Confirm-before-delete error surfacing (Stores section) -- Build a small reusable Svelte component (success / info / warning / error variants, auto-dismiss with timeout, optional action button for "Undo"), expose via `$lib/toast.ts`. -- Migrate existing `alert(e.message)` call sites as part of landing it. - ### Account & session lifecycle - **Password reset.** Currently no flow, no email infrastructure. Required before multi-family launches publicly. Needs SMTP config, email template, single-use token table, rate limiting on the reset endpoint. - **JWT refresh tokens.** Today's tokens are signed with HS256 and (per `Program.cs`) likely have no refresh path; they expire and the user gets bounced to login. Add refresh tokens with rotation + revocation list. @@ -221,8 +213,7 @@ Replace free-form `Quantity` strings with a structured `(Quantity, UnitOfMeasure ### Block create-list flow when no stores exist - A shopping list requires a `Store` (see `ListSummary.store` and the `newStoreId` state in `lists/+page.svelte`), so the create-list flow shouldn't be available until at least one store exists. -- Behavior: if user tries to open the create-list UI (or hits the create-list page directly via URL) with zero stores, surface a toast or modal that says "You need to create a store first" with a CTA linking to `/stores`. Don't render the empty/broken create form. -- Belongs with the toast-component work above. +- Behavior: if user tries to open the create-list UI (or hits the create-list page directly via URL) with zero stores, surface a `toast.warning()` (or modal) that says "You need to create a store first" with a CTA linking to `/stores`. Don't render the empty/broken create form. ## Stores @@ -239,12 +230,11 @@ Replace free-form `Quantity` strings with a structured `(Quantity, UnitOfMeasure - Add a modal confirmation prompt before deleting a store (currently one click → gone, no undo). - Disallow deletion of a store that has any active shopping lists associated with it. - Backend status: `StoreEndpoints.cs` DELETE already returns 400 with `{error: "Store has shopping lists. Remove them first."}` if any list references the store. Consider switching to 409 Conflict for semantic correctness. -- Frontend status: `stores/+page.svelte` `deleteStore` currently shows the backend message via `alert()`. Replace with the new confirmation modal that also surfaces this error inline. +- Frontend status: `stores/+page.svelte` `deleteStore` currently surfaces the backend message via `toast.error()`. Replace with the new confirmation modal that also surfaces this error inline (or as a toast on confirm-action failure). - Open question: what counts as "active"? Backend currently blocks on *any* list. Decide whether archived/completed lists should still block deletion. ### Duplicate store name → 500 + silent frontend (bug) - Adding a store with a name that already exists triggers the unique constraint on `Store.Name`, which leaks out as a 500 from `StoreEndpoints.cs` POST (no exception handling). - Frontend `addStore` in `stores/+page.svelte` swallows the error — the form just sits there with no feedback. -- Fix: backend should pre-check (or catch the unique-violation) and return 409 with a helpful message; frontend should display a **toast** (e.g. "A store named 'Kroger' already exists") rather than a silent failure or a blocking `alert()`. +- Fix: backend should pre-check (or catch the unique-violation) and return 409 with a helpful message; frontend should display a `toast.error()` (e.g. "A store named 'Kroger' already exists") rather than failing silently. - Same pattern likely affects PUT (rename to an existing name). -- Note: app does not currently have a toast system. This work probably needs a small reusable toast component before the duplicate-name handling can land — worth adopting it across the app (the existing `alert(e.message)` calls on delete failures should also move to toasts). diff --git a/src/frontend/src/lib/Toaster.svelte b/src/frontend/src/lib/Toaster.svelte new file mode 100644 index 0000000..d5c9aa0 --- /dev/null +++ b/src/frontend/src/lib/Toaster.svelte @@ -0,0 +1,58 @@ + + +