Spec reflection and update

This commit is contained in:
jableader 2025-11-01 23:46:01 +11:00
parent d90ffddcd7
commit adb2fc1bae

View file

@ -1,12 +1,9 @@
## 0. Current State (Nov 1, 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.
## 0. Current State (Nov 1, 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.
Status of tests and typing
- All tests pass: 27 files, 46 tests (slug-only routes; memory history fallback in non-browser envs; unauthenticated and refresh-401 guard redirects covered).
- All tests pass: 28 files, 45 tests (slug-only routes; memory history fallback in non-browser envs; unauthenticated and refresh-401 guard redirects covered).
- `tsc` and `vue-tsc` pass with no errors.
# Frontend Specification: Household Multi-Tenancy (v2)
@ -126,7 +123,9 @@ 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 uses a temporary raw fetch endpoint until typed coverage is available.
- `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:
- `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[]`.
- `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.
@ -136,7 +135,7 @@ What exists now
- MyShopping: page remains as in master with editable panel backed by legacy v1 stubs (`getMyShoppingList/saveMyShoppingList`) pending backend ad-hoc item endpoints.
Status of tests and typing
- All tests pass: 27 files, 46 tests.
- All tests pass: 28 files, 45 tests.
- `tsc` and `vue-tsc` pass with no errors.
---
@ -171,12 +170,12 @@ Progress Log (Nov 1, 2025)
- Backend updated OpenAPI and codegen has been run:
- Many endpoints are now path-scoped with `{householdSlug}` (recipes, meals, shopping, invitations (create), whoami).
- Auth endpoints (login/register/refresh/logout) are fully typed; `refresh` returns only `{ accessToken, tokenType }`.
- Completed migration to typed path parameters; header injection removed; only small raw fetch helpers remain for endpoints not yet in OpenAPI (parse only).
- Completed migration to typed path parameters; header injection removed; only Google OAuth remains using raw fetch until typed endpoints are available.
Refinements (Nov 1, 2025, later):
- Lint hardening: removed remaining `as any` and unsafe assertions across SDK/decoders.
- Lint hardening: removed remaining `as` and unsafe assertions across SDK/decoders.
- decodeRecipe/decodeMeal simplified to use concrete OpenAPI shapes and defaults; legacy Person normalization removed.
- Raw parse endpoints now use small runtime guards and normalize to strict RecipeOut before decoding.
- Parse flows are fully typed; SDK constructs a minimal RecipeOut for decoding where needed (no ad-hoc property guards).
- UI polish: MemberList and EditMealPage CSS class names unified (person-* → member-*). Login page shows a Google sign-in button wired to the placeholder handler.
Google OAuth (Nov 1, 2025, later):
@ -226,7 +225,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.
- Persons and parse endpoints are still raw until they are added to the OpenAPI.
- Google OAuth endpoints remain raw until they are added to the OpenAPI.
UI
- Login Page: Refactored to show email/password form; Google sign-in planned. Link to Create Account added.
@ -245,12 +244,12 @@ Tests
## OpenAPI & Typing Considerations (Updated)
- Avoid `any`/`unknown` in app code; keep all API calls typed via `openapi-fetch`.
- Avoid `any`/`unknown` in app code; keep all API calls typed via `openapi-fetch`. Do not use ad-hoc property guards (e.g., hasProp/Reflect) in the SDK; rely on generated types plus decoders at the boundary.
- Household scoping: use typed path params (`{ params: { path: { householdSlug } } }`); do not mutate path strings.
- Auth refresh: returns `{ accessToken, tokenType }`. After refresh, call user/household endpoints to populate app state. Use `whoami` to validate the active routes slug when needed.
- Cleanup/migration tasks:
1) Remove X-Household-Slug header injection in `api/client.ts` and refactor services to accept `householdSlug` via typed params. (Completed)
2) Replace temporary raw fetch calls with generated typed endpoints where available: invitations and members listing are now typed; migrate usages. Persons and parse remain raw for now.
2) Replace temporary raw fetch calls with generated typed endpoints where available: invitations and members listing are now typed; parse is now typed; Google OAuth remains raw for now.
3) Integrate the new `POST /shopping/current/ingredients` endpoint into the SDK (`requestIngredient(ingredientId: number)`) and expose via `useShopping`; refactor `MyShoppingPage.vue` accordingly and remove legacy stubs. (SDK + composable done; UI refactor next)
4) Identity: `User` remains the primary identity. `Person` has been removed; meal-related UIs use `MemberRef` exclusively.