diff --git a/app/db/migrations/005_receipt_staged_status.sql b/app/db/migrations/005_receipt_staged_status.sql index d323526..286fd41 100644 --- a/app/db/migrations/005_receipt_staged_status.sql +++ b/app/db/migrations/005_receipt_staged_status.sql @@ -9,6 +9,7 @@ CREATE TABLE receipts_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, filename TEXT NOT NULL, original_path TEXT NOT NULL, + processed_path TEXT, status TEXT NOT NULL DEFAULT 'uploaded' CHECK (status IN ( 'uploaded', diff --git a/app/db/migrations/006_element_profiles.sql b/app/db/migrations/006_element_profiles.sql new file mode 100644 index 0000000..09c9367 --- /dev/null +++ b/app/db/migrations/006_element_profiles.sql @@ -0,0 +1,48 @@ +-- Migration 006: Ingredient element profiles + FlavorGraph molecule index. + +CREATE TABLE ingredient_profiles ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + name_variants TEXT NOT NULL DEFAULT '[]', -- JSON array of aliases/alternate spellings + elements TEXT NOT NULL DEFAULT '[]', -- JSON array: ["Richness","Depth"] + -- Functional submetadata (from USDA FDC) + fat_pct REAL DEFAULT 0.0, + fat_saturated_pct REAL DEFAULT 0.0, + moisture_pct REAL DEFAULT 0.0, + protein_pct REAL DEFAULT 0.0, + starch_pct REAL DEFAULT 0.0, + binding_score INTEGER DEFAULT 0 CHECK (binding_score BETWEEN 0 AND 3), + glutamate_mg REAL DEFAULT 0.0, + ph_estimate REAL, + sodium_mg_per_100g REAL DEFAULT 0.0, + smoke_point_c REAL, + is_fermented INTEGER NOT NULL DEFAULT 0, + is_emulsifier INTEGER NOT NULL DEFAULT 0, + -- Aroma submetadata + flavor_molecule_ids TEXT NOT NULL DEFAULT '[]', -- JSON array of FlavorGraph compound IDs + heat_stable INTEGER NOT NULL DEFAULT 1, + add_timing TEXT NOT NULL DEFAULT 'any' + CHECK (add_timing IN ('early','finish','any')), + -- Brightness submetadata + acid_type TEXT CHECK (acid_type IN ('citric','acetic','lactic',NULL)), + -- Texture submetadata + texture_profile TEXT NOT NULL DEFAULT 'neutral', + water_activity REAL, + -- Source + usda_fdc_id TEXT, + source TEXT NOT NULL DEFAULT 'usda', + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE UNIQUE INDEX idx_ingredient_profiles_name ON ingredient_profiles (name); +CREATE INDEX idx_ingredient_profiles_elements ON ingredient_profiles (elements); + +CREATE TABLE flavor_molecules ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + compound_id TEXT NOT NULL UNIQUE, -- FlavorGraph node ID + compound_name TEXT NOT NULL, + ingredient_names TEXT NOT NULL DEFAULT '[]', -- JSON array of ingredient names + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_flavor_molecules_compound_id ON flavor_molecules (compound_id); diff --git a/app/db/migrations/007_recipe_corpus.sql b/app/db/migrations/007_recipe_corpus.sql new file mode 100644 index 0000000..19a79f4 --- /dev/null +++ b/app/db/migrations/007_recipe_corpus.sql @@ -0,0 +1,24 @@ +-- Migration 007: Recipe corpus index (food.com dataset). + +CREATE TABLE recipes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + external_id TEXT, + title TEXT NOT NULL, + ingredients TEXT NOT NULL DEFAULT '[]', -- JSON array of raw ingredient strings + ingredient_names TEXT NOT NULL DEFAULT '[]', -- JSON array of normalized names + directions TEXT NOT NULL DEFAULT '[]', -- JSON array of step strings + category TEXT, + keywords TEXT NOT NULL DEFAULT '[]', -- JSON array + calories REAL, + fat_g REAL, + protein_g REAL, + sodium_mg REAL, + -- Element coverage scores computed at import time + element_coverage TEXT NOT NULL DEFAULT '{}', -- JSON {element: 0.0-1.0} + source TEXT NOT NULL DEFAULT 'foodcom', + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_recipes_title ON recipes (title); +CREATE INDEX idx_recipes_category ON recipes (category); +CREATE INDEX idx_recipes_external_id ON recipes (external_id); diff --git a/app/db/migrations/008_substitution_pairs.sql b/app/db/migrations/008_substitution_pairs.sql new file mode 100644 index 0000000..fe1c12a --- /dev/null +++ b/app/db/migrations/008_substitution_pairs.sql @@ -0,0 +1,22 @@ +-- Migration 008: Derived substitution pairs. +-- Source: diff of lishuyang/recipepairs (GPL-3.0 derivation — raw data not shipped). + +CREATE TABLE substitution_pairs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + original_name TEXT NOT NULL, + substitute_name TEXT NOT NULL, + constraint_label TEXT NOT NULL, -- 'vegan'|'vegetarian'|'dairy_free'|'gluten_free'|'low_fat'|'low_sodium' + fat_delta REAL DEFAULT 0.0, + moisture_delta REAL DEFAULT 0.0, + glutamate_delta REAL DEFAULT 0.0, + protein_delta REAL DEFAULT 0.0, + occurrence_count INTEGER DEFAULT 1, + compensation_hints TEXT NOT NULL DEFAULT '[]', -- JSON [{ingredient, reason, element}] + source TEXT NOT NULL DEFAULT 'derived', + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_substitution_pairs_original ON substitution_pairs (original_name); +CREATE INDEX idx_substitution_pairs_constraint ON substitution_pairs (constraint_label); +CREATE UNIQUE INDEX idx_substitution_pairs_pair + ON substitution_pairs (original_name, substitute_name, constraint_label); diff --git a/app/db/migrations/009_staple_library.sql b/app/db/migrations/009_staple_library.sql new file mode 100644 index 0000000..ec9d7d7 --- /dev/null +++ b/app/db/migrations/009_staple_library.sql @@ -0,0 +1,27 @@ +-- Migration 009: Staple library (bulk-preparable base components). + +CREATE TABLE staples ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + slug TEXT NOT NULL UNIQUE, + name TEXT NOT NULL, + description TEXT, + base_ingredients TEXT NOT NULL DEFAULT '[]', -- JSON array of ingredient strings + base_method TEXT, + base_time_minutes INTEGER, + yield_formats TEXT NOT NULL DEFAULT '{}', -- JSON {format_name: {elements, shelf_days, methods, texture}} + dietary_labels TEXT NOT NULL DEFAULT '[]', -- JSON ['vegan','high-protein'] + compatible_styles TEXT NOT NULL DEFAULT '[]', -- JSON [style_id] + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE user_staples ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + staple_slug TEXT NOT NULL REFERENCES staples(slug) ON DELETE CASCADE, + active_format TEXT NOT NULL, + quantity_g REAL, + prepared_at TEXT, + notes TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_user_staples_slug ON user_staples (staple_slug); diff --git a/app/db/migrations/010_recipe_feedback.sql b/app/db/migrations/010_recipe_feedback.sql new file mode 100644 index 0000000..c4f358e --- /dev/null +++ b/app/db/migrations/010_recipe_feedback.sql @@ -0,0 +1,15 @@ +-- Migration 010: User substitution approval log (opt-in dataset moat). + +CREATE TABLE substitution_feedback ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + original_name TEXT NOT NULL, + substitute_name TEXT NOT NULL, + constraint_label TEXT, + compensation_used TEXT NOT NULL DEFAULT '[]', -- JSON array of compensation ingredient names + approved INTEGER NOT NULL DEFAULT 0, + opted_in INTEGER NOT NULL DEFAULT 0, -- user consented to anonymized sharing + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_substitution_feedback_original ON substitution_feedback (original_name); +CREATE INDEX idx_substitution_feedback_opted_in ON substitution_feedback (opted_in); diff --git a/app/db/migrations/011_rate_limits.sql b/app/db/migrations/011_rate_limits.sql new file mode 100644 index 0000000..421002a --- /dev/null +++ b/app/db/migrations/011_rate_limits.sql @@ -0,0 +1,11 @@ +-- Migration 011: Daily rate limits (leftover mode: 5/day free tier). + +CREATE TABLE rate_limits ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + feature TEXT NOT NULL, + window_date TEXT NOT NULL, -- YYYY-MM-DD + count INTEGER NOT NULL DEFAULT 0, + UNIQUE (feature, window_date) +); + +CREATE INDEX idx_rate_limits_feature_date ON rate_limits (feature, window_date);