diff --git a/frontend-spec.md b/frontend-spec.md index d8a5c53..003ca9c 100644 --- a/frontend-spec.md +++ b/frontend-spec.md @@ -140,16 +140,23 @@ Assumptions and constraints --- -## Amendment: API Services and Typing Strategy +## Amendment: API Services and Typing Strategy (Updated Nov 1, 2025) -To align with OpenAPI typing and README axioms, do not rewrite request paths to include the household slug. +The backend OpenAPI has been updated and now exposes `householdSlug` as a path parameter for scoped endpoints (recipes, meals, shopping, invitations, whoami). Auth endpoints are fully typed (login/register/refresh/logout). Invitation acceptance remains a global endpoint (`/api/v1/invitations/accept`) with a typed operation. -- Preferred: Backend exposes `householdSlug` as a path or header parameter in OpenAPI. Regenerate types and thread via `params` for each call. -- Interim: Agree a header (e.g., `X-Household-Slug`) and inject it in `src/api/client.ts` for all requests based on the current route’s slug. Keep existing typed paths untouched. - -Action -- Implement header injection in `api/client.ts` with a pluggable getter for the active slug (decoupled from Vue imports). Update this spec once backend finalizes the parameter shape. - - DONE: Implemented with `setHouseholdSlugProvider`. Will align to OpenAPI when backend finalizes. +Implications and actions: +- Replace the temporary `X-Household-Slug` header injection with typed path parameters. + - Migrate all API calls to pass `{ params: { path: { householdSlug } } }` where required. + - Remove `setHouseholdSlugProvider` usage once the migration is complete. +- Auth refresh now returns only `{ accessToken, tokenType }` (no `user` object). The `currentUser()` flow must: + 1) Call refresh to obtain a token and set the Authorization provider. + 2) Load user/household context via typed endpoints (e.g., `GET /api/v1/users/me/households`). + 3) Optional: Use `GET /api/v1/households/{householdSlug}/whoami` to validate membership for the active route. +- Invitations: + - Create invitation is now typed at `POST /api/v1/households/{householdSlug}/invitations`. + - Accept invitation is typed at `POST /api/v1/invitations/accept`. + - Remove temporary raw fetch usage for invitations and switch to the generated client. +- Household members listing endpoint is still not present in OpenAPI; continue using the temporary fetch wrapper until the backend exposes it. --- @@ -168,6 +175,10 @@ Progress Log (Nov 1, 2025) - Added a Settings link to `HouseholdSwitcher.vue` to surface the `household-settings` route for easier discovery. - Implemented Household Settings invite form and members list UI. `src/views/HouseholdSettings.vue` now loads members via a temporary `listMembers()` in `src/api/households.ts` using the raw fetch helper. When the backend exposes a typed endpoint, we will swap to the generated client. - Fixed router tests by using memory history in non-browser environments to avoid relying on `window.location` during unit tests. + - 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 }`. + - Action: begin migrating API usage to typed path parameters and remove temporary header injection and fetch helpers. --- @@ -197,9 +208,9 @@ Router API client - `src/api/client.ts`: - - Add header injection (`X-Household-Slug`) from a configurable getter to scope requests. - - Keep `paths` typing intact; no path string mutations. - - Cleanup task: Once OpenAPI exposes `householdSlug` as a path parameter, remove the `X-Household-Slug` header injection and switch calls to use typed params. + - Previous: header injection (`X-Household-Slug`) from a configurable getter to scope requests. + - Now: migrate calls to use typed `{ params: { path: { householdSlug } } }` and remove the `X-Household-Slug` header provider. + - Authorization provider remains as-is, fed by the JWT token from login/refresh. SDK - `src/api/sdk.ts`: @@ -210,22 +221,25 @@ UI - Add `HouseholdSwitcher.vue` to app chrome and wire with router. - Update components that navigate using string paths to use named routes with slug. - `src/views/HouseholdSettings.vue`: Invite members form wired to `sendInvitation(email)`. Members list rendered from `listMembers()`; guarded for backends that don’t yet support the endpoint. + - Adjust pages that call SDK/API to pass `{ householdSlug }` path params once client services are migrated. Tests - Update MSW handlers/tests to assume JWT auth and household header. - Add tests for router guards, invitation acceptance, and household switching. - Add API tests for invitations (accept/send) and members listing header behavior. Router tests run under memory history in tests. + - Update tests to assert that calls pass `householdSlug` via typed params instead of relying on an injected header. --- -## OpenAPI & Typing Considerations +## OpenAPI & Typing Considerations (Updated) - Avoid `any`/`unknown` in app code; keep all API calls typed via `openapi-fetch`. -- If backend adds header parameter to OpenAPI, regenerate and remove any client-specific header wiring. - - Cleanup tasks: - 1) Remove X-Household-Slug header injection when `openapi.json` includes `householdSlug` path params; adopt typed client params. - 2) Replace temporary raw fetch for invitations (`acceptInvitation`, `sendInvitation`) and members listing (`listMembers`) with generated typed endpoints. - 3) Remove legacy `Person` model usages and the `currentUser()` adaptation shim once all flows use the `User` shape. +- 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 route’s 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. + 2) Replace temporary raw fetch for invitations (both accept and create) and members listing with generated typed endpoints. Invitations are now typed; members listing remains pending. + 3) Legacy identity: continue using `User` as the primary identity. Keep `Person` in meal-related UIs where the backend requires it, but remove Person as the login/identity concept. ---