API Service Contracts Demo 1 - COS301-SE-2026/Mealchemy GitHub Wiki

Mealchemy API Service Contracts


Table of Contents


1. Authentication Services

User Registration Service:

Description: Registers a new user account and returns an authentication token.

Endpoint: POST /auth/register

Inputs:

Name Type Description
email string A valid, non-blank email address
password string User's password, minimum 8 characters
displayName string User's display name, max 80 characters

Outputs:

Name Type Description
user_id integer The newly created user's unique identifier
token string Access token for authenticated requests
onboarding_required boolean Whether the user still needs to complete onboarding

Usage / Interaction Rules:

  • Send a POST request to /auth/register with email, password, and displayName in JSON format
  • Returns 201 Created on success
  • Returns 400 Bad Request if validation fails (e.g. invalid email)

User Login Service

Description: Authenticates an existing user and returns an access token.

Endpoint: POST /auth/login

Inputs:

Name Type Description
email string A valid, non-blank email address
password string User's non-blank password

Outputs:

Name Type Description
user_id integer The authenticated user's unique identifier
token string Access token for authenticated requests
onboarding_required boolean Whether the user still needs to complete onboarding

Usage / Interaction Rules:

  • Send a POST request to /auth/login with email and password in JSON format
  • Returns 200 OK on success
  • Returns 401 Unauthorized if credentials are invalid

User Logout Service

Description: Terminates the current user's authenticated session.

Endpoint: POST /auth/logout

Inputs: None

Outputs: None

Usage / Interaction Rules:

  • Send a POST request to /auth/logout - no request body required
  • Returns 204 No Content on success

2. Preference Services:

Get User Preferences Service

Description: Retrieves the dietary preferences and restrictions for the authenticated user.

Endpoint: GET /user/preferences

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal

Outputs:

Name Type Description
dietary_restrictions List<string> User's dietary restrictions (e.g. vegan, halal)
allergies List<string> User's listed allergies
disliked_ingredients List<string> Ingredients the user wants excluded
flavour_profile List<string> User's preferred flavour profiles

Usage / Interaction Rules:

  • Send a GET request to /user/preferences - no request body required
  • Caller must be authenticated; JWT token must be present in the request header
  • Returns 200 OK with the user's current preferences

Update User Preferences Service

Description: Replaces the authenticated user's dietary preferences with the provided values.

Endpoint: PUT /user/preferences

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal
dietary_restrictions List<string> Updated dietary restrictions
allergies List<string> Updated allergies
disliked_ingredients List<string> Updated disliked ingredients
flavour_profile List<string> Updated flavour profiles

Outputs:

Name Type Description
dietary_restrictions List<string> Saved dietary restrictions
allergies List<string> Saved allergies
disliked_ingredients List<string> Saved disliked ingredients
flavour_profile List<string> Saved flavour profiles

Usage / Interaction Rules:

  • Send a PUT request to /user/preferences with a JSON body containing any combination of the four preference fields
  • Caller must be authenticated; JWT token must be present in the request header
  • Returns 200 OK with the full updated preferences object

3. Vault Services:

Get Vaults By Owner

Description: Retrieves all vaults belonging to a specific owner.

Endpoint: GET /vaults/owner/{ownerId}

Inputs:

Name Type Description
ownerId integer Path variable identifying the owner

Outputs:

Name Type Description
vault_id integer Unique vault identifier
owner_id integer ID of the vault's owner
vault_type VaultType (enum) Type/category of the vault
name string Name of the vault
created_at OffsetDateTime Timestamp of vault creation

Usage / Interaction Rules:

  • Send a GET request to /vaults/owner/{ownerId}
  • Returns 200 OK with a list of vaults

Get Vault By ID

Description: Retrieves a single vault by its unique identifier.

Endpoint: GET /vaults/{id}

Inputs:

Name Type Description
id integer Path variable for the vault

Outputs:

Name Type Description
vault_id integer Unique vault identifier
owner_id integer ID of the vault's owner
vault_type VaultType (enum) Type/category of the vault
name string Name of the vault
created_at OffsetDateTime Timestamp of vault creation

Usage / Interaction Rules:

  • Send a GET request to /vaults/{id}
  • Returns 200 OK with the vault object

Create Vault

Description: Creates a new vault for a given owner.

Endpoint: POST /vaults

Inputs:

Name Type Description
owner_id integer The owner of the vault
vault_type VaultType (enum) Type/category of the vault
name string Name of the vault

Outputs:

Name Type Description
vault_id integer Unique vault identifier
owner_id integer ID of the vault's owner
vault_type VaultType (enum) Type/category of the vault
name string Name of the vault
created_at OffsetDateTime Timestamp of vault creation

Usage / Interaction Rules:

  • Send a POST request to /vaults with owner_id, vault_type, and name in JSON format
  • Returns 200 OK with the created vault

Update Vault

Description: Replaces an existing vault's details with the provided values.

Endpoint: PUT /vaults/{id}

Inputs:

Name Type Description
id integer Path variable for the vault to update
owner_id integer Updated owner ID
vault_type VaultType (enum) Updated vault type
name string Updated vault name

Outputs:

Name Type Description
vault_id integer Unique vault identifier
owner_id integer ID of the vault's owner
vault_type VaultType (enum) Type/category of the vault
name string Name of the vault
created_at OffsetDateTime Timestamp of vault creation

Usage / Interaction Rules:

  • Send a PUT request to /vaults/{id} with updated fields in JSON format
  • Returns 200 OK with the updated vault

Delete Vault

Description: Permanently deletes a vault by its ID.

Endpoint: DELETE /vaults/{id}

Inputs:

Name Type Description
id integer Path variable for the vault to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /vaults/{id}
  • Returns 200 OK (no body)

4. Vault Folder Services:

Get Folders By Vault ID

Description: Retrieves all folders within a specific vault.

Endpoint: GET /folders/vault/{vaultId}

Inputs:

Name Type Description
vaultId integer Path variable identifying the vault

Outputs:

Name Type Description
folder_id integer Unique folder identifier
vault_id integer ID of the parent vault
folder_name string Name of the folder
created_at OffsetDateTime Timestamp of folder creation

Usage / Interaction Rules:

  • Send a GET request to /folders/vault/{vaultId}
  • Returns 200 OK with a list of folders

Get Folder By Name

Description: Retrieves a single vault folder by its name.

Endpoint: GET /folders/folder/name/{name}

Inputs:

Name Type Description
name string Path variable for the folder name

Outputs:

Name Type Description
folder_id integer Unique folder identifier
vault_id integer ID of the parent vault
folder_name string Name of the folder
created_at OffsetDateTime Timestamp of folder creation

Usage / Interaction Rules:

  • Send a GET request to /folders/folder/name/{name}
  • Returns 200 OK with the matched folder

Get Folder By ID

Description: Retrieves a single vault folder by its unique identifier.

Endpoint: GET /folders/folder/{id}

Inputs:

Name Type Description
id integer Path variable for the folder

Outputs:

Name Type Description
folder_id integer Unique folder identifier
vault_id integer ID of the parent vault
folder_name string Name of the folder
created_at OffsetDateTime Timestamp of folder creation

Usage / Interaction Rules:

  • Send a GET request to /folders/folder/{id}
  • Returns 200 OK with the folder object

Create Vault Folder

Description: Creates a new folder within a specified vault.

Endpoint: POST /folders

Inputs:

Name Type Description
vault_id integer The vault to create the folder in
folder_name string Name of the new folder

Outputs:

Name Type Description
folder_id integer Unique folder identifier
vault_id integer ID of the parent vault
folder_name string Name of the folder
created_at OffsetDateTime Timestamp of folder creation

Usage / Interaction Rules:

  • Send a POST request to /folders with vault_id and folder_name in JSON format
  • Returns 200 OK with the created folder

Update Vault Folder

Description: Updates an existing folder's details.

Endpoint: PUT /folders/{id}

Inputs:

Name Type Description
id integer Path variable for the folder to update
vault_id integer Updated parent vault ID
folder_name string Updated folder name

Outputs:

Name Type Description
folder_id integer Unique folder identifier
vault_id integer ID of the parent vault
folder_name string Name of the folder
created_at OffsetDateTime Timestamp of folder creation

Usage / Interaction Rules:

  • Send a PUT request to /folders/{id} with updated fields in JSON format
  • Returns 200 OK with the updated folder

Delete Vault Folder

Description: Permanently deletes a folder by its ID.

Endpoint: DELETE /folders/{id}

Inputs:

Name Type Description
id integer Path variable for the folder to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /folders/{id}
  • Returns 200 OK (no body)

5. Vault Folder Recipe Services

Get Recipes By Folder ID

Description: Retrieves all recipe entries associated with a specific folder.

Endpoint: GET /recipefolders/recipes/{folderId}

Inputs:

Name Type Description
folderId integer Path variable identifying the folder

Outputs:

Name Type Description
id integer Unique ID of the association record
folder_id integer The folder the recipe belongs to
recipe_id integer The linked recipe
added_at OffsetDateTime When the recipe was added to the folder

Usage / Interaction Rules:

  • Send a GET request to /recipefolders/recipes/{folderId}
  • Returns 200 OK with a list of recipe-folder associations

Get Folders By Recipe ID

Description: Retrieves all folder entries that contain a specific recipe.

Endpoint: GET /recipefolders/folders/{recipeId}

Inputs:

Name Type Description
recipeId integer Path variable identifying the recipe

Outputs:

Name Type Description
id integer Unique ID of the association record
folder_id integer The folder the recipe belongs to
recipe_id integer The linked recipe
added_at OffsetDateTime When the recipe was added to the folder

Usage / Interaction Rules:

  • Send a GET request to /recipefolders/folders/{recipeId}
  • Returns 200 OK with a list of folder-recipe associations

Get Folder Recipe By ID

Description: Retrieves a single folder-recipe association by its ID.

Endpoint: GET /recipefolders/{id}

Inputs:

Name Type Description
id integer Path variable for the association record

Outputs:

Name Type Description
id integer Unique ID of the association record
folder_id integer The folder the recipe belongs to
recipe_id integer The linked recipe
added_at OffsetDateTime When the recipe was added to the folder

Usage / Interaction Rules:

  • Send a GET request to /recipefolders/{id}
  • Returns 200 OK

Create Vault Folder Recipe

Description: Links a recipe to a folder by creating a new association record.

Endpoint: POST /recipefolders

Inputs:

Name Type Description
folder_id integer The folder to link to
recipe_id integer The recipe to link

Outputs:

Name Type Description
id integer Unique ID of the association record
folder_id integer The folder the recipe belongs to
recipe_id integer The linked recipe
added_at OffsetDateTime When the recipe was added to the folder

Usage / Interaction Rules:

  • Send a POST request to /recipefolders with folder_id and recipe_id in JSON format
  • Returns 200 OK with the created association record

Update Vault Folder Recipe

Description: Updates an existing folder-recipe association.

Endpoint: PUT /recipefolders/{id}

Inputs:

Name Type Description
id integer Path variable for the association to update
folder_id integer Updated folder ID
recipe_id integer Updated recipe ID

Outputs:

Name Type Description
id integer Unique ID of the association record
folder_id integer The folder the recipe belongs to
recipe_id integer The linked recipe
added_at OffsetDateTime When the recipe was added to the folder

Usage / Interaction Rules:

  • Send a PUT request to /recipefolders/{id} with updated fields in JSON format
  • Returns 200 OK with the updated association record

Delete Vault Folder Recipe

Description: Removes a folder-recipe association by its ID.

Endpoint: DELETE /recipefolders/{id}

Inputs:

Name Type Description
id integer Path variable for the association to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /recipefolders/{id}
  • Returns 200 OK (no body)

6. Recipe Services:

Get All Recipes

Description: Retrieves all recipes

Endpoint: GET /recipes/all

Inputs: None

Outputs:

Name Type Description
recipeId integer Unique recipe identifier
ownerId integer ID of the recipe's owner
title string Recipe title
description string null
cuisineType string Cuisine category, validated against Flavour Profile Options
prepTimeMins integer Preparation time in minutes
cookingTimeMins integer Cooking time in minutes
servingSize integer Number of servings
photoUrl string null
videoUrl string null
externalUrl string null
isCommunityPublished boolean Whether the recipe is visible to the community
createdAt OffsetDateTime Timestamp of recipe creation
updatedAt OffsetDateTime Timestamp of last update
parentRecipeId integer ID of the source recipe this was copied from, if any

Usage / Interaction Rules:

  • Send a GET request to /recipes/all - no request body
  • Returns 200 OK with a list of all recipes

Get Single Recipe

Description: Retrieves one recipe by ID.

Endpoint: GET /recipes/single/{id}

Inputs:

Name Type Description
id integer Path variable for the recipe

Outputs:

Name Type Description
recipeId integer Unique recipe identifier
ownerId integer ID of the recipe's owner
title string Recipe title
description string null
cuisineType string Cuisine category, validated against Flavour Profile Options
prepTimeMins integer Preparation time in minutes
cookingTimeMins integer Cooking time in minutes
servingSize integer Number of servings
photoUrl string null
videoUrl string null
externalUrl string null
isCommunityPublished boolean Whether the recipe is visible to the community
createdAt OffsetDateTime Timestamp of recipe creation
updatedAt OffsetDateTime Timestamp of last update
parentRecipeId integer ID of the source recipe this was copied from, if any

Usage / Interaction Rules:

  • Send a GET request to /recipes/single/{id} - no request body
  • Returns 200 OK with the recipe object

Create Recipe

Description: Creates a bare recipe with no ingredients or steps.

Endpoint: POST /recipes/create

Inputs:

Name Type Description
ownerId string Extracted automatically from the JWT token via @AuthenticationPrincipal
title string Recipe title, required, not blank
description string Optional recipe description
cuisineType string Required, not blank; must match an existing Flavour Profile Options value
prepTimeMins integer Required
cookingTimeMins integer Required
servingSize integer Required
photoUrl string Optional
videoUrl string Optional
externalUrl string Optional
isCommunityPublished boolean Optional

Outputs:

Name Type Description
recipeId integer Unique recipe identifier
ownerId integer ID of the recipe's owner
title string Recipe title
description string null
cuisineType string Cuisine category, validated against Flavour Profile Options
prepTimeMins integer Preparation time in minutes
cookingTimeMins integer Cooking time in minutes
servingSize integer Number of servings
photoUrl string null
videoUrl string null
externalUrl string null
isCommunityPublished boolean Whether the recipe is visible to the community
createdAt OffsetDateTime Timestamp of recipe creation
updatedAt OffsetDateTime Timestamp of last update
parentRecipeId integer ID of the source recipe this was copied from, if any

Usage / Interaction Rules:

  • Send a POST request to /recipes/create
  • owner is inferred from the JWT/session and is not accepted in the request body
  • Returns 400 Bad Request if cuisineType is invalid
  • Returns 200 OK with the created recipe

Create Full Recipe (with ingredients and steps)

Description: Creates a complete recipe including ingredients and steps in one request. Can optionally be linked to a source recipe (e.g. when copying/forking an existing recipe).

Endpoint: POST /recipes/{sourceId}/copy

Inputs:

Name Type Description
sourceId integer Path variable for the source recipe being copied from, if any
ownerId string Extracted automatically from the JWT token via @AuthenticationPrincipal
title string Required, not blank
description string Optional
cuisineType string Required, not blank
prepTimeMins integer Required
cookingTimeMins integer Required
servingSize integer Required
photoUrl string Optional
videoUrl string Optional
externalUrl string Optional
isCommunityPublished boolean Optional
ingredients List<object> Required, non-empty. Each item: ingId (integer, required), quantity (decimal, required), unit (string, required, not blank), sortOrder (integer, required)
steps List<object> Required, non-empty. Each item: stepNr (integer, required, min 1), content (string, required, not blank)

Outputs:

Name Type Description
recipeId integer Unique recipe identifier
ownerId integer ID of the recipe's owner
title string Recipe title
description string null
cuisineType string Cuisine category, validated against Flavour Profile Options
prepTimeMins integer Preparation time in minutes
cookingTimeMins integer Cooking time in minutes
servingSize integer Number of servings
photoUrl string null
videoUrl string null
externalUrl string null
isCommunityPublished boolean Whether the recipe is visible to the community
createdAt OffsetDateTime Timestamp of recipe creation
updatedAt OffsetDateTime Timestamp of last update
parentRecipeId integer ID of the source recipe this was copied from, if any

Usage / Interaction Rules:

  • Send a POST request to /recipes/{sourceId}/copy
  • ingredients and steps must each contain at least one entry
  • Returns 400 Bad Request if cuisineType is invalid
  • Returns 400 Bad Request if one of the supplied ingredients doesn't exist in the catalogue
  • Returns 200 OK with the created recipe

Update Recipe

Description: Updates a recipe's top-level fields. Does not modify ingredients or steps.

Endpoint: PUT /recipes/edit/{id}

Inputs:

Name Type Description
id integer Path variable for the recipe to update
ownerId string Extracted automatically from the JWT token via @AuthenticationPrincipal
title string Recipe title, required, not blank
description string Optional recipe description
cuisineType string Required, not blank; must match an existing Flavour Profile Options value
prepTimeMins integer Required
cookingTimeMins integer Required
servingSize integer Required
photoUrl string Optional
videoUrl string Optional
externalUrl string Optional
isCommunityPublished boolean Optional

Outputs:

Name Type Description
recipeId integer Unique recipe identifier
ownerId integer ID of the recipe's owner
title string Recipe title
description string null
cuisineType string Cuisine category, validated against Flavour Profile Options
prepTimeMins integer Preparation time in minutes
cookingTimeMins integer Cooking time in minutes
servingSize integer Number of servings
photoUrl string null
videoUrl string null
externalUrl string null
isCommunityPublished boolean Whether the recipe is visible to the community
createdAt OffsetDateTime Timestamp of recipe creation
updatedAt OffsetDateTime Timestamp of last update
parentRecipeId integer ID of the source recipe this was copied from, if any

Usage / Interaction Rules:

  • Send a PUT request to /recipes/edit/{id}
  • User can only update recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 400 Bad Request if cuisineType is invalid
  • Returns 200 OK with the updated recipe

Delete Recipe

Description: Deletes a recipe owned by the logged-in user.

Endpoint: DELETE /recipes/delete/{id}

Inputs:

Name Type Description
id integer Path variable for the recipe to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /recipes/delete/{id}
  • User can only delete recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 204 No Content

7. Recipe Ingredient Services:

Add Recipe Ingredient

Description: Adds an ingredient line to a recipe.

Endpoint: POST /ingredients/recipe/{recipeId}/ingredient/create

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
ownerId string Extracted automatically from the JWT token via @AuthenticationPrincipal
ingId integer Required; must exist in the ingredient catalogue
quantity decimal Required
unit string Required, not blank
sortOrder integer Required

Outputs:

Name Type Description
ingredientId integer Unique recipe-ingredient line identifier
recipeId integer ID of the parent recipe
ingId integer Linked ingredient catalogue ID
quantity decimal Quantity amount
unit string Unit of measurement
sortOrder integer Display order within the recipe

Usage / Interaction Rules:

  • Send a POST request to /ingredients/recipe/{recipeId}/ingredient/create
  • User can only modify ingredients on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 400 Bad Request if the supplied ingId doesn't exist in the catalogue
  • Returns 200 OK with the created ingredient line

Update Recipe Ingredient

Description: Updates an existing ingredient line on a recipe.

Endpoint: PUT /ingredients/recipe/{recipeId}/ingredient/{id}/edit

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
id integer Path variable for the ingredient line to update
ingId integer Required; must exist in the ingredient catalogue
quantity decimal Required
unit string Required, not blank
sortOrder integer Required

Outputs:

Name Type Description
ingredientId integer Unique recipe-ingredient line identifier
recipeId integer ID of the parent recipe
ingId integer Linked ingredient catalogue ID
quantity decimal Quantity amount
unit string Unit of measurement
sortOrder integer Display order within the recipe

Usage / Interaction Rules:

  • Send a PUT request to /ingredients/recipe/{recipeId}/ingredient/{id}/edit
  • User can only modify ingredients on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 403 Forbidden if the ingredient line doesn't belong to the specified recipe
  • Returns 400 Bad Request if the new ingId doesn't exist in the catalogue
  • Returns 200 OK with the updated ingredient line

Delete Recipe Ingredient

Description: Removes an ingredient line from a recipe.

Endpoint: DELETE /ingredients/recipe/{recipeId}/ingredient/{id}/delete

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
id integer Path variable for the ingredient line to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /ingredients/recipe/{recipeId}/ingredient/{id}/delete
  • User can only modify ingredients on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 403 Forbidden if the ingredient line doesn't belong to the specified recipe
  • Returns 204 No Content

8. Recipe Step Services:

Add Recipe Step

Description: Adds a step to a recipe.

Endpoint: POST /steps/recipe/{recipeId}/step/create

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
stepNr integer Required, min 1
content string Required, not blank

Outputs:

Name Type Description
stepId integer Unique step identifier
recipeId integer ID of the parent recipe
stepNr integer Step number/order
content string Instruction text

Usage / Interaction Rules:

  • Send a POST request to /steps/recipe/{recipeId}/step/create
  • User can only modify steps on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 200 OK with the created step

Update Recipe Step

Description: Updates an existing step.

Endpoint: PUT /steps/recipe/{recipeId}/step/{id}/edit

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
id integer Path variable for the step to update
stepNr integer Required, min 1
content string Required, not blank

Outputs: Same shape as Add Recipe Step

Usage / Interaction Rules:

  • Send a PUT request to /steps/recipe/{recipeId}/step/{id}/edit
  • User can only modify steps on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 403 Forbidden if the step doesn't belong to the specified recipe
  • Returns 200 OK with the updated step

Delete Recipe Step

Description: Removes a step from a recipe.

Endpoint: DELETE /steps/recipe/{recipeId}/step/{id}/delete

Inputs:

Name Type Description
recipeId integer Path variable for the parent recipe
id integer Path variable for the step to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /steps/recipe/{recipeId}/step/{id}/delete
  • User can only modify steps on recipes they own
  • Returns 403 Forbidden if the caller doesn't own the recipe
  • Returns 403 Forbidden if the step doesn't belong to the specified recipe
  • Returns 204 No Content

9. Pantry Services:

Get Pantry Items

Description: Retrieves all pantry items belonging to the logged-in user.

Endpoint: GET /api/pantry

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal

Outputs:

Name Type Description
p_ingredient_id integer Unique pantry ingredient identifier
ing_id integer Linked ingredient catalogue ID
name string Ingredient name
category string Ingredient category (e.g. pasta, rice, spice, dairy, vegetable)
quantity decimal Current quantity available in the pantry
unit string Unit of measurement (e.g. g, kg, ml, cup, item)
created_at OffsetDateTime Timestamp when the pantry item was created
updated_at OffsetDateTime Timestamp when the pantry item was last updated

Usage / Interaction Rules:

  • Send a GET request to /api/pantry - no request body required
  • Returns 200 OK with a list of pantry items

Add Pantry Item

Description: Adds a new ingredient to the logged-in user's pantry.

Endpoint: POST /api/pantry

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal
ing_id integer Ingredient catalogue ID, required
quantity decimal Quantity to add, should be greater than zero
unit string Unit of measurement

Outputs:

Name Type Description
p_ingredient_id integer Unique pantry ingredient identifier
ing_id integer Linked ingredient catalogue ID
name string Ingredient name
category string Ingredient category
quantity decimal Current quantity available in the pantry
unit string Unit of measurement
created_at OffsetDateTime Timestamp when the pantry item was created
updated_at OffsetDateTime Timestamp when the pantry item was last updated

Usage / Interaction Rules:

  • Send a POST request to /api/pantry
  • name is required and quantity should be greater than zero
  • Returns 200 OK with the created pantry item

Update Pantry Item

Description: Updates an existing pantry item.

Endpoint: PUT /api/pantry/{id}

Inputs:

Name Type Description
id integer Path variable for the pantry item to update
ing_id integer Ingredient catalogue ID
quantity decimal Updated quantity
unit string Updated unit of measurement

Outputs:

Name Type Description
p_ingredient_id integer Unique pantry ingredient identifier
ing_id integer Linked ingredient catalogue ID
name string Ingredient name
category string Ingredient category
quantity decimal Current quantity available in the pantry
unit string Unit of measurement
created_at OffsetDateTime Timestamp when the pantry item was created
updated_at OffsetDateTime Timestamp when the pantry item was last updated

Usage / Interaction Rules:

  • Send a PUT request to /api/pantry/{id}
  • User can only update their own pantry items
  • Quantity changes should be reflected immediately in recipe generation and shopping-list logic
  • Returns 200 OK with the updated pantry item
  • If a quantity is updated to zero, the pantry item is deleted instead of being updated, and returns 204 No Content

Delete Pantry Item

Description: Deletes a pantry item from the logged-in user's pantry.

Endpoint: DELETE /api/pantry/{id}

Inputs:

Name Type Description
id integer Path variable for the pantry item to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /api/pantry/{id}
  • User can only delete their own pantry items
  • Deleted pantry items should no longer appear in pantry lists
  • Returns 204 No Content

Search Pantry Items

Description: Searches the logged-in user's pantry by ingredient name.

Endpoint: GET /api/pantry/search?q={query}

Inputs:

Name Type Description
q string Query parameter for the ingredient name to search

Outputs:

Name Type Description
p_ingredient_id integer Unique pantry ingredient identifier
ing_id integer Linked ingredient catalogue ID
name string Ingredient name
category string Ingredient category
quantity decimal Current quantity available in the pantry
unit string Unit of measurement
created_at OffsetDateTime Timestamp when the pantry item was created
updated_at OffsetDateTime Timestamp when the pantry item was last updated

Usage / Interaction Rules:

  • Send a GET request to /api/pantry/search?q={query} - no request body required
  • Returns 200 OK with a list of matching pantry items scoped to the logged-in user's pantry

10. Shopping List Services:

Get Shopping Lists By User

Description: Retrieves all shopping lists belonging to the logged-in user.

Endpoint: GET /api/shopping-lists

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation

Usage / Interaction Rules:

  • Send a GET request to /api/shopping-lists - no request body required
  • Returns 200 OK with a list of shopping lists

Get Shopping List By ID

Description: Retrieves a single shopping list, including its items.

Endpoint: GET /api/shopping-lists/{id}

Inputs:

Name Type Description
id integer Path variable for the shopping list

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation
items List<ShoppingListItem> Items belonging to the list

Usage / Interaction Rules:

  • Send a GET request to /api/shopping-lists/{id}
  • User can only retrieve their own shopping lists
  • Returns 200 OK with the shopping list object and its items

Create Shopping List

Description: Creates a new shopping list for the logged-in user.

Endpoint: POST /api/shopping-lists

Inputs:

Name Type Description
userId string Extracted automatically from the JWT token via @AuthenticationPrincipal
name string Name of the shopping list, required, max 200 characters
status ShoppingListStatus (enum) Optional, defaults to ACTIVE

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation

Usage / Interaction Rules:

  • Send a POST request to /api/shopping-lists
  • Owner is inferred from the JWT/session and is not accepted in the request body
  • Returns 200 OK with the created shopping list

Update Shopping List

Description: Updates an existing shopping list's information.

Endpoint: PUT /api/shopping-lists/{id}

Inputs:

Name Type Description
id integer Path variable for the shopping list to update
name string Updated name, cannot be blank
status ShoppingListStatus (enum) Updated status, must be a valid enum value

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation

Usage / Interaction Rules:

  • Send a PUT request to /api/shopping-lists/{id}
  • User can only update their own shopping lists
  • Returns 200 OK with the updated shopping list

Delete Shopping List

Description: Permanently deletes a shopping list by its ID.

Endpoint: DELETE /api/shopping-lists/{id}

Inputs:

Name Type Description
id integer Path variable for the shopping list to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /api/shopping-lists/{id}
  • User can only delete their own shopping lists
  • Deleting a shopping list also removes its related shopping list items via ON DELETE CASCADE
  • Returns 204 No Content

Add Shopping List Item

Description: Adds a new item to an existing shopping list.

Endpoint: POST /api/shopping-lists/{id}/items

Inputs:

Name Type Description
id integer Path variable for the parent shopping list
ing_id integer Optional ingredient catalogue ID (either ing_id or name must be provided, not both)
name string Manually entered item name (used only when ing_id is null)
quantity decimal Optional quantity amount
unit string Optional unit of measurement
purchased boolean Optional, defaults to false

Outputs:

Name Type Description
item_id integer Unique shopping list item identifier
shopping_list_id integer ID of the parent shopping list
ing_id integer Linked ingredient catalogue ID, or null
name string Item name
category string Ingredient category, resolved from catalogue but always null for manual items
quantity decimal Quantity amount
unit string Unit of measurement
purchased boolean Purchased state

Usage / Interaction Rules:

  • Send a POST request to /api/shopping-lists/{id}/items with item fields in JSON format
  • User can only add items to their own shopping lists
  • Either ing_id or name must be provided (providing neither or both returns 400 Bad Request)
  • Returns 200 OK with the created item

Update Shopping List Item

Description: Updates an existing item on a shopping list.

Endpoint: PUT /api/shopping-lists/{id}/items/{itemId}

Inputs:

Name Type Description
id integer Path variable for the parent shopping list
itemId integer Path variable for the item to update
ing_id integer Optional ingredient catalogue ID (either ing_id or name must be provided, not both)
name string Manually entered item name; used only when ing_id is null
quantity decimal Updated quantity amount
unit string Updated unit of measurement
purchased boolean Updated purchased state

Outputs:

Name Type Description
item_id integer Unique shopping list item identifier
shopping_list_id integer ID of the parent shopping list
ing_id integer Linked ingredient catalogue ID, or null
name string Item name
category string Ingredient category, resolved from catalogue (always null for manual items)
quantity decimal Quantity amount
unit string Unit of measurement
purchased boolean Purchased state

Usage / Interaction Rules:

  • Send a PUT request to /api/shopping-lists/{id}/items/{itemId} with updated fields in JSON format
  • User can only update items on their own shopping lists
  • Either ing_id or name must be provided (providing neither or both returns 400 Bad Request)
  • The item must belong to the shopping list specified in the URL path, or the request returns 404 Not Found
  • Returns 200 OK with the updated item

Update Shopping List Item Purchased Status

Description: Updates the purchased state for one shopping list item.

Endpoint: PATCH /api/shopping-lists/{id}/items/{itemId}/purchased

Inputs:

Name Type Description
id integer Path variable for the parent shopping list
itemId integer Path variable for the item to update
purchased boolean New purchased state

Outputs:

Name Type Description
item_id integer Unique shopping list item identifier
shopping_list_id integer ID of the parent shopping list
ing_id integer Linked ingredient catalogue ID, or null
name string Item name
category string Ingredient category, resolved from catalogue (always null for manual items)
quantity decimal Quantity amount
unit string Unit of measurement
purchased boolean Updated purchased state

Usage / Interaction Rules:

  • Send a PATCH request to /api/shopping-lists/{id}/items/{itemId}/purchased
  • User can only update purchased state for items on their own shopping lists
  • This endpoint does not update pantry quantities by itself. Use PUT /api/shopping-lists/{id}/complete-shop for that
  • Returns 200 OK with the updated item

Delete Shopping List Item

Description: Deletes one item from a shopping list.

Endpoint: DELETE /api/shopping-lists/{id}/items/{itemId}

Inputs:

Name Type Description
id integer Path variable for the parent shopping list
itemId integer Path variable for the item to delete

Outputs: None

Usage / Interaction Rules:

  • Send a DELETE request to /api/shopping-lists/{id}/items/{itemId}
  • User can only delete items from their own shopping lists
  • Returns 204 No Content

Batch Delete Shopping List Items

Description: Deletes multiple selected items from a shopping list at once.

Endpoint: POST /api/shopping-lists/{id}/items/batch-delete

Inputs:

Name Type Description
id integer Path variable for the parent shopping list
item_ids List<integer> IDs of the items to delete

Outputs: None

Usage / Interaction Rules:

  • Send a POST request to /api/shopping-lists/{id}/items/batch-delete
  • User can only delete items from their own shopping lists
  • All item_ids must belong to the shopping list specified in the URL path, if any item is not found or belongs to a different list, the request fails with 404 Not Found and no items are deleted
  • Returns 204 No Content

Select All Shopping List Items

Description: Marks every item on a shopping list as purchased.

Endpoint: PUT /api/shopping-lists/{id}/items/select-all

Inputs:

Name Type Description
id integer Path variable for the shopping list

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation
items List<ShoppingListItem> Items belonging to the list, all with purchased: true

Usage / Interaction Rules:

  • Send a PUT request to /api/shopping-lists/{id}/items/select-all - no request body required
  • User can only select all items on their own shopping lists
  • Every item on the list is marked purchased: true, regardless of its prior state
  • Returns 200 OK with the full shopping list and updated items

Deselect All Shopping List Items

Description: Marks every item on a shopping list as not purchased.

Endpoint: PUT /api/shopping-lists/{id}/items/deselect-all

Inputs:

Name Type Description
id integer Path variable for the shopping list

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation
items List<ShoppingListItem> Items belonging to the list, all with purchased: false

Usage / Interaction Rules:

  • Send a PUT request to /api/shopping-lists/{id}/items/deselect-all - no request body required
  • User can only deselect all items on their own shopping lists
  • Every item on the list is marked purchased: false, regardless of its prior state
  • Returns 200 OK with the full shopping list and updated items

Complete Shop

Description: Moves all purchased, catalogue-linked items into the user's pantry and removes them from the shopping list.

Endpoint: PUT /api/shopping-lists/{id}/complete-shop

Inputs:

Name Type Description
id integer Path variable for the shopping list

Outputs:

Name Type Description
added_to_pantry_count integer Number of catalogue-linked items moved into the pantry
skipped_manual_items List<string> Names of manually entered purchased items removed from the list but not added to the pantry
shopping_list_deleted boolean Whether the shopping list was deleted because it became empty

Usage / Interaction Rules:

  • Send a PUT request to /api/shopping-lists/{id}/complete-shop - no request body required
  • User can only complete-shop their own shopping lists
  • Only items marked purchased: true are processed; unpurchased items are left untouched on the list
  • Catalogue-linked purchased items are inserted into the pantry as new rows and removed from the list. Existing pantry rows for the same ingredient are never merged
  • Manually entered purchased items are removed from the list but not added to the pantry
  • If every item on the list is removed as a result, the shopping list itself is deleted
  • Returns 200 OK with the completion summary

Create Shopping List From Recipe

Description: Creates a shopping list from the ingredients for a recipe. This endpoint is planned and not yet implemented.

Endpoint: POST /api/shopping-lists/from-recipe/{recipeId}

Inputs:

Name Type Description
recipeId integer Path variable identifying the recipe
name string Name for the new shopping list
include_available_pantry_items boolean Optional, defaults to false

Outputs:

Name Type Description
shopping_list_id integer Unique shopping list identifier
user_id integer ID of the list's owner
name string Name of the shopping list
status ShoppingListStatus (enum) ACTIVE or COMPLETED
created_at OffsetDateTime Timestamp of list creation
items List<ShoppingListItem> Generated items for the recipe

Usage / Interaction Rules:

  • Send a POST request to /api/shopping-lists/from-recipe/{recipeId} with name and optional include_available_pantry_items in JSON format
  • Recipe must be visible to the logged-in user
  • include_available_pantry_items: false (default) compares recipe ingredients against the user's pantry and only adds missing ones
  • include_available_pantry_items: true adds every recipe ingredient regardless of pantry contents
  • Generated shopping_list_items use ing_id where a catalogue ingredient match exists, name otherwise
  • Returns 200 OK with the created shopping list and its items
⚠️ **GitHub.com Fallback** ⚠️