Cookest
Backend API

Database Schema

Entity-relationship diagram and table descriptions for the Cookest database

Database Schema

The Cookest API uses PostgreSQL 15+ accessed via SeaORM 1.1. Migrations run automatically at server startup β€” all operations use IF NOT EXISTS making them safe to replay.

ER Diagram


Identity & preferences

users

Account credentials, profile, onboarding data, and subscription status.

ColumnTypeNotes
idUUID PKAuto-generated v4
emailVARCHAR(255) UNIQUELogin identifier
nameVARCHAR(255)Display name
password_hashTEXTbcrypt hash
refresh_token_hashTEXTSHA-256 of raw refresh token
household_sizeINTEGERDefault 1 β€” scales recipe servings
dietary_restrictionsTEXT[]e.g. {vegetarian, gluten_free}
allergiesTEXT[]e.g. {shellfish, eggs}
avatar_urlTEXTProfile picture URL
subscription_tierTEXTfree / pro / family
subscription_valid_untilTIMESTAMPTZNull for free tier
stripe_customer_idTEXTStripe customer reference
cooking_skill_levelTEXTbeginner / intermediate / advanced
preferred_cuisinesTEXT[]Onboarding selections
health_goalsTEXT[]e.g. {weight_loss, muscle_gain}
weekly_budgetNUMERIC(10,2)Optional budget cap
preferred_time_per_meal_minINTEGERMax cook time preference
onboarding_completedBOOLEANDefault false
is_adminBOOLEANChecked via DB, never JWT
is_email_verifiedBOOLEANEmail verification status
two_factor_enabledBOOLEANTOTP 2FA toggle
totp_secretTEXTEncrypted TOTP seed
failed_login_attemptsINTEGERReset on successful login
locked_untilTIMESTAMPTZAccount lockout expiry
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

user_preferences

Per-user AI preference vectors updated incrementally via online gradient descent (learning rate 0.01).

ColumnTypeNotes
user_idUUID PK, FK β†’ usersOne-to-one with users
cuisine_weightsJSONBe.g. {"italian": 0.8, "japanese": 0.3}
ingredient_weightsJSONBPer-ingredient affinity scores
macro_biasJSONB{"protein": 0.0, "carbs": 0.0, "fat": 0.0}
difficulty_weightsJSONB{"easy": 0.0, "medium": 0.0, "hard": 0.0}
preferred_time_minINTEGERDefault 30
interaction_countINTEGERTotal ratings + cooks
updated_atTIMESTAMPTZ

Ingredients & nutrition

ingredients

Master ingredient catalog seeded by the ETL pipeline from FoodData Central and Open Food Facts.

ColumnTypeNotes
idBIGSERIAL PK
nameTEXT UNIQUECanonical name
categoryTEXTe.g. dairy, vegetable
fdc_idINTEGERFoodData Central ID (indexed)
off_idTEXTOpen Food Facts ID
created_atTIMESTAMPTZ

ingredient_nutrients

Detailed macro and micronutrient values per 100 g of ingredient. One-to-one with ingredients.

ColumnTypeNotes
idBIGSERIAL PK
ingredient_idBIGINT FK β†’ ingredientsUNIQUE β€” one row per ingredient
caloriesNUMERIC(10,4)kcal per 100 g
protein_gNUMERIC(10,4)
carbs_gNUMERIC(10,4)
fat_gNUMERIC(10,4)
fiber_gNUMERIC(10,4)
sugar_gNUMERIC(10,4)
sodium_mgNUMERIC(10,4)
saturated_fat_gNUMERIC(10,4)
cholesterol_mgNUMERIC(10,4)
micronutrientsJSONBGIN-indexed for flexible queries

portion_sizes

Common serving sizes per ingredient (e.g. "1 medium egg = 50 g").

ColumnTypeNotes
idBIGSERIAL PK
ingredient_idBIGINT FK β†’ ingredients
descriptionTEXTe.g. "1 medium"
weight_gramsNUMERIC(10,3)
unitTEXTe.g. "cup", "tbsp"

Recipes

recipes

Recipe metadata. Supports dietary filters, full-text search (trigram GIN index on name), and per-user authorship.

ColumnTypeNotes
idBIGSERIAL PK
nameTEXTTrigram GIN-indexed
slugTEXT UNIQUEURL-safe identifier
descriptionTEXT
cuisineTEXTIndexed
categoryTEXTIndexed
difficultyTEXTIndexed β€” easy / medium / hard
servingsINTEGERDefault 2
prep_time_minINTEGER
cook_time_minINTEGER
total_time_minINTEGER
is_vegetarianBOOLEANComposite dietary index
is_veganBOOLEAN
is_gluten_freeBOOLEAN
is_dairy_freeBOOLEAN
is_nut_freeBOOLEAN
source_urlTEXTOriginal recipe URL
average_ratingNUMERIC(3,2)Denormalized average
rating_countINTEGER
author_idUUID FK β†’ usersNullable β€” user-submitted recipes
is_publicBOOLEANDefault true
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

recipe_ingredients

Junction table bridging recipes ↔ ingredients with quantity and unit.

ColumnTypeNotes
idBIGSERIAL PK
recipe_idBIGINT FK β†’ recipesON DELETE CASCADE
ingredient_idBIGINT FK β†’ ingredientsON DELETE RESTRICT
quantityNUMERIC(10,3)e.g. 200
unitTEXTe.g. g, ml, tbsp
quantity_gramsNUMERIC(10,3)Normalized weight for nutrition calc
notesTEXTe.g. "finely chopped"
display_orderINTEGERPresentation sequence

recipe_steps

Ordered cooking instructions for a recipe.

ColumnTypeNotes
idBIGSERIAL PK
recipe_idBIGINT FK β†’ recipes
step_numberINTEGERUNIQUE per recipe
instructionTEXTStep text
duration_minINTEGEROptional time estimate
image_urlTEXTOptional step photo
tipTEXTOptional cooking tip

recipe_images

Image URLs associated with recipes.

ColumnTypeNotes
idBIGSERIAL PK
recipe_idBIGINT FK β†’ recipes
urlTEXTImage URL
image_typeTEXTe.g. hero, step
is_primaryBOOLEANDefault false
widthINTEGER
heightINTEGER
sourceTEXTAttribution
created_atTIMESTAMPTZ

recipe_nutrition

Pre-calculated macro totals for a recipe. One-to-one with recipes.

ColumnTypeNotes
idBIGSERIAL PK
recipe_idBIGINT FK β†’ recipesUNIQUE
per_servingBOOLEANDefault true β€” values are per-serving
caloriesNUMERIC(10,4)
protein_gNUMERIC(10,4)
carbs_gNUMERIC(10,4)
fat_gNUMERIC(10,4)
fiber_gNUMERIC(10,4)
sugar_gNUMERIC(10,4)
sodium_mgNUMERIC(10,4)
saturated_fat_gNUMERIC(10,4)
cholesterol_mgNUMERIC(10,4)
micronutrientsJSONB
calculated_atTIMESTAMPTZ

User interactions

user_favorites

Recipe saves/bookmarks per user.

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ usersUNIQUE(user_id, recipe_id)
recipe_idBIGINT FK β†’ recipes
saved_atTIMESTAMPTZ

recipe_ratings

1–5 star ratings with optional text comment.

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ usersUNIQUE(user_id, recipe_id)
recipe_idBIGINT FK β†’ recipes
ratingSMALLINTCHECK 1–5
commentTEXT
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

cooking_history

Timestamped record of every time a user cooks a recipe. Triggers automatic inventory deduction.

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ users
recipe_idBIGINT FK β†’ recipes
servings_madeINTEGERDefault 1
inventory_deductedBOOLEANDefault false β€” set true after deduction
cooked_atTIMESTAMPTZ

Planning & inventory

inventory_items

Pantry items with quantity, unit, expiry date, and storage location.

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ users
ingredient_idBIGINT FK β†’ ingredientsON DELETE RESTRICT
custom_nameTEXTOptional override display name
quantityNUMERIC(10,3)
unitTEXTe.g. g, ml, units
expiry_dateDATEIndexed for expiry alerts
storage_locationTEXTfridge / freezer / pantry / other
added_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

meal_plans

Weekly plan container. One plan per user per week.

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ usersUNIQUE(user_id, week_start)
week_startDATEMonday of the plan week
is_ai_generatedBOOLEANDefault false
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

meal_plan_slots

Individual meal assignments: day 0–6 Γ— meal type. Supports flex/relief days.

ColumnTypeNotes
idBIGSERIAL PK
meal_plan_idBIGINT FK β†’ meal_plans
recipe_idBIGINT FK β†’ recipesNullable β€” null for flex days
day_of_weekSMALLINTCHECK 0–6 (Mon–Sun)
meal_typeTEXTbreakfast / lunch / dinner / snack
servings_overrideINTEGEROverrides recipe default
is_completedBOOLEANDefault false
is_flexBOOLEANDefault false β€” relief day flag
flex_typeTEXTeffort / nutrition / mental / social
energy_levelTEXTOptional energy tracking

UNIQUE constraint on (meal_plan_id, day_of_week, meal_type) ensures at most one recipe per slot.

shopping_list_items

User shopping list items, optionally linked to a meal plan for auto-sync.

ColumnTypeNotes
idUUID PK
user_idUUID FK β†’ users
ingredient_idBIGINT FK β†’ ingredientsNullable β€” for manual items
nameTEXTDisplay name
quantityNUMERIC(10,3)
unitTEXT
is_checkedBOOLEANDefault false
is_manualBOOLEANtrue if added manually vs. synced
meal_plan_idBIGINT FK β†’ meal_plansNullable β€” links to source plan
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

AI chat

chat_sessions

One session per conversation thread, optionally scoped to a recipe (Cooking Mode chat).

ColumnTypeNotes
idBIGSERIAL PK
user_idUUID FK β†’ users
current_recipe_idBIGINT FK β†’ recipesNullable β€” provides recipe context
titleTEXTAuto-generated or user-set
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

chat_messages

Individual messages within a chat session.

ColumnTypeNotes
idBIGSERIAL PK
session_idBIGINT FK β†’ chat_sessionsIndexed with created_at ASC
roleTEXTCHECK user / assistant / system
contentTEXTMessage body
tokens_usedINTEGERLLM token count for rate limiting
created_atTIMESTAMPTZ

Stores & promotions

stores

Retail stores whose promotional flyers are processed by the PDF pipeline.

ColumnTypeNotes
idUUID PK
nameTEXTStore name
slugTEXT UNIQUEURL-safe identifier
websiteTEXT
logo_urlTEXT
countryTEXT
cityTEXT
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

pdf_processing_jobs

Tracks the status of PDF flyer processing jobs.

ColumnTypeNotes
idUUID PK
store_idUUID FK β†’ stores
file_pathTEXTPath to uploaded PDF
statusTEXTpending / processing / completed / failed
errorTEXTError message on failure
retry_countINTEGERDefault 0
started_atTIMESTAMPTZ
heartbeat_atTIMESTAMPTZLiveness check for long jobs
processed_atTIMESTAMPTZ
created_atTIMESTAMPTZ

store_promotions

Live promotional prices extracted from processed PDFs and approved by admin.

ColumnTypeNotes
idUUID PK
store_idUUID FK β†’ stores
product_nameTEXTRaw product name from PDF
brandTEXT
original_priceNUMERIC(10,2)
discounted_priceNUMERIC(10,2)
discount_pctNUMERIC(5,2)
unitTEXTe.g. kg, unit
valid_fromTIMESTAMPTZPromotion window
valid_untilTIMESTAMPTZ
is_activeBOOLEANDefault true
source_pdf_urlTEXT
confidenceNUMERIC(4,3)LLM extraction confidence 0–1
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

store_promotion_ingredients

Links promotions to ingredients in the catalog using similarity matching.

ColumnTypeNotes
promotion_idUUID FK β†’ store_promotionsComposite PK
ingredient_idBIGINT FK β†’ ingredientsComposite PK
similarity_scoreNUMERIC(4,3)Match confidence 0–1

store_promotion_candidates

Staging table for promotions extracted from PDFs, pending admin review.

ColumnTypeNotes
idUUID PK
store_idUUID FK β†’ stores
job_idUUID FK β†’ pdf_processing_jobsSource processing job
product_nameTEXT
brandTEXT
original_priceNUMERIC(10,2)
discounted_priceNUMERIC(10,2)
discount_pctNUMERIC(5,2)
unitTEXT
valid_fromTIMESTAMPTZ
valid_untilTIMESTAMPTZ
confidenceNUMERIC(4,3)
review_statusTEXTpending / approved / rejected
reviewed_byUUID FK β†’ usersAdmin who reviewed
reviewed_atTIMESTAMPTZ
created_atTIMESTAMPTZ

Push notifications & payments

user_push_tokens

Device push tokens for notifications.

ColumnTypeNotes
idUUID PK
user_idUUID FK β†’ users
tokenTEXT UNIQUEDevice token
platformTEXTios / android / web
created_atTIMESTAMPTZ

stripe_processed_events

Idempotency table for Stripe webhook processing β€” prevents duplicate event handling.

ColumnTypeNotes
event_idTEXT PKStripe event ID
processed_atTIMESTAMPTZ

Key relationships

  • recipe_ingredients bridges recipes and ingredients, storing quantity and unit (e.g. 200 g). The quantity_grams column holds the normalized weight used for nutrition calculation.
  • meal_plan_slots ties weekly plans to specific recipes and tracks is_flex, flex_type, is_completed, and servings_override.
  • cooking_history triggers automatic inventory deduction scaled by household_size when inventory_deducted transitions from false to true.
  • user_preferences stores floating-point weight vectors that the online learning algorithm updates incrementally with each user rating or cook event.
  • store_promotion_candidates β†’ store_promotions β€” promotions flow through admin review before becoming live.
  • stripe_processed_events ensures webhook idempotency β€” each Stripe event is processed exactly once.

Source of truth

The migration SQL in api/src/main.rs is the canonical schema. This document reflects that schema β€” consult the source file for exact column types and constraints.

On this page