Spaces:
Running
Running
File size: 7,445 Bytes
1313d86 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | -- ==========================================
-- 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;
|