Spaces:
Running
Running
| -- ========================================== | |
| -- SpendWise Full Database Setup Script | |
| -- Paste this into your Supabase SQL Editor | |
| -- ========================================== | |
| -- 1. Enable Extensions | |
| CREATE EXTENSION IF NOT EXISTS vector; | |
| CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; | |
| -- 2. Users Profile Table | |
| CREATE TABLE IF NOT EXISTS public.profiles ( | |
| id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, | |
| email TEXT UNIQUE NOT NULL, | |
| display_name TEXT, | |
| currency TEXT DEFAULT 'INR', | |
| timezone TEXT DEFAULT 'Asia/Kolkata', | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_profile" ON public.profiles | |
| FOR ALL USING (auth.uid() = id); | |
| -- 3. Categories Table | |
| CREATE TABLE IF NOT EXISTS public.categories ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| name TEXT NOT NULL, | |
| icon TEXT, | |
| color TEXT, | |
| is_system BOOLEAN DEFAULT FALSE, | |
| parent_id UUID REFERENCES public.categories(id), | |
| created_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| ALTER TABLE public.categories ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_categories" ON public.categories | |
| FOR ALL USING (auth.uid() = user_id OR is_system = TRUE); | |
| INSERT INTO public.categories (name, icon, color, is_system, user_id) VALUES | |
| ('Food & Dining', 'π½οΈ', '#FF6B6B', TRUE, NULL), | |
| ('Transport', 'π', '#4ECDC4', TRUE, NULL), | |
| ('Shopping', 'ποΈ', '#45B7D1', TRUE, NULL), | |
| ('Entertainment', 'π¬', '#96CEB4', TRUE, NULL), | |
| ('Utilities', 'β‘', '#FFEAA7', TRUE, NULL), | |
| ('Health & Medical', 'π₯', '#DDA0DD', TRUE, NULL), | |
| ('Education', 'π', '#98D8C8', TRUE, NULL), | |
| ('Travel', 'βοΈ', '#F7DC6F', TRUE, NULL), | |
| ('Financial Services', 'π³', '#82E0AA', TRUE, NULL), | |
| ('Groceries', 'π', '#F8C471', TRUE, NULL), | |
| ('Peer Transfer', 'π€', '#AED6F1', TRUE, NULL), | |
| ('Others', 'π¦', '#D5DBDB', TRUE, NULL) | |
| ON CONFLICT DO NOTHING; | |
| -- 4. Transactions Table | |
| CREATE TABLE IF NOT EXISTS public.transactions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| raw_description TEXT NOT NULL, | |
| amount NUMERIC(14, 2) NOT NULL, | |
| direction TEXT CHECK (direction IN ('debit', 'credit')) NOT NULL, | |
| balance NUMERIC(14, 2), | |
| transaction_date TIMESTAMPTZ NOT NULL, | |
| payment_method TEXT CHECK (payment_method IN ('UPI', 'IMPS', 'NEFT', 'ATM', 'OTHER')), | |
| cleaned_description TEXT, | |
| merchant_name TEXT, | |
| is_low_descriptiveness BOOLEAN DEFAULT FALSE, | |
| category_id UUID REFERENCES public.categories(id), | |
| category_source TEXT CHECK (category_source IN ('semantic','behavioural','fused','zero_shot','manual','pending')), | |
| confidence_score NUMERIC(4, 3), | |
| gating_alpha NUMERIC(4, 3), | |
| is_recurring BOOLEAN DEFAULT FALSE, | |
| recurrence_strength NUMERIC(4, 3), | |
| needs_review BOOLEAN DEFAULT FALSE, | |
| user_corrected BOOLEAN DEFAULT FALSE, | |
| user_category_id UUID REFERENCES public.categories(id), | |
| processing_status TEXT DEFAULT 'pending' CHECK ( | |
| processing_status IN ('pending', 'processing', 'completed', 'failed') | |
| ), | |
| processed_at TIMESTAMPTZ, | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| CREATE INDEX idx_transactions_user_date ON public.transactions(user_id, transaction_date DESC); | |
| CREATE INDEX idx_transactions_category ON public.transactions(user_id, category_id); | |
| CREATE INDEX idx_transactions_status ON public.transactions(user_id, processing_status); | |
| CREATE INDEX idx_transactions_merchant ON public.transactions(user_id, merchant_name); | |
| ALTER TABLE public.transactions ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_transactions" ON public.transactions | |
| FOR ALL USING (auth.uid() = user_id); | |
| -- 5. Embeddings Table | |
| CREATE TABLE IF NOT EXISTS public.transaction_embeddings ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| transaction_id UUID UNIQUE NOT NULL REFERENCES public.transactions(id) ON DELETE CASCADE, | |
| user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| embedding vector(768), | |
| created_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| CREATE INDEX ON public.transaction_embeddings | |
| USING ivfflat (embedding vector_cosine_ops) | |
| WITH (lists = 100); | |
| ALTER TABLE public.transaction_embeddings ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_embeddings" ON public.transaction_embeddings | |
| FOR ALL USING (auth.uid() = user_id); | |
| -- 6. Cluster State Table | |
| CREATE TABLE IF NOT EXISTS public.user_clusters ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| cluster_id INTEGER NOT NULL, | |
| category_id UUID REFERENCES public.categories(id), | |
| label_name TEXT, | |
| transaction_count INTEGER DEFAULT 0, | |
| last_clustered TIMESTAMPTZ DEFAULT NOW(), | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| UNIQUE (user_id, cluster_id) | |
| ); | |
| ALTER TABLE public.user_clusters ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_clusters" ON public.user_clusters | |
| FOR ALL USING (auth.uid() = user_id); | |
| -- 7. Budgets Table | |
| CREATE TABLE IF NOT EXISTS public.budgets ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| category_id UUID NOT NULL REFERENCES public.categories(id), | |
| amount NUMERIC(14, 2) NOT NULL, | |
| period TEXT CHECK (period IN ('monthly', 'weekly', 'annual')) DEFAULT 'monthly', | |
| start_date DATE NOT NULL, | |
| end_date DATE, | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| ALTER TABLE public.budgets ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_budgets" ON public.budgets | |
| FOR ALL USING (auth.uid() = user_id); | |
| -- 8. Gating Model Weights Table | |
| CREATE TABLE IF NOT EXISTS public.gating_model_state ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID UNIQUE NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, | |
| W1 JSONB, | |
| b1 JSONB, | |
| W2 JSONB, | |
| b2 FLOAT, | |
| training_samples INTEGER DEFAULT 0, | |
| val_mse FLOAT, | |
| trained_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| ALTER TABLE public.gating_model_state ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "users_own_model" ON public.gating_model_state | |
| FOR ALL USING (auth.uid() = user_id); | |
| -- 9. Triggers | |
| CREATE OR REPLACE FUNCTION update_updated_at_column() | |
| RETURNS TRIGGER AS $$ | |
| BEGIN | |
| NEW.updated_at = NOW(); | |
| RETURN NEW; | |
| END; | |
| $$ LANGUAGE plpgsql; | |
| CREATE TRIGGER update_transactions_updated_at | |
| BEFORE UPDATE ON public.transactions | |
| FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | |
| CREATE TRIGGER update_budgets_updated_at | |
| BEFORE UPDATE ON public.budgets | |
| FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | |
| -- Note: Run this last manually or ensure publication exists | |
| -- ALTER PUBLICATION supabase_realtime ADD TABLE public.transactions; | |