feat: KitchenStock light UI, Gemma 31B AI, supermarket store filters & 130+ vegan products
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
-- Migration 00001: Initial Schema for KitchenStock
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Enums
|
||||
CREATE TYPE household_role AS ENUM ('OWNER', 'ADMIN', 'MEMBER', 'VIEWER');
|
||||
CREATE TYPE aldi_region_type AS ENUM ('NORD', 'SUED', 'UNSPECIFIED');
|
||||
CREATE TYPE unit_type AS ENUM ('COUNT', 'WEIGHT', 'VOLUME', 'OTHER');
|
||||
CREATE TYPE stock_movement_reason AS ENUM ('PURCHASE', 'CONSUMED', 'CORRECTION', 'INVENTORY', 'EXPIRED', 'DISCARDED', 'TRANSFER', 'INITIAL');
|
||||
CREATE TYPE shopping_list_status AS ENUM ('ACTIVE', 'COMPLETED', 'ARCHIVED');
|
||||
CREATE TYPE price_type AS ENUM ('REGULAR', 'OFFER', 'LOYALTY', 'UNKNOWN');
|
||||
CREATE TYPE source_kind AS ENUM ('USER_PURCHASE', 'USER_ESTIMATE', 'OFFICIAL_RETAILER', 'OFFICIAL_PROSPECT', 'GEMINI_GROUNDED', 'HISTORICAL_AVERAGE', 'AI_ESTIMATE');
|
||||
CREATE TYPE confidence_level AS ENUM ('HIGH', 'MEDIUM', 'LOW');
|
||||
CREATE TYPE budget_period AS ENUM ('WEEKLY', 'MONTHLY', 'CUSTOM');
|
||||
CREATE TYPE inventory_session_status AS ENUM ('OPEN', 'COMPLETED', 'CANCELLED');
|
||||
CREATE TYPE diet_type AS ENUM ('OMNIVORE', 'VEGETARIAN', 'VEGAN', 'PESCETARIAN', 'CUSTOM');
|
||||
CREATE TYPE pending_action_status AS ENUM ('PENDING', 'CONFIRMED', 'REJECTED', 'EXPIRED');
|
||||
|
||||
-- Trigger to update updated_at
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 1. Profiles
|
||||
CREATE TABLE IF NOT EXISTS public.profiles (
|
||||
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
display_name TEXT NOT NULL,
|
||||
avatar_path TEXT,
|
||||
locale TEXT NOT NULL DEFAULT 'de-DE',
|
||||
timezone TEXT NOT NULL DEFAULT 'Europe/Berlin',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 2. Households
|
||||
CREATE TABLE IF NOT EXISTS public.households (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
locale TEXT NOT NULL DEFAULT 'de-DE',
|
||||
timezone TEXT NOT NULL DEFAULT 'Europe/Berlin',
|
||||
postal_code TEXT,
|
||||
city TEXT,
|
||||
aldi_region aldi_region_type NOT NULL DEFAULT 'UNSPECIFIED',
|
||||
default_servings INT NOT NULL DEFAULT 2 CHECK (default_servings > 0),
|
||||
owner_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 3. Household Members
|
||||
CREATE TABLE IF NOT EXISTS public.household_members (
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
|
||||
role household_role NOT NULL DEFAULT 'MEMBER',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (household_id, user_id)
|
||||
);
|
||||
|
||||
-- 4. Categories
|
||||
CREATE TABLE IF NOT EXISTS public.categories (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
icon TEXT,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 5. Locations (supports nesting)
|
||||
CREATE TABLE IF NOT EXISTS public.locations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
parent_location_id UUID REFERENCES public.locations(id) ON DELETE SET NULL,
|
||||
name TEXT NOT NULL,
|
||||
icon TEXT,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 6. Units
|
||||
CREATE TABLE IF NOT EXISTS public.units (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID REFERENCES public.households(id) ON DELETE CASCADE, -- NULL for system defaults
|
||||
name TEXT NOT NULL,
|
||||
abbreviation TEXT NOT NULL,
|
||||
unit_type unit_type NOT NULL DEFAULT 'COUNT',
|
||||
allows_decimals BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 7. Products
|
||||
CREATE TABLE IF NOT EXISTS public.products (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
category_id UUID REFERENCES public.categories(id) ON DELETE SET NULL,
|
||||
default_location_id UUID REFERENCES public.locations(id) ON DELETE SET NULL,
|
||||
default_unit_id UUID REFERENCES public.units(id) ON DELETE SET NULL,
|
||||
name TEXT NOT NULL,
|
||||
brand TEXT,
|
||||
description TEXT,
|
||||
barcode TEXT,
|
||||
image_path TEXT,
|
||||
package_size NUMERIC(10, 3) NOT NULL DEFAULT 1.0,
|
||||
package_unit TEXT NOT NULL DEFAULT 'Stück',
|
||||
minimum_quantity NUMERIC(10, 3) NOT NULL DEFAULT 0.0 CHECK (minimum_quantity >= 0),
|
||||
favorite BOOLEAN NOT NULL DEFAULT false,
|
||||
preferred_store TEXT,
|
||||
estimated_price_cents INT CHECK (estimated_price_cents >= 0),
|
||||
price_updated_at TIMESTAMPTZ,
|
||||
archived BOOLEAN NOT NULL DEFAULT false,
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 8. Inventory Batches
|
||||
CREATE TABLE IF NOT EXISTS public.inventory_batches (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
product_id UUID NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,
|
||||
location_id UUID REFERENCES public.locations(id) ON DELETE SET NULL,
|
||||
quantity NUMERIC(10, 3) NOT NULL DEFAULT 0.0 CHECK (quantity >= 0),
|
||||
expiration_date DATE,
|
||||
purchase_date DATE,
|
||||
purchase_price_cents INT CHECK (purchase_price_cents >= 0),
|
||||
store TEXT,
|
||||
lot_number TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 9. Stock Movements
|
||||
CREATE TABLE IF NOT EXISTS public.stock_movements (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
product_id UUID NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,
|
||||
batch_id UUID REFERENCES public.inventory_batches(id) ON DELETE SET NULL,
|
||||
quantity_before NUMERIC(10, 3) NOT NULL,
|
||||
quantity_change NUMERIC(10, 3) NOT NULL,
|
||||
quantity_after NUMERIC(10, 3) NOT NULL CHECK (quantity_after >= 0),
|
||||
reason stock_movement_reason NOT NULL,
|
||||
note TEXT,
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 10. Shopping Lists
|
||||
CREATE TABLE IF NOT EXISTS public.shopping_lists (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL DEFAULT 'Einkaufsliste',
|
||||
status shopping_list_status NOT NULL DEFAULT 'ACTIVE',
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 11. Shopping List Items
|
||||
CREATE TABLE IF NOT EXISTS public.shopping_list_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
shopping_list_id UUID NOT NULL REFERENCES public.shopping_lists(id) ON DELETE CASCADE,
|
||||
product_id UUID REFERENCES public.products(id) ON DELETE SET NULL,
|
||||
custom_name TEXT,
|
||||
quantity NUMERIC(10, 3) NOT NULL DEFAULT 1.0 CHECK (quantity > 0),
|
||||
unit_id UUID REFERENCES public.units(id) ON DELETE SET NULL,
|
||||
estimated_unit_price_cents INT CHECK (estimated_unit_price_cents >= 0),
|
||||
selected_store TEXT,
|
||||
checked BOOLEAN NOT NULL DEFAULT false,
|
||||
automatically_added BOOLEAN NOT NULL DEFAULT false,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 12. Purchases
|
||||
CREATE TABLE IF NOT EXISTS public.purchases (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
store TEXT NOT NULL,
|
||||
purchase_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
total_price_cents INT NOT NULL DEFAULT 0 CHECK (total_price_cents >= 0),
|
||||
receipt_image_path TEXT,
|
||||
notes TEXT,
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 13. Purchase Items
|
||||
CREATE TABLE IF NOT EXISTS public.purchase_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
purchase_id UUID NOT NULL REFERENCES public.purchases(id) ON DELETE CASCADE,
|
||||
product_id UUID REFERENCES public.products(id) ON DELETE SET NULL,
|
||||
quantity NUMERIC(10, 3) NOT NULL DEFAULT 1.0 CHECK (quantity > 0),
|
||||
unit_price_cents INT NOT NULL CHECK (unit_price_cents >= 0),
|
||||
total_price_cents INT NOT NULL CHECK (total_price_cents >= 0),
|
||||
package_size NUMERIC(10, 3),
|
||||
package_unit TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 14. Price Observations
|
||||
CREATE TABLE IF NOT EXISTS public.price_observations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
product_id UUID REFERENCES public.products(id) ON DELETE SET NULL,
|
||||
product_name TEXT NOT NULL,
|
||||
brand TEXT,
|
||||
package_size NUMERIC(10, 3),
|
||||
package_unit TEXT,
|
||||
price_cents INT NOT NULL CHECK (price_cents >= 0),
|
||||
base_price_cents INT CHECK (base_price_cents >= 0),
|
||||
base_price_unit TEXT,
|
||||
retailer TEXT NOT NULL,
|
||||
price_type price_type NOT NULL DEFAULT 'REGULAR',
|
||||
postal_code TEXT,
|
||||
region TEXT,
|
||||
source_url TEXT,
|
||||
source_title TEXT,
|
||||
observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
valid_from DATE,
|
||||
valid_until DATE,
|
||||
confidence confidence_level NOT NULL DEFAULT 'MEDIUM',
|
||||
exact_match BOOLEAN NOT NULL DEFAULT true,
|
||||
verified BOOLEAN NOT NULL DEFAULT false,
|
||||
source_kind source_kind NOT NULL DEFAULT 'USER_ESTIMATE',
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 15. Budgets
|
||||
CREATE TABLE IF NOT EXISTS public.budgets (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
period budget_period NOT NULL DEFAULT 'MONTHLY',
|
||||
amount_cents INT NOT NULL CHECK (amount_cents >= 0),
|
||||
warning_threshold_percent INT NOT NULL DEFAULT 80 CHECK (warning_threshold_percent BETWEEN 1 AND 100),
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 16. Inventory Sessions
|
||||
CREATE TABLE IF NOT EXISTS public.inventory_sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
location_id UUID REFERENCES public.locations(id) ON DELETE SET NULL,
|
||||
status inventory_session_status NOT NULL DEFAULT 'OPEN',
|
||||
started_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
completed_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 17. Inventory Session Items
|
||||
CREATE TABLE IF NOT EXISTS public.inventory_session_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id UUID NOT NULL REFERENCES public.inventory_sessions(id) ON DELETE CASCADE,
|
||||
product_id UUID NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,
|
||||
expected_quantity NUMERIC(10, 3) NOT NULL DEFAULT 0.0,
|
||||
counted_quantity NUMERIC(10, 3) NOT NULL DEFAULT 0.0,
|
||||
difference NUMERIC(10, 3) NOT NULL DEFAULT 0.0,
|
||||
confirmed BOOLEAN NOT NULL DEFAULT false,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 18. Dietary Preferences
|
||||
CREATE TABLE IF NOT EXISTS public.dietary_preferences (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL UNIQUE REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
diet_type diet_type NOT NULL DEFAULT 'OMNIVORE',
|
||||
excluded_ingredients TEXT[] NOT NULL DEFAULT '{}',
|
||||
allergens TEXT[] NOT NULL DEFAULT '{}',
|
||||
preferred_cuisines TEXT[] NOT NULL DEFAULT '{}',
|
||||
maximum_preparation_minutes INT,
|
||||
maximum_meal_budget_cents INT,
|
||||
default_servings INT NOT NULL DEFAULT 2,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 19. Recipes
|
||||
CREATE TABLE IF NOT EXISTS public.recipes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
servings INT NOT NULL DEFAULT 2,
|
||||
preparation_minutes INT,
|
||||
difficulty TEXT,
|
||||
estimated_cost_cents INT,
|
||||
inventory_coverage_percent INT NOT NULL DEFAULT 0,
|
||||
ingredients_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
steps_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
dietary_tags TEXT[] NOT NULL DEFAULT '{}',
|
||||
allergen_warnings TEXT[] NOT NULL DEFAULT '{}',
|
||||
source_information_json JSONB,
|
||||
created_by_ai BOOLEAN NOT NULL DEFAULT false,
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 20. Meal Plans
|
||||
CREATE TABLE IF NOT EXISTS public.meal_plans (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE NOT NULL,
|
||||
estimated_total_cost_cents INT,
|
||||
plan_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
created_by UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 21. AI Settings
|
||||
CREATE TABLE IF NOT EXISTS public.ai_settings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL UNIQUE REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
preferred_retailers TEXT[] NOT NULL DEFAULT '{"KAUFLAND", "REWE", "ALDI_NORD", "ALDI_SUED", "LIDL"}',
|
||||
allow_google_search BOOLEAN NOT NULL DEFAULT true,
|
||||
daily_request_limit INT NOT NULL DEFAULT 30 CHECK (daily_request_limit > 0),
|
||||
automatic_price_updates BOOLEAN NOT NULL DEFAULT false,
|
||||
price_update_interval_days INT NOT NULL DEFAULT 14 CHECK (price_update_interval_days > 0),
|
||||
maximum_products_per_price_request INT NOT NULL DEFAULT 20 CHECK (maximum_products_per_price_request > 0),
|
||||
save_chat_history BOOLEAN NOT NULL DEFAULT true,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 22. AI Request Logs
|
||||
CREATE TABLE IF NOT EXISTS public.ai_request_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
user_id UUID REFERENCES public.profiles(id) ON DELETE SET NULL,
|
||||
feature TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
grounding_used BOOLEAN NOT NULL DEFAULT false,
|
||||
input_token_count INT,
|
||||
output_token_count INT,
|
||||
latency_ms INT,
|
||||
successful BOOLEAN NOT NULL DEFAULT true,
|
||||
error_code TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 23. AI Pending Actions
|
||||
CREATE TABLE IF NOT EXISTS public.ai_pending_actions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
household_id UUID NOT NULL REFERENCES public.households(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
|
||||
action_type TEXT NOT NULL,
|
||||
payload_json JSONB NOT NULL,
|
||||
status pending_action_status NOT NULL DEFAULT 'PENDING',
|
||||
expires_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() + INTERVAL '24 hours'),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
confirmed_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- 24. Rate Limit Events
|
||||
CREATE TABLE IF NOT EXISTS public.rate_limit_events (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
|
||||
action TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Triggers for updated_at
|
||||
CREATE TRIGGER trg_profiles_updated_at BEFORE UPDATE ON public.profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_households_updated_at BEFORE UPDATE ON public.households FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_categories_updated_at BEFORE UPDATE ON public.categories FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_locations_updated_at BEFORE UPDATE ON public.locations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_products_updated_at BEFORE UPDATE ON public.products FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_inventory_batches_updated_at BEFORE UPDATE ON public.inventory_batches FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_shopping_lists_updated_at BEFORE UPDATE ON public.shopping_lists FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_shopping_list_items_updated_at BEFORE UPDATE ON public.shopping_list_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_purchases_updated_at BEFORE UPDATE ON public.purchases FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_budgets_updated_at BEFORE UPDATE ON public.budgets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_inventory_session_items_updated_at BEFORE UPDATE ON public.inventory_session_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_dietary_preferences_updated_at BEFORE UPDATE ON public.dietary_preferences FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_recipes_updated_at BEFORE UPDATE ON public.recipes FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_meal_plans_updated_at BEFORE UPDATE ON public.meal_plans FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER trg_ai_settings_updated_at BEFORE UPDATE ON public.ai_settings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Indexes for optimal query performance
|
||||
CREATE INDEX idx_household_members_user ON public.household_members(user_id);
|
||||
CREATE INDEX idx_products_household ON public.products(household_id);
|
||||
CREATE INDEX idx_products_category ON public.products(category_id);
|
||||
CREATE INDEX idx_products_location ON public.products(default_location_id);
|
||||
CREATE INDEX idx_products_barcode ON public.products(barcode);
|
||||
CREATE INDEX idx_inventory_batches_product ON public.inventory_batches(product_id);
|
||||
CREATE INDEX idx_inventory_batches_household ON public.inventory_batches(household_id);
|
||||
CREATE INDEX idx_inventory_batches_exp ON public.inventory_batches(expiration_date);
|
||||
CREATE INDEX idx_stock_movements_product ON public.stock_movements(product_id);
|
||||
CREATE INDEX idx_stock_movements_household ON public.stock_movements(household_id);
|
||||
CREATE INDEX idx_shopping_list_items_list ON public.shopping_list_items(shopping_list_id);
|
||||
CREATE INDEX idx_purchases_household_date ON public.purchases(household_id, purchase_date);
|
||||
CREATE INDEX idx_price_observations_product ON public.price_observations(product_id);
|
||||
CREATE INDEX idx_price_observations_observed ON public.price_observations(observed_at);
|
||||
CREATE INDEX idx_rate_limit_events_user_action ON public.rate_limit_events(user_id, action, created_at);
|
||||
Reference in New Issue
Block a user