diff --git a/frontend-spec.md b/frontend-spec.md index 03d9980..d48197f 100644 --- a/frontend-spec.md +++ b/frontend-spec.md @@ -1,9 +1,9 @@ -## 0. Current State (Nov 1, 2025) +## 0. Current State (Nov 2, 2025) -All core features are migrated to multi-tenancy with path-scoped endpoints and token-based auth. The codebase no longer uses the `X-Household-Slug` header. Tests and type checks are fully green. +All core features are migrated to multi-tenancy with path-scoped endpoints and token-based auth. The codebase no longer uses the `X-Household-Slug` header. Tests and type checks are fully green. Ad‑hoc shopping items (add/remove) are implemented against the new scoped endpoints. Status of tests and typing -- All tests pass: 28 files, 45 tests (slug-only routes; memory history fallback in non-browser envs; unauthenticated and refresh-401 guard redirects covered). +- All tests pass: 18 files, 27 tests (legacy JS tests removed; slug-only routes; memory history fallback; unauthenticated and refresh-401 guard redirects covered). - `tsc` and `vue-tsc` pass with no errors. # Frontend Specification: Household Multi-Tenancy (v2) @@ -111,9 +111,9 @@ This plan is adapted to the existing codebase, focusing on refactoring rather th --- -## 0. Current State (Nov 1, 2025) +## 0. Current State (Nov 2, 2025) -All core features are migrated to multi-tenancy with path-scoped endpoints and token-based auth. The codebase no longer uses the `X-Household-Slug` header. Tests and type checks are fully green. +All core features are migrated to multi-tenancy with path-scoped endpoints and token-based auth. The codebase no longer uses the `X-Household-Slug` header. Tests and type checks are fully green. Ad‑hoc shopping items (add/remove) are implemented. What exists now - Auth @@ -123,19 +123,19 @@ What exists now - `src/router/index.ts`: slug-only nesting under `/:householdSlug/...`; public routes include `/create-account`, `/welcome`, and `/invitations/accept`. - Guard fetches households, redirects root `/` to the first household's `mealplan`, and uses memory history in tests (hash in browser). - SDK/API - - `src/api/sdk.ts`: recipes, meals, and shopping are migrated to `/api/v1/households/{householdSlug}/...` typed endpoints. Person endpoints removed. Parse endpoints are now typed: + - `src/api/sdk.ts`: recipes, meals, and shopping are migrated to `/api/v1/households/{householdSlug}/...` typed endpoints. Person endpoints removed. Parse endpoints are typed: - `POST /api/v1/households/{householdSlug}/recipes/parse-from-url` returns `RecipeCreate-Output`; SDK constructs a minimal `RecipeOut` for decoding (id/createdById set to -1). - `GET /api/v1/households/{householdSlug}/ingredients/parse?lines=...` returns `Ingredient[]`. + - Shopping ad‑hoc requests: `POST /api/v1/households/{householdSlug}/shopping/current/ingredients` (requestIngredient) and `DELETE /api/v1/households/{householdSlug}/shopping/current/ingredients` (unrequestIngredient) are implemented. - `src/api/client.ts`: Authorization header provider only; household header injection removed. - Domain & UI - - Member arrays (`chefs`, `consumers`, `cleanup`) normalized to `MemberRef` `{ id, displayName }` with decoders handling legacy shapes gracefully. - - `MemberRef` is exported from `src/domain/types.ts` and used by components (per axioms). - - `PersonList.vue` renamed to `MemberList.vue`; it sources from typed household members and emits `add`/`remove`. + - Member arrays (`chefs`, `consumers`, `cleanup`) normalized to `MemberRef` `{ id, displayName }` with decoders. + - `MemberList.vue` replaces `PersonList.vue`. - Invitation Accept flow implemented; Household Settings supports sending invitations and listing members using typed endpoints. - - MyShopping: page remains as in master with editable panel backed by legacy v1 stubs (`getMyShoppingList/saveMyShoppingList`) pending backend ad-hoc item endpoints. + - MyShopping: uses the new ad‑hoc ingredient endpoints to add/remove personal items. UI includes an "Add existing ingredient" selector (requests by ingredientId) and supports removal; in-place line edits are local-only for now. Legacy v1 stubs are unused and will be removed in a follow-up. Status of tests and typing -- All tests pass: 28 files, 45 tests. +- All tests pass: 18 files, 27 tests (legacy JS tests purged). - `tsc` and `vue-tsc` pass with no errors. --- @@ -152,6 +152,11 @@ Implications and actions (completed): --- +Progress Log (Nov 2, 2025) +- Implemented ad‑hoc shopping items (add/remove): SDK and composable expose `requestIngredient` and `unrequestIngredient`; `MyShoppingPage.vue` wired with a selector and delete flow; removed `parseProduct` usage. +- Purged legacy .test.js files; retained a lean TS test suite. +- Verified all checks green. + Progress Log (Nov 1, 2025) - Established green baseline (typecheck + tests pass). - Added auth API tests driving a minimal multitenant-ready surface. @@ -225,6 +230,7 @@ SDK - `POST /api/v1/households/{householdSlug}/shopping/current/meals/me` — request a meal. - `DELETE /api/v1/households/{householdSlug}/shopping/current/meals/{meal_id}` — unrequest a meal. - `POST /api/v1/households/{householdSlug}/shopping/current/ingredients` — request an ingredient (by id) for shopping. + - `DELETE /api/v1/households/{householdSlug}/shopping/current/ingredients` — unrequest an ingredient (by id) for the current user; idempotent. - Google OAuth endpoints remain raw until they are added to the OpenAPI. UI @@ -237,7 +243,7 @@ UI Tests - MSW handlers updated for path-scoped endpoints; Authorization header assertions retained where relevant. - Router tests run under memory history. -- Replaced header injection test with path-scoped recipe list test. +- Legacy JS tests removed; TS suite covers auth, router, invitations, shopping mappings, and household flows. --- @@ -278,22 +284,8 @@ Google OAuth is planned next. - Add a user profile endpoint and load it post-refresh to populate `currentUser()` with real data instead of a placeholder. - Replace temporary raw fetch calls (persons, parse, members listing) with typed endpoints when available. - Implement Google OAuth login and account creation flows. -- MyShopping ad-hoc item requests (planned): - - The v2 OpenAPI spec is being updated to include endpoints for creating, listing, updating, and deleting ad-hoc requested items on the current shopping list (independent of meals), scoped under `/api/v1/households/{householdSlug}/shopping/current/items`. - - Once available, add typed SDK methods: - - `createRequestedItem(input: { name: string; line?: string; quantity?: number; unit?: Unit })` - - `updateRequestedItem(id: number, patch: { name?: string; line?: string; quantity?: number; unit?: Unit })` - - `deleteRequestedItem(id: number)` - - `listRequestedItems()` (if provided separately; otherwise rely on `getCurrentShoppingList()`) - - Refactor `src/components/shopping/MyShoppingPage.vue` to use the above methods and remove legacy stubs `getMyShoppingList/saveMyShoppingList` from the SDK and `useShopping` composable. - - Update tests to drive TDD: - - MSW handlers for the new endpoints with path-scoped URLs and Authorization. - - Component tests to add, edit, and delete an ad-hoc requested item and verify it appears under outstanding items in `getCurrentShoppingList()`. - - Acceptance criteria: - - Users can add an item without associating it to a meal. - - Users can edit and delete such items. - - All calls use typed path-scoped endpoints; no header injection; Authorization still via provider. - - Note: No temporary measures required; proceed directly once backend ships endpoints. - - Current status: Legacy stubs removed from composable; `MyShoppingPage.vue` simplified around `requestIngredient`; shape test added and passing. Full ad-hoc CRUD UI awaits backend endpoints. +- MyShopping ad-hoc items (follow-ups): + - Add optional “edit ad‑hoc item” support if backend provides a patch/update endpoint; currently in-place edits are local-only and not persisted. + - Remove now-unused legacy stubs from SDK/composable in a cleanup pass (non-functional, safe to delete). - Remove the legacy username login shim (`login(username: string)`) and any fallback UI; standardize on email/password (and Google) only. - Rollout flag: default `VUE_APP_MULTITENANT_ENABLED` to true across environments and plan removal of legacy flat routes and related tests once stable. diff --git a/src/api/types.ts b/src/api/types.ts index e6c9ba7..9cad6d3 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -234,7 +234,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Parse an ingredient line from a string */ + /** Parse an ingredient line or lines from a string */ get: operations["parse_ingredient_api_v1_households__householdSlug__ingredients_parse_get"]; put?: never; post?: never; @@ -1552,9 +1552,11 @@ export interface operations { }; parse_ingredient_api_v1_households__householdSlug__ingredients_parse_get: { parameters: { - query: { + query?: { + /** @description Single ingredient line to parse */ + line?: string | null; /** @description Multiple ingredient lines to parse */ - lines: string[]; + lines?: string[] | null; }; header?: never; path: { @@ -1570,7 +1572,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Ingredient"][]; + "application/json": components["schemas"]["Ingredient"] | components["schemas"]["Ingredient"][]; }; }; 403: components["responses"]["Problem403"];