diff --git a/backend/src/main/java/com/recipeapp/shopping/ShoppingListController.java b/backend/src/main/java/com/recipeapp/shopping/ShoppingListController.java index 3589d4b..7f57ba1 100644 --- a/backend/src/main/java/com/recipeapp/shopping/ShoppingListController.java +++ b/backend/src/main/java/com/recipeapp/shopping/ShoppingListController.java @@ -22,7 +22,7 @@ public class ShoppingListController { this.householdResolver = householdResolver; } - @GetMapping("/v1/shopping-lists") + @GetMapping("/v1/shopping-list") public ShoppingListResponse getByWeekStart( @RequestParam(required = false) LocalDate weekStart, Principal principal) { diff --git a/backend/src/main/resources/application-docker.yml b/backend/src/main/resources/application-docker.yml new file mode 100644 index 0000000..c0cb1ec --- /dev/null +++ b/backend/src/main/resources/application-docker.yml @@ -0,0 +1,4 @@ +spring: + flyway: + locations: classpath:db/migration,classpath:db/seed + out-of-order: true diff --git a/backend/src/main/resources/db/migration/V022__add_shopping_list_generated_at.sql b/backend/src/main/resources/db/migration/V022__add_shopping_list_generated_at.sql index 2c4c697..767cb38 100644 --- a/backend/src/main/resources/db/migration/V022__add_shopping_list_generated_at.sql +++ b/backend/src/main/resources/db/migration/V022__add_shopping_list_generated_at.sql @@ -1,2 +1,2 @@ ALTER TABLE shopping_list - ADD COLUMN generated_at timestamptz NOT NULL DEFAULT now(); + ADD COLUMN IF NOT EXISTS generated_at timestamptz NOT NULL DEFAULT now(); diff --git a/backend/src/test/java/com/recipeapp/shopping/ShoppingListControllerTest.java b/backend/src/test/java/com/recipeapp/shopping/ShoppingListControllerTest.java index a09e619..5c897c7 100644 --- a/backend/src/test/java/com/recipeapp/shopping/ShoppingListControllerTest.java +++ b/backend/src/test/java/com/recipeapp/shopping/ShoppingListControllerTest.java @@ -56,7 +56,7 @@ class ShoppingListControllerTest { when(householdResolver.resolve("sarah@example.com")).thenReturn(HOUSEHOLD_ID); when(shoppingService.getByWeekStart(eq(HOUSEHOLD_ID), any())).thenReturn(response); - mockMvc.perform(get("/v1/shopping-lists") + mockMvc.perform(get("/v1/shopping-list") .param("weekStart", "2026-04-06") .principal(() -> "sarah@example.com")) .andExpect(status().isOk()) @@ -69,7 +69,7 @@ class ShoppingListControllerTest { when(householdResolver.resolve("sarah@example.com")).thenReturn(HOUSEHOLD_ID); when(shoppingService.getByWeekStart(eq(HOUSEHOLD_ID), any())).thenReturn(null); - mockMvc.perform(get("/v1/shopping-lists") + mockMvc.perform(get("/v1/shopping-list") .param("weekStart", "2026-04-06") .principal(() -> "sarah@example.com")) .andExpect(status().isNotFound()); diff --git a/frontend/src/lib/api/openapi.json b/frontend/src/lib/api/openapi.json index 4caf3f8..0b6b1ec 100644 --- a/frontend/src/lib/api/openapi.json +++ b/frontend/src/lib/api/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"http://localhost:8080","description":"Generated server url"}],"paths":{"/v1/recipes/{id}":{"get":{"tags":["recipe-controller"],"operationId":"getRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}},"put":{"tags":["recipe-controller"],"operationId":"updateRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}},"delete":{"tags":["recipe-controller"],"operationId":"deleteRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}}},"/v1/week-plans":{"get":{"tags":["week-plan-controller"],"operationId":"getWeekPlan","parameters":[{"name":"weekStart","in":"query","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}},"post":{"tags":["week-plan-controller"],"operationId":"createWeekPlan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWeekPlanRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}}},"/v1/week-plans/{id}/slots":{"post":{"tags":["week-plan-controller"],"operationId":"addSlot","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlotRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SlotResponse"}}}}}}},"/v1/week-plans/{id}/shopping-list":{"post":{"tags":["shopping-list-controller"],"operationId":"generateFromPlan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}}}}},"/v1/week-plans/{id}/confirm":{"post":{"tags":["week-plan-controller"],"operationId":"confirmPlan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}}},"/v1/tags":{"get":{"tags":["tag-controller"],"operationId":"listTags","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TagResponse"}}}}}}},"post":{"tags":["tag-controller"],"operationId":"createTag","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TagResponse"}}}}}}},"/v1/shopping-lists/{id}/items":{"post":{"tags":["shopping-list-controller"],"operationId":"addItem","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddItemRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}}}}},"/v1/recipes":{"get":{"tags":["recipe-controller"],"operationId":"listRecipes","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"effort","in":"query","required":false,"schema":{"type":"string"}},{"name":"isChildFriendly","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"cookTimeMin.lte","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListRecipeSummaryResponse"}}}}}},"post":{"tags":["recipe-controller"],"operationId":"createRecipe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}}},"/v1/pantry-items":{"get":{"tags":["pantry-controller"],"operationId":"listItems","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"post":{"tags":["pantry-controller"],"operationId":"createItem","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePantryItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"/v1/invites/{code}/accept":{"post":{"tags":["household-controller"],"operationId":"acceptInvite","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAcceptInviteResponse"}}}}}}},"/v1/ingredient-categories":{"get":{"tags":["ingredient-category-controller"],"operationId":"listCategories","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IngredientCategoryResponse"}}}}}}},"post":{"tags":["ingredient-category-controller"],"operationId":"createCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngredientCategoryCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/IngredientCategoryResponse"}}}}}}},"/v1/households":{"post":{"tags":["household-controller"],"operationId":"createHousehold","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHouseholdRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseHouseholdResponse"}}}}}}},"/v1/households/mine/invites":{"post":{"tags":["household-controller"],"operationId":"createInvite","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseInviteResponse"}}}}}}},"/v1/cooking-logs":{"get":{"tags":["cooking-log-controller"],"operationId":"listCookingLogs","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":30}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CookingLogResponse"}}}}}}},"post":{"tags":["cooking-log-controller"],"operationId":"createCookingLog","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCookingLogRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CookingLogResponse"}}}}}}},"/v1/auth/signup":{"post":{"tags":["auth-controller"],"operationId":"signup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/auth/logout":{"post":{"tags":["auth-controller"],"operationId":"logout","responses":{"200":{"description":"OK"}}}},"/v1/auth/login":{"post":{"tags":["auth-controller"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/admin/users":{"get":{"tags":["admin-controller"],"operationId":"listUsers","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"isActive","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAdminUserResponse"}}}}}},"post":{"tags":["admin-controller"],"operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserResponse"}}}}}}},"/v1/admin/users/{id}/reset-password":{"post":{"tags":["admin-controller"],"operationId":"resetPassword","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseResetPasswordResponse"}}}}}}},"/v1/week-plans/{planId}/slots/{slotId}":{"delete":{"tags":["week-plan-controller"],"operationId":"deleteSlot","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["week-plan-controller"],"operationId":"updateSlot","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlotRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SlotResponse"}}}}}}},"/v1/shopping-lists/{listId}/items/{itemId}":{"delete":{"tags":["shopping-list-controller"],"operationId":"deleteItem","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["shopping-list-controller"],"operationId":"checkItem","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}}}}},"/v1/pantry-items/{id}":{"delete":{"tags":["pantry-controller"],"operationId":"deleteItem_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["pantry-controller"],"operationId":"updateItem","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePantryItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"/v1/ingredients/{id}":{"patch":{"tags":["ingredient-controller"],"operationId":"patchIngredient","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngredientPatchRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/IngredientResponse"}}}}}}},"/v1/auth/me":{"get":{"tags":["auth-controller"],"operationId":"me","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}},"patch":{"tags":["auth-controller"],"operationId":"updateProfile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/admin/users/{id}":{"patch":{"tags":["admin-controller"],"operationId":"updateUser","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserResponse"}}}}}}},"/v1/week-plans/{id}/variety-score":{"get":{"tags":["week-plan-controller"],"operationId":"getVarietyScore","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/VarietyScoreResponse"}}}}}}},"/v1/week-plans/{id}/suggestions":{"get":{"tags":["week-plan-controller"],"operationId":"getSuggestions","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotDate","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"tags","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"topN","in":"query","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SuggestionResponse"}}}}}}},"/v1/shopping-lists/{id}":{"get":{"tags":["shopping-list-controller"],"operationId":"getShoppingList","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}}}}},"/v1/ingredients":{"get":{"tags":["ingredient-controller"],"operationId":"searchIngredients","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"isStaple","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IngredientResponse"}}}}}}}},"/v1/households/mine":{"get":{"tags":["household-controller"],"operationId":"getMyHousehold","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseHouseholdResponse"}}}}}}},"/v1/households/mine/members":{"get":{"tags":["household-controller"],"operationId":"getMembers","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponse"}}}}}}}},"/v1/admin/audit-log":{"get":{"tags":["admin-controller"],"operationId":"listAuditLog","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"targetUserId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAuditLogResponse"}}}}}}}},"components":{"schemas":{"IngredientEntry":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"newIngredientName":{"type":"string","maxLength":200,"minLength":0},"quantity":{"type":"number","minimum":0.01},"unit":{"type":"string","maxLength":20,"minLength":0},"sortOrder":{"type":"integer","format":"int32"}},"required":["quantity","unit"]},"RecipeCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"minLength":0},"serves":{"type":"integer","format":"int32","maximum":20,"minimum":1},"cookTimeMin":{"type":"integer","format":"int32","minimum":0},"effort":{"type":"string","minLength":1,"pattern":"easy|medium|hard"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string","maxLength":500,"minLength":0},"ingredients":{"type":"array","items":{"$ref":"#/components/schemas/IngredientEntry"},"minItems":1},"steps":{"type":"array","items":{"$ref":"#/components/schemas/StepEntry"}},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1}},"required":["effort","ingredients","name","tagIds"]},"StepEntry":{"type":"object","properties":{"stepNumber":{"type":"integer","format":"int32","minimum":1},"instruction":{"type":"string","minLength":1}},"required":["instruction"]},"CategoryRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"IngredientItem":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"sortOrder":{"type":"integer","format":"int32"}}},"RecipeDetailResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"serves":{"type":"integer","format":"int32"},"cookTimeMin":{"type":"integer","format":"int32"},"effort":{"type":"string"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string"},"ingredients":{"type":"array","items":{"$ref":"#/components/schemas/IngredientItem"}},"steps":{"type":"array","items":{"$ref":"#/components/schemas/StepItem"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagItem"}}}},"StepItem":{"type":"object","properties":{"stepNumber":{"type":"integer","format":"int32"},"instruction":{"type":"string"}}},"TagItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"tagType":{"type":"string"}}},"CreateWeekPlanRequest":{"type":"object","properties":{"weekStart":{"type":"string","format":"date"}},"required":["weekStart"]},"SlotRecipe":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"effort":{"type":"string"},"cookTimeMin":{"type":"integer","format":"int32"},"heroImageUrl":{"type":"string"}}},"SlotResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slotDate":{"type":"string","format":"date"},"recipe":{"$ref":"#/components/schemas/SlotRecipe"}}},"WeekPlanResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"weekStart":{"type":"string","format":"date"},"status":{"type":"string"},"confirmedAt":{"type":"string","format":"date-time"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/SlotResponse"}}}},"CreateSlotRequest":{"type":"object","properties":{"slotDate":{"type":"string","format":"date"},"recipeId":{"type":"string","format":"uuid"}},"required":["recipeId","slotDate"]},"ShoppingListItemResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"isChecked":{"type":"boolean"},"checkedBy":{"type":"string","format":"uuid"},"sourceRecipes":{"type":"array","items":{"type":"string","format":"uuid"}}}},"ShoppingListResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"weekPlanId":{"type":"string","format":"uuid"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}},"TagCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":0},"tagType":{"type":"string","minLength":1,"pattern":"protein|dietary|cuisine|other"}},"required":["name","tagType"]},"TagResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"tagType":{"type":"string"}}},"AddItemRequest":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"customName":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}},"CreatePantryItemRequest":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"customName":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"PantryItemResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"AcceptInviteResponse":{"type":"object","properties":{"householdId":{"type":"string","format":"uuid"},"householdName":{"type":"string"},"role":{"type":"string"}}},"ApiResponseAcceptInviteResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/AcceptInviteResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"Meta":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer","format":"int64"},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"IngredientCategoryCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":0}},"required":["name"]},"IngredientCategoryResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"CreateHouseholdRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"minLength":0}},"required":["name"]},"ApiResponseHouseholdResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/HouseholdResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"HouseholdResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"members":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponse"}}}},"MemberResponse":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"role":{"type":"string"},"joinedAt":{"type":"string","format":"date-time"}}},"ApiResponseInviteResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/InviteResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"InviteResponse":{"type":"object","properties":{"inviteCode":{"type":"string"},"shareUrl":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}},"CreateCookingLogRequest":{"type":"object","properties":{"recipeId":{"type":"string","format":"uuid"},"cookedOn":{"type":"string","format":"date"}},"required":["recipeId"]},"CookingLogResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"recipeId":{"type":"string","format":"uuid"},"recipeName":{"type":"string"},"cookedOn":{"type":"string","format":"date"},"cookedBy":{"type":"string","format":"uuid"}}},"SignupRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"password":{"type":"string","maxLength":2147483647,"minLength":8},"displayName":{"type":"string","maxLength":100,"minLength":0}},"required":["displayName","email","password"]},"ApiResponseUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/UserResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"UserResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"displayName":{"type":"string"},"householdId":{"type":"string","format":"uuid"},"householdName":{"type":"string"},"householdRole":{"type":"string"},"systemRole":{"type":"string"}}},"LoginRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"password":{"type":"string","minLength":1}},"required":["email","password"]},"CreateUserRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"displayName":{"type":"string","maxLength":100,"minLength":0},"tempPassword":{"type":"string","maxLength":2147483647,"minLength":8},"systemRole":{"type":"string"}},"required":["displayName","email","tempPassword"]},"AdminUserResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"displayName":{"type":"string"},"systemRole":{"type":"string"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"ApiResponseAdminUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/AdminUserResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ResetPasswordRequest":{"type":"object","properties":{"tempPassword":{"type":"string","maxLength":2147483647,"minLength":8},"reason":{"type":"string"}},"required":["tempPassword"]},"ApiResponseResetPasswordResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/ResetPasswordResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ResetPasswordResponse":{"type":"object","properties":{"message":{"type":"string"},"mustChangePassword":{"type":"boolean"}}},"UpdateSlotRequest":{"type":"object","properties":{"recipeId":{"type":"string","format":"uuid"}},"required":["recipeId"]},"CheckItemRequest":{"type":"object","properties":{"isChecked":{"type":"boolean"}}},"UpdatePantryItemRequest":{"type":"object","properties":{"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"IngredientPatchRequest":{"type":"object","properties":{"name":{"type":"string"},"isStaple":{"type":"boolean"},"categoryId":{"type":"string","format":"uuid"}}},"IngredientResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"isStaple":{"type":"boolean"}}},"UpdateProfileRequest":{"type":"object","properties":{"displayName":{"type":"string","maxLength":100,"minLength":0},"currentPassword":{"type":"string"},"newPassword":{"type":"string","maxLength":2147483647,"minLength":8}}},"UpdateUserRequest":{"type":"object","properties":{"displayName":{"type":"string"},"email":{"type":"string"},"systemRole":{"type":"string"},"isActive":{"type":"boolean"}}},"IngredientOverlap":{"type":"object","properties":{"ingredientName":{"type":"string"},"days":{"type":"array","items":{"type":"string","format":"date"}}}},"TagRepeat":{"type":"object","properties":{"tagName":{"type":"string"},"tagType":{"type":"string"},"days":{"type":"array","items":{"type":"string","format":"date"}}}},"VarietyScoreResponse":{"type":"object","properties":{"score":{"type":"number","format":"double"},"tagRepeats":{"type":"array","items":{"$ref":"#/components/schemas/TagRepeat"}},"ingredientOverlaps":{"type":"array","items":{"$ref":"#/components/schemas/IngredientOverlap"}},"recentRepeats":{"type":"array","items":{"type":"string"}},"duplicatesInPlan":{"type":"array","items":{"type":"string"}}}},"SuggestionItem":{"type":"object","properties":{"recipe":{"$ref":"#/components/schemas/SlotRecipe"},"simulatedScore":{"type":"number","format":"double"}}},"SuggestionResponse":{"type":"object","properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SuggestionItem"}}}},"ApiResponseListRecipeSummaryResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/RecipeSummaryResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"RecipeSummaryResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"serves":{"type":"integer","format":"int32"},"cookTimeMin":{"type":"integer","format":"int32"},"effort":{"type":"string"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string"}}},"ApiResponseListAdminUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"ApiResponseListAuditLogResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"AuditLogResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"adminId":{"type":"string","format":"uuid"},"adminEmail":{"type":"string"},"targetUserId":{"type":"string","format":"uuid"},"targetEmail":{"type":"string"},"action":{"type":"string"},"detail":{"type":"object","additionalProperties":{}},"performedAt":{"type":"string","format":"date-time"}}}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"http://localhost:8080","description":"Generated server url"}],"paths":{"/v1/recipes/{id}":{"get":{"tags":["recipe-controller"],"operationId":"getRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}},"put":{"tags":["recipe-controller"],"operationId":"updateRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}},"delete":{"tags":["recipe-controller"],"operationId":"deleteRecipe","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}}},"/v1/week-plans":{"get":{"tags":["week-plan-controller"],"operationId":"getWeekPlan","parameters":[{"name":"weekStart","in":"query","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}},"post":{"tags":["week-plan-controller"],"operationId":"createWeekPlan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWeekPlanRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}}},"/v1/week-plans/{id}/slots":{"post":{"tags":["week-plan-controller"],"operationId":"addSlot","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlotRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SlotResponse"}}}}}}},"/v1/week-plans/{id}/shopping-list":{"post":{"tags":["shopping-list-controller"],"operationId":"generateFromPlan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}}}}},"/v1/week-plans/{id}/confirm":{"post":{"tags":["week-plan-controller"],"operationId":"confirmPlan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WeekPlanResponse"}}}}}}},"/v1/tags":{"get":{"tags":["tag-controller"],"operationId":"listTags","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TagResponse"}}}}}}},"post":{"tags":["tag-controller"],"operationId":"createTag","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TagResponse"}}}}}}},"/v1/shopping-lists/{id}/items":{"post":{"tags":["shopping-list-controller"],"operationId":"addItem","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddItemRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}}}}},"/v1/recipes":{"get":{"tags":["recipe-controller"],"operationId":"listRecipes","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"effort","in":"query","required":false,"schema":{"type":"string"}},{"name":"isChildFriendly","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"cookTimeMin.lte","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListRecipeSummaryResponse"}}}}}},"post":{"tags":["recipe-controller"],"operationId":"createRecipe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecipeDetailResponse"}}}}}}},"/v1/pantry-items":{"get":{"tags":["pantry-controller"],"operationId":"listItems","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"post":{"tags":["pantry-controller"],"operationId":"createItem","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePantryItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"/v1/invites/{code}/accept":{"post":{"tags":["household-controller"],"operationId":"acceptInvite","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAcceptInviteResponse"}}}}}}},"/v1/ingredient-categories":{"get":{"tags":["ingredient-category-controller"],"operationId":"listCategories","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IngredientCategoryResponse"}}}}}}},"post":{"tags":["ingredient-category-controller"],"operationId":"createCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngredientCategoryCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/IngredientCategoryResponse"}}}}}}},"/v1/households":{"post":{"tags":["household-controller"],"operationId":"createHousehold","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHouseholdRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseHouseholdResponse"}}}}}}},"/v1/households/mine/invites":{"post":{"tags":["household-controller"],"operationId":"createInvite","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseInviteResponse"}}}}}}},"/v1/cooking-logs":{"get":{"tags":["cooking-log-controller"],"operationId":"listCookingLogs","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":30}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CookingLogResponse"}}}}}}},"post":{"tags":["cooking-log-controller"],"operationId":"createCookingLog","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCookingLogRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CookingLogResponse"}}}}}}},"/v1/auth/signup":{"post":{"tags":["auth-controller"],"operationId":"signup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/auth/logout":{"post":{"tags":["auth-controller"],"operationId":"logout","responses":{"200":{"description":"OK"}}}},"/v1/auth/login":{"post":{"tags":["auth-controller"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/admin/users":{"get":{"tags":["admin-controller"],"operationId":"listUsers","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"isActive","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAdminUserResponse"}}}}}},"post":{"tags":["admin-controller"],"operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserResponse"}}}}}}},"/v1/admin/users/{id}/reset-password":{"post":{"tags":["admin-controller"],"operationId":"resetPassword","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseResetPasswordResponse"}}}}}}},"/v1/week-plans/{planId}/slots/{slotId}":{"delete":{"tags":["week-plan-controller"],"operationId":"deleteSlot","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["week-plan-controller"],"operationId":"updateSlot","parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlotRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SlotResponse"}}}}}}},"/v1/shopping-lists/{listId}/items/{itemId}":{"delete":{"tags":["shopping-list-controller"],"operationId":"deleteItem","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["shopping-list-controller"],"operationId":"checkItem","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}}}}},"/v1/pantry-items/{id}":{"delete":{"tags":["pantry-controller"],"operationId":"deleteItem_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}},"patch":{"tags":["pantry-controller"],"operationId":"updateItem","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePantryItemRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PantryItemResponse"}}}}}}},"/v1/ingredients/{id}":{"patch":{"tags":["ingredient-controller"],"operationId":"patchIngredient","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngredientPatchRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/IngredientResponse"}}}}}}},"/v1/auth/me":{"get":{"tags":["auth-controller"],"operationId":"me","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}},"patch":{"tags":["auth-controller"],"operationId":"updateProfile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUserResponse"}}}}}}},"/v1/admin/users/{id}":{"patch":{"tags":["admin-controller"],"operationId":"updateUser","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserResponse"}}}}}}},"/v1/week-plans/{id}/variety-score":{"get":{"tags":["week-plan-controller"],"operationId":"getVarietyScore","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/VarietyScoreResponse"}}}}}}},"/v1/week-plans/{id}/suggestions":{"get":{"tags":["week-plan-controller"],"operationId":"getSuggestions","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slotDate","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"tags","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"topN","in":"query","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SuggestionResponse"}}}}}}},"/v1/shopping-lists/{id}":{"get":{"tags":["shopping-list-controller"],"operationId":"getShoppingList","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}}}}},"/v1/shopping-list":{"get":{"tags":["shopping-list-controller"],"operationId":"getByWeekStart","parameters":[{"name":"weekStart","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}}}}},"/v1/ingredients":{"get":{"tags":["ingredient-controller"],"operationId":"searchIngredients","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"isStaple","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IngredientResponse"}}}}}}}},"/v1/households/mine":{"get":{"tags":["household-controller"],"operationId":"getMyHousehold","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseHouseholdResponse"}}}}}}},"/v1/households/mine/members":{"get":{"tags":["household-controller"],"operationId":"getMembers","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponse"}}}}}}}},"/v1/admin/audit-log":{"get":{"tags":["admin-controller"],"operationId":"listAuditLog","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"targetUserId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAuditLogResponse"}}}}}}}},"components":{"schemas":{"IngredientEntry":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"newIngredientName":{"type":"string","maxLength":200,"minLength":0},"quantity":{"type":"number","minimum":0.01},"unit":{"type":"string","maxLength":20,"minLength":0},"sortOrder":{"type":"integer","format":"int32"}},"required":["quantity","unit"]},"RecipeCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"minLength":0},"serves":{"type":"integer","format":"int32","maximum":20,"minimum":1},"cookTimeMin":{"type":"integer","format":"int32","minimum":0},"effort":{"type":"string","minLength":1,"pattern":"easy|medium|hard"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string","maxLength":500,"minLength":0},"ingredients":{"type":"array","items":{"$ref":"#/components/schemas/IngredientEntry"},"minItems":1},"steps":{"type":"array","items":{"$ref":"#/components/schemas/StepEntry"}},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1}},"required":["effort","ingredients","name","tagIds"]},"StepEntry":{"type":"object","properties":{"stepNumber":{"type":"integer","format":"int32","minimum":1},"instruction":{"type":"string","minLength":1}},"required":["instruction"]},"CategoryRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"IngredientItem":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"sortOrder":{"type":"integer","format":"int32"}}},"RecipeDetailResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"serves":{"type":"integer","format":"int32"},"cookTimeMin":{"type":"integer","format":"int32"},"effort":{"type":"string"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string"},"ingredients":{"type":"array","items":{"$ref":"#/components/schemas/IngredientItem"}},"steps":{"type":"array","items":{"$ref":"#/components/schemas/StepItem"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagItem"}}}},"StepItem":{"type":"object","properties":{"stepNumber":{"type":"integer","format":"int32"},"instruction":{"type":"string"}}},"TagItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"tagType":{"type":"string"}}},"CreateWeekPlanRequest":{"type":"object","properties":{"weekStart":{"type":"string","format":"date"}},"required":["weekStart"]},"SlotRecipe":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"effort":{"type":"string"},"cookTimeMin":{"type":"integer","format":"int32"},"heroImageUrl":{"type":"string"}}},"SlotResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slotDate":{"type":"string","format":"date"},"recipe":{"$ref":"#/components/schemas/SlotRecipe"}}},"WeekPlanResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"weekStart":{"type":"string","format":"date"},"status":{"type":"string"},"confirmedAt":{"type":"string","format":"date-time"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/SlotResponse"}}}},"CreateSlotRequest":{"type":"object","properties":{"slotDate":{"type":"string","format":"date"},"recipeId":{"type":"string","format":"uuid"}},"required":["recipeId","slotDate"]},"RecipeRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"ShoppingListItemResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"isChecked":{"type":"boolean"},"checkedBy":{"type":"string","format":"uuid"},"sourceRecipes":{"type":"array","items":{"$ref":"#/components/schemas/RecipeRef"}}}},"ShoppingListResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"weekPlanId":{"type":"string","format":"uuid"},"generatedAt":{"type":"string","format":"date-time"},"filteredStaplesCount":{"type":"integer","format":"int32"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ShoppingListItemResponse"}}}},"TagCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":0},"tagType":{"type":"string","minLength":1,"pattern":"protein|dietary|cuisine|other"}},"required":["name","tagType"]},"TagResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"tagType":{"type":"string"}}},"AddItemRequest":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"customName":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}},"CreatePantryItemRequest":{"type":"object","properties":{"ingredientId":{"type":"string","format":"uuid"},"customName":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"PantryItemResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ingredientId":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"AcceptInviteResponse":{"type":"object","properties":{"householdId":{"type":"string","format":"uuid"},"householdName":{"type":"string"},"role":{"type":"string"}}},"ApiResponseAcceptInviteResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/AcceptInviteResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"Meta":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer","format":"int64"},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"IngredientCategoryCreateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":0}},"required":["name"]},"IngredientCategoryResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"CreateHouseholdRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"minLength":0}},"required":["name"]},"ApiResponseHouseholdResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/HouseholdResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"HouseholdResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"members":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponse"}}}},"MemberResponse":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"role":{"type":"string"},"joinedAt":{"type":"string","format":"date-time"}}},"ApiResponseInviteResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/InviteResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"InviteResponse":{"type":"object","properties":{"inviteCode":{"type":"string"},"shareUrl":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}},"CreateCookingLogRequest":{"type":"object","properties":{"recipeId":{"type":"string","format":"uuid"},"cookedOn":{"type":"string","format":"date"}},"required":["recipeId"]},"CookingLogResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"recipeId":{"type":"string","format":"uuid"},"recipeName":{"type":"string"},"cookedOn":{"type":"string","format":"date"},"cookedBy":{"type":"string","format":"uuid"}}},"SignupRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"password":{"type":"string","maxLength":2147483647,"minLength":8},"displayName":{"type":"string","maxLength":100,"minLength":0}},"required":["displayName","email","password"]},"ApiResponseUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/UserResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"UserResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"displayName":{"type":"string"},"householdId":{"type":"string","format":"uuid"},"householdName":{"type":"string"},"householdRole":{"type":"string"},"systemRole":{"type":"string"}}},"LoginRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"password":{"type":"string","minLength":1}},"required":["email","password"]},"CreateUserRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"displayName":{"type":"string","maxLength":100,"minLength":0},"tempPassword":{"type":"string","maxLength":2147483647,"minLength":8},"systemRole":{"type":"string"}},"required":["displayName","email","tempPassword"]},"AdminUserResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"displayName":{"type":"string"},"systemRole":{"type":"string"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"ApiResponseAdminUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/AdminUserResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ResetPasswordRequest":{"type":"object","properties":{"tempPassword":{"type":"string","maxLength":2147483647,"minLength":8},"reason":{"type":"string"}},"required":["tempPassword"]},"ApiResponseResetPasswordResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"$ref":"#/components/schemas/ResetPasswordResponse"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ResetPasswordResponse":{"type":"object","properties":{"message":{"type":"string"},"mustChangePassword":{"type":"boolean"}}},"UpdateSlotRequest":{"type":"object","properties":{"recipeId":{"type":"string","format":"uuid"}},"required":["recipeId"]},"CheckItemRequest":{"type":"object","properties":{"isChecked":{"type":"boolean"}}},"UpdatePantryItemRequest":{"type":"object","properties":{"quantity":{"type":"number"},"unit":{"type":"string"},"bestBefore":{"type":"string","format":"date"},"openedOn":{"type":"string","format":"date"}}},"IngredientPatchRequest":{"type":"object","properties":{"name":{"type":"string"},"isStaple":{"type":"boolean"},"categoryId":{"type":"string","format":"uuid"}}},"IngredientResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryRef"},"isStaple":{"type":"boolean"}}},"UpdateProfileRequest":{"type":"object","properties":{"displayName":{"type":"string","maxLength":100,"minLength":0},"currentPassword":{"type":"string"},"newPassword":{"type":"string","maxLength":2147483647,"minLength":8}}},"UpdateUserRequest":{"type":"object","properties":{"displayName":{"type":"string"},"email":{"type":"string"},"systemRole":{"type":"string"},"isActive":{"type":"boolean"}}},"IngredientOverlap":{"type":"object","properties":{"ingredientName":{"type":"string"},"days":{"type":"array","items":{"type":"string","format":"date"}}}},"TagRepeat":{"type":"object","properties":{"tagName":{"type":"string"},"tagType":{"type":"string"},"days":{"type":"array","items":{"type":"string","format":"date"}}}},"VarietyScoreResponse":{"type":"object","properties":{"score":{"type":"number","format":"double"},"tagRepeats":{"type":"array","items":{"$ref":"#/components/schemas/TagRepeat"}},"ingredientOverlaps":{"type":"array","items":{"$ref":"#/components/schemas/IngredientOverlap"}},"recentRepeats":{"type":"array","items":{"type":"string"}},"duplicatesInPlan":{"type":"array","items":{"type":"string"}}}},"SuggestionItem":{"type":"object","properties":{"recipe":{"$ref":"#/components/schemas/SlotRecipe"},"simulatedScore":{"type":"number","format":"double"}}},"SuggestionResponse":{"type":"object","properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SuggestionItem"}}}},"ApiResponseListRecipeSummaryResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/RecipeSummaryResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"RecipeSummaryResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"serves":{"type":"integer","format":"int32"},"cookTimeMin":{"type":"integer","format":"int32"},"effort":{"type":"string"},"isChildFriendly":{"type":"boolean"},"heroImageUrl":{"type":"string"}}},"ApiResponseListAdminUserResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"ApiResponseListAuditLogResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"AuditLogResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"adminId":{"type":"string","format":"uuid"},"adminEmail":{"type":"string"},"targetUserId":{"type":"string","format":"uuid"},"targetEmail":{"type":"string"},"action":{"type":"string"},"detail":{"type":"object","additionalProperties":{}},"performedAt":{"type":"string","format":"date-time"}}}}}} \ No newline at end of file diff --git a/frontend/src/lib/api/schema.d.ts b/frontend/src/lib/api/schema.d.ts index aeea7e6..74d1952 100644 --- a/frontend/src/lib/api/schema.d.ts +++ b/frontend/src/lib/api/schema.d.ts @@ -452,6 +452,22 @@ export interface paths { patch?: never; trace?: never; }; + "/v1/shopping-list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["getByWeekStart"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/v1/ingredients": { parameters: { query?: never; @@ -624,6 +640,11 @@ export interface components { /** Format: uuid */ recipeId: string; }; + RecipeRef: { + /** Format: uuid */ + id?: string; + name?: string; + }; ShoppingListItemResponse: { /** Format: uuid */ id?: string; @@ -636,13 +657,17 @@ export interface components { isChecked?: boolean; /** Format: uuid */ checkedBy?: string; - sourceRecipes?: string[]; + sourceRecipes?: components["schemas"]["RecipeRef"][]; }; ShoppingListResponse: { /** Format: uuid */ id?: string; /** Format: uuid */ weekPlanId?: string; + /** Format: date-time */ + generatedAt?: string; + /** Format: int32 */ + filteredStaplesCount?: number; items?: components["schemas"]["ShoppingListItemResponse"][]; }; TagCreateRequest: { @@ -1902,6 +1927,28 @@ export interface operations { }; }; }; + getByWeekStart: { + parameters: { + query?: { + weekStart?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": components["schemas"]["ShoppingListResponse"]; + }; + }; + }; + }; searchIngredients: { parameters: { query?: {