Spaces:
Running
Running
| -- Medical AI Platform Database Schema | |
| -- This is the ONLY schema file you need to run | |
| -- Run this in Supabase SQL Editor | |
| -- ============================================================================ | |
| -- STEP 1: Enable required extensions | |
| -- ============================================================================ | |
| CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; | |
| CREATE EXTENSION IF NOT EXISTS "vector"; | |
| -- ============================================================================ | |
| -- STEP 2: Create all tables | |
| -- ============================================================================ | |
| -- Users table | |
| CREATE TABLE IF NOT EXISTS public.users ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| email TEXT UNIQUE NOT NULL, | |
| name TEXT, | |
| plan TEXT NOT NULL DEFAULT 'free' CHECK (plan IN ('free', 'student', 'pro', 'admin')), | |
| role TEXT CHECK (role IN ('super_admin', 'admin', 'ops', 'support', 'viewer')), | |
| personal_api_key TEXT, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| disabled BOOLEAN NOT NULL DEFAULT FALSE | |
| ); | |
| -- Admin allowlist table | |
| CREATE TABLE IF NOT EXISTS public.admin_allowlist ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| email TEXT UNIQUE NOT NULL, | |
| role TEXT NOT NULL CHECK (role IN ('super_admin', 'admin', 'ops', 'support', 'viewer')), | |
| added_by UUID REFERENCES public.users(id), | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Usage counters table | |
| CREATE TABLE IF NOT EXISTS public.usage_counters ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| date DATE NOT NULL DEFAULT CURRENT_DATE, | |
| tokens_used INTEGER NOT NULL DEFAULT 0, | |
| requests_count INTEGER NOT NULL DEFAULT 0, | |
| pdf_uploads INTEGER NOT NULL DEFAULT 0, | |
| mcqs_generated INTEGER NOT NULL DEFAULT 0, | |
| images_used INTEGER NOT NULL DEFAULT 0, | |
| flashcards_generated INTEGER NOT NULL DEFAULT 0, | |
| UNIQUE(user_id, date) | |
| ); | |
| -- API keys table | |
| CREATE TABLE IF NOT EXISTS public.api_keys ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| provider TEXT NOT NULL, | |
| feature TEXT NOT NULL, | |
| key_value TEXT NOT NULL, | |
| priority INTEGER NOT NULL DEFAULT 0, | |
| status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'degraded', 'disabled')), | |
| failure_count INTEGER NOT NULL DEFAULT 0, | |
| last_used_at TIMESTAMPTZ, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Provider health table | |
| CREATE TABLE IF NOT EXISTS public.provider_health ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| api_key_id UUID NOT NULL REFERENCES public.api_keys(id) ON DELETE CASCADE, | |
| checked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| status TEXT NOT NULL CHECK (status IN ('healthy', 'degraded', 'failed')), | |
| response_time_ms INTEGER, | |
| error_message TEXT, | |
| quota_remaining INTEGER | |
| ); | |
| -- System flags table | |
| CREATE TABLE IF NOT EXISTS public.system_flags ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| flag_name TEXT UNIQUE NOT NULL, | |
| flag_value TEXT NOT NULL, | |
| updated_by UUID REFERENCES public.users(id), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Documents table | |
| CREATE TABLE IF NOT EXISTS public.documents ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| filename TEXT NOT NULL, | |
| file_type TEXT NOT NULL CHECK (file_type IN ('pdf', 'image')), | |
| file_size INTEGER NOT NULL, | |
| storage_path TEXT NOT NULL, | |
| processing_status TEXT NOT NULL DEFAULT 'pending' CHECK (processing_status IN ('pending', 'processing', 'completed', 'failed')), | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Embeddings table | |
| CREATE TABLE IF NOT EXISTS public.embeddings ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| document_id UUID NOT NULL REFERENCES public.documents(id) ON DELETE CASCADE, | |
| chunk_text TEXT NOT NULL, | |
| chunk_index INTEGER NOT NULL, | |
| embedding VECTOR(768), | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Chat sessions table | |
| CREATE TABLE IF NOT EXISTS public.chat_sessions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| title TEXT, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Messages table | |
| CREATE TABLE IF NOT EXISTS public.messages ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| session_id UUID NOT NULL REFERENCES public.chat_sessions(id) ON DELETE CASCADE, | |
| role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')), | |
| content TEXT NOT NULL, | |
| tokens_used INTEGER, | |
| citations JSONB, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Study sessions table | |
| CREATE TABLE IF NOT EXISTS public.study_sessions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| topic TEXT NOT NULL, | |
| duration INTEGER NOT NULL, | |
| scheduled_date TIMESTAMPTZ, | |
| notes TEXT, | |
| status TEXT NOT NULL DEFAULT 'planned' CHECK (status IN ('planned', 'in_progress', 'completed', 'cancelled')), | |
| completed_at TIMESTAMPTZ, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Subscriptions table | |
| CREATE TABLE IF NOT EXISTS public.subscriptions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| plan TEXT NOT NULL CHECK (plan IN ('free', 'student', 'pro', 'admin')), | |
| razorpay_subscription_id TEXT UNIQUE, | |
| status TEXT NOT NULL CHECK (status IN ('active', 'cancelled', 'expired')), | |
| current_period_start TIMESTAMPTZ, | |
| current_period_end TIMESTAMPTZ, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Payments table | |
| CREATE TABLE IF NOT EXISTS public.payments ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| subscription_id UUID REFERENCES public.subscriptions(id), | |
| razorpay_payment_id TEXT UNIQUE, | |
| amount INTEGER NOT NULL, | |
| currency TEXT NOT NULL DEFAULT 'INR', | |
| status TEXT NOT NULL CHECK (status IN ('success', 'failed', 'pending')), | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- Audit logs table | |
| CREATE TABLE IF NOT EXISTS public.audit_logs ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| admin_id UUID REFERENCES public.users(id), | |
| action_type TEXT NOT NULL, | |
| target_type TEXT, | |
| target_id TEXT, | |
| details JSONB, | |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ); | |
| -- ============================================================================ | |
| -- STEP 3: Create indexes | |
| -- ============================================================================ | |
| CREATE INDEX IF NOT EXISTS idx_users_email ON public.users(email); | |
| CREATE INDEX IF NOT EXISTS idx_admin_allowlist_email ON public.admin_allowlist(email); | |
| CREATE INDEX IF NOT EXISTS idx_usage_counters_user_date ON public.usage_counters(user_id, date); | |
| CREATE INDEX IF NOT EXISTS idx_api_keys_provider_feature ON public.api_keys(provider, feature); | |
| CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id ON public.chat_sessions(user_id); | |
| CREATE INDEX IF NOT EXISTS idx_messages_session_created ON public.messages(session_id, created_at); | |
| CREATE INDEX IF NOT EXISTS idx_documents_user_id ON public.documents(user_id); | |
| CREATE INDEX IF NOT EXISTS idx_audit_logs_admin_created ON public.audit_logs(admin_id, created_at DESC); | |
| -- ============================================================================ | |
| -- STEP 4: Create trigger for updated_at | |
| -- ============================================================================ | |
| CREATE OR REPLACE FUNCTION update_updated_at_column() | |
| RETURNS TRIGGER AS $$ | |
| BEGIN | |
| NEW.updated_at = NOW(); | |
| RETURN NEW; | |
| END; | |
| $$ LANGUAGE plpgsql; | |
| DROP TRIGGER IF EXISTS update_users_updated_at ON public.users; | |
| CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON public.users | |
| FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | |
| DROP TRIGGER IF EXISTS update_chat_sessions_updated_at ON public.chat_sessions; | |
| CREATE TRIGGER update_chat_sessions_updated_at BEFORE UPDATE ON public.chat_sessions | |
| FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | |
| -- ============================================================================ | |
| -- DONE! | |
| -- ============================================================================ | |
| SELECT 'Schema created successfully!' as status; | |