CREATE TABLE IF NOT EXISTS stores ( id SERIAL PRIMARY KEY, name TEXT NOT NULL UNIQUE, enabled BOOLEAN NOT NULL DEFAULT TRUE ); ALTER TABLE stores ADD COLUMN IF NOT EXISTS address TEXT; ALTER TABLE stores ADD COLUMN IF NOT EXISTS postal_code TEXT; ALTER TABLE stores ADD COLUMN IF NOT EXISTS store_code TEXT; ALTER TABLE stores ADD COLUMN IF NOT EXISTS flyer_page_url TEXT; CREATE TABLE IF NOT EXISTS household_settings ( id INTEGER PRIMARY KEY CHECK (id=1), household_size INTEGER NOT NULL DEFAULT 4, weekly_budget NUMERIC(10,2) NOT NULL DEFAULT 150.00, dinners_per_week INTEGER NOT NULL DEFAULT 7, currency TEXT NOT NULL DEFAULT 'CAD' ); INSERT INTO household_settings (id,household_size,weekly_budget,dinners_per_week,currency) VALUES (1,4,150.00,7,'CAD') ON CONFLICT (id) DO NOTHING; INSERT INTO stores (name) VALUES ('IGA'),('Metro'),('Costco'),('Maxi'),('Super C'),('Walmart') ON CONFLICT (name) DO NOTHING; CREATE TABLE IF NOT EXISTS products ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, brand TEXT, unit TEXT ); CREATE TABLE IF NOT EXISTS flyer_offers ( id SERIAL PRIMARY KEY, store_id INTEGER REFERENCES stores(id) ON DELETE CASCADE, product_id INTEGER REFERENCES products(id) ON DELETE SET NULL, price NUMERIC(10,2), regular_price NUMERIC(10,2), valid_from DATE, valid_to DATE, source_url TEXT ); CREATE TABLE IF NOT EXISTS recipes ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, description TEXT, servings INTEGER NOT NULL DEFAULT 4, instructions TEXT, estimated_cost NUMERIC(10,2) ); CREATE TABLE IF NOT EXISTS recipe_ingredients ( id SERIAL PRIMARY KEY, recipe_id INTEGER NOT NULL REFERENCES recipes(id) ON DELETE CASCADE, product_id INTEGER REFERENCES products(id) ON DELETE SET NULL, ingredient_name TEXT NOT NULL, quantity NUMERIC(10,2), unit TEXT ); CREATE TABLE IF NOT EXISTS meal_plans ( id SERIAL PRIMARY KEY, week_start DATE NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS planned_meals ( id SERIAL PRIMARY KEY, meal_plan_id INTEGER NOT NULL REFERENCES meal_plans(id) ON DELETE CASCADE, meal_date DATE NOT NULL, recipe_id INTEGER REFERENCES recipes(id) ON DELETE SET NULL, custom_name TEXT ); CREATE TABLE IF NOT EXISTS flyer_sources ( id SERIAL PRIMARY KEY, store_id INTEGER NOT NULL REFERENCES stores(id) ON DELETE CASCADE, source_url TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT TRUE, last_checked_at TIMESTAMPTZ, last_success_at TIMESTAMPTZ, last_error TEXT, UNIQUE(store_id,source_url) ); CREATE TABLE IF NOT EXISTS flyers ( id SERIAL PRIMARY KEY, store_id INTEGER NOT NULL REFERENCES stores(id) ON DELETE CASCADE, source_id INTEGER REFERENCES flyer_sources(id) ON DELETE SET NULL, title TEXT NOT NULL, source_url TEXT NOT NULL, local_path TEXT NOT NULL, checksum TEXT NOT NULL UNIQUE, file_size BIGINT NOT NULL DEFAULT 0, page_count INTEGER NOT NULL DEFAULT 0, extracted_text TEXT NOT NULL DEFAULT '', extraction_status TEXT NOT NULL DEFAULT 'pending', valid_from DATE, valid_to DATE, downloaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS flyer_import_runs ( id SERIAL PRIMARY KEY, store_id INTEGER REFERENCES stores(id) ON DELETE SET NULL, source_url TEXT NOT NULL, started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), finished_at TIMESTAMPTZ, status TEXT NOT NULL DEFAULT 'running', message TEXT );