MySHopping spec updates
This commit is contained in:
parent
53f8909924
commit
290ad06f0c
2 changed files with 96 additions and 8 deletions
|
|
@ -128,7 +128,7 @@ What exists now
|
||||||
- `src/api/client.ts`: Authorization header provider only; household header injection removed.
|
- `src/api/client.ts`: Authorization header provider only; household header injection removed.
|
||||||
- Domain & UI
|
- Domain & UI
|
||||||
- Member arrays (`chefs`, `consumers`, `cleanup`) normalized to MemberRef `{ id, displayName }` with decoders handling legacy shapes gracefully.
|
- Member arrays (`chefs`, `consumers`, `cleanup`) normalized to MemberRef `{ id, displayName }` with decoders handling legacy shapes gracefully.
|
||||||
- Invitation Accept flow implemented; Household Settings supports sending invitations and listing members (members via temporary raw fetch path-scoped endpoint until typed spec lands).
|
- Invitation Accept flow implemented; Household Settings supports sending invitations and listing members using typed endpoints.
|
||||||
|
|
||||||
Status of tests and typing
|
Status of tests and typing
|
||||||
- All tests pass: 27 files, 48 tests.
|
- All tests pass: 27 files, 48 tests.
|
||||||
|
|
@ -201,13 +201,21 @@ API client
|
||||||
|
|
||||||
SDK
|
SDK
|
||||||
- `src/api/sdk.ts`:
|
- `src/api/sdk.ts`:
|
||||||
- Recipes, meals, shopping fully path-scoped to households. Persons/parse remain via raw fetch until typed coverage.
|
- Recipes, meals, shopping fully path-scoped to households.
|
||||||
|
- Newly typed endpoints (post-latest codegen):
|
||||||
|
- `GET /api/v1/households/{householdSlug}/shopping/current` — current aggregated list.
|
||||||
|
- `GET /api/v1/households/{householdSlug}/shopping/{list_id}` — purchased list by id.
|
||||||
|
- `POST /api/v1/households/{householdSlug}/shopping` — purchase items (storeName + items).
|
||||||
|
- `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.
|
||||||
|
|
||||||
UI
|
UI
|
||||||
- Login Page: Refactored to show email/password form when multitenant flag is enabled; legacy person list retained otherwise. Link to Create Account added.
|
- Login Page: Refactored to show email/password form when multitenant flag is enabled; legacy person list retained otherwise. Link to Create Account added.
|
||||||
- Add `HouseholdSwitcher.vue` to app chrome and wire with router.
|
- Add `HouseholdSwitcher.vue` to app chrome and wire with router.
|
||||||
- Update components that navigate using string paths to use named routes with slug.
|
- 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.
|
- `src/views/HouseholdSettings.vue`: Invite members form wired to `sendInvitation(email)`. Members list rendered from `listMembers()` using the typed endpoint.
|
||||||
- Adjust pages that call SDK/API to pass `{ householdSlug }` path params once client services are migrated.
|
- Adjust pages that call SDK/API to pass `{ householdSlug }` path params once client services are migrated.
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
|
|
@ -223,9 +231,10 @@ Tests
|
||||||
- Household scoping: use typed path params (`{ params: { path: { householdSlug } } }`); do not mutate path strings.
|
- 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.
|
- 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:
|
- Cleanup/migration tasks:
|
||||||
1) Remove X-Household-Slug header injection in `api/client.ts` and refactor services to accept `householdSlug` via typed params.
|
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 for invitations (both accept and create) and members listing with generated typed endpoints. Invitations are now typed; members listing remains pending.
|
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.
|
||||||
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.
|
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.
|
||||||
|
4) Legacy identity: continue using `User` as the primary identity. Keep `Person` in meal-related UIs where required by backend, but remove Person as the login/identity concept.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -252,6 +261,21 @@ 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.
|
- 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.
|
- Replace temporary raw fetch calls (persons, parse, members listing) with typed endpoints when available.
|
||||||
- Implement Google OAuth login and account creation flows.
|
- Implement Google OAuth login and account creation flows.
|
||||||
- Review `MyShoppingPage` usage and remove legacy `getMyShoppingList/saveMyShoppingList` stubs when UI is refactored or removed.
|
- 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.
|
||||||
- Remove the legacy username login shim (`login(username: string)`) and any fallback UI; standardize on email/password (and Google) only.
|
- 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.
|
- Rollout flag: default `VUE_APP_MULTITENANT_ENABLED` to true across environments and plan removal of legacy flat routes and related tests once stable.
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,23 @@ export interface paths {
|
||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/v1/households/{householdSlug}/shopping/current/ingredients": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get?: never;
|
||||||
|
put?: never;
|
||||||
|
/** Request an ingredient for shopping (scoped) */
|
||||||
|
post: operations["requestIngredientV2"];
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
"/healthz": {
|
"/healthz": {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
|
|
@ -481,6 +498,11 @@ export interface components {
|
||||||
mealId?: number | null;
|
mealId?: number | null;
|
||||||
product?: components["schemas"]["Product"] | null;
|
product?: components["schemas"]["Product"] | null;
|
||||||
};
|
};
|
||||||
|
/** IngredientIdWrapper */
|
||||||
|
IngredientIdWrapper: {
|
||||||
|
/** Ingredientid */
|
||||||
|
ingredientId: number;
|
||||||
|
};
|
||||||
/** IngredientPurchaseItemIn */
|
/** IngredientPurchaseItemIn */
|
||||||
IngredientPurchaseItemIn: {
|
IngredientPurchaseItemIn: {
|
||||||
/** Ingredientid */
|
/** Ingredientid */
|
||||||
|
|
@ -822,6 +844,12 @@ export interface components {
|
||||||
imageUrls: string[];
|
imageUrls: string[];
|
||||||
/** Ingredients */
|
/** Ingredients */
|
||||||
ingredients: components["schemas"]["Ingredient"][];
|
ingredients: components["schemas"]["Ingredient"][];
|
||||||
|
/** Createdbyid */
|
||||||
|
createdById: number;
|
||||||
|
createdBy?: components["schemas"]["MemberRef"] | null;
|
||||||
|
/** Hiddenbyid */
|
||||||
|
hiddenById?: number | null;
|
||||||
|
hiddenBy?: components["schemas"]["MemberRef"] | null;
|
||||||
};
|
};
|
||||||
/** RefreshResponse */
|
/** RefreshResponse */
|
||||||
RefreshResponse: {
|
RefreshResponse: {
|
||||||
|
|
@ -882,7 +910,7 @@ export interface components {
|
||||||
storeName: "woolworths" | "coles" | "home";
|
storeName: "woolworths" | "coles" | "home";
|
||||||
/** Purchasedbyid */
|
/** Purchasedbyid */
|
||||||
purchasedById: number;
|
purchasedById: number;
|
||||||
purchasedBy?: components["schemas"]["Person"] | null;
|
purchasedBy?: components["schemas"]["MemberRef"] | null;
|
||||||
/** Items */
|
/** Items */
|
||||||
items: components["schemas"]["ListIngredientItem"][];
|
items: components["schemas"]["ListIngredientItem"][];
|
||||||
};
|
};
|
||||||
|
|
@ -1812,6 +1840,42 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
requestIngredientV2: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
householdSlug: string;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["IngredientIdWrapper"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["ListIngredientItem"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
403: components["responses"]["Problem403"];
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["HTTPValidationError"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
healthz_healthz_get: {
|
healthz_healthz_get: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue