math-solver / migrations /v4_migration.sql
Cuong2004
Deploy API from GitHub Actions
395651c
-- ============================================================
-- MATHSOLVER v4.0 - Migration Script (Multi-Session & History)
-- ============================================================
-- 1. Profiles Table (Extends Supabase Auth)
CREATE TABLE IF NOT EXISTS public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
display_name TEXT,
avatar_url TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Function to handle new user signup and auto-create profile
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, display_name, avatar_url)
VALUES (
NEW.id,
COALESCE(NEW.raw_user_meta_data->>'full_name', NEW.email),
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Trigger for profile creation
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
-- 2. Sessions Table
CREATE TABLE IF NOT EXISTS public.sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
title TEXT DEFAULT 'Bài toán mới',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index for sessions
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON public.sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_sessions_updated_at ON public.sessions(updated_at DESC);
-- 3. Messages Table
CREATE TABLE IF NOT EXISTS public.messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES public.sessions(id) ON DELETE CASCADE,
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
type TEXT NOT NULL DEFAULT 'text',
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index for messages
CREATE INDEX IF NOT EXISTS idx_messages_session_id ON public.messages(session_id);
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON public.messages(session_id, created_at);
-- 4. Session Assets Table (v5.1 Versioning)
CREATE TABLE IF NOT EXISTS public.session_assets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES public.sessions(id) ON DELETE CASCADE,
job_id UUID NOT NULL,
asset_type TEXT NOT NULL CHECK (asset_type IN ('video', 'image')),
storage_path TEXT NOT NULL,
public_url TEXT NOT NULL,
version INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index for session_assets
CREATE INDEX IF NOT EXISTS idx_session_assets_session_id ON public.session_assets(session_id);
-- 5. Update Jobs Table
ALTER TABLE public.jobs ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES auth.users(id);
ALTER TABLE public.jobs ADD COLUMN IF NOT EXISTS session_id UUID REFERENCES public.sessions(id);
-- 6. Row Level Security (RLS)
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.session_assets ENABLE ROW LEVEL SECURITY;
-- Polices for public.profiles
DROP POLICY IF EXISTS "Users view own profile" ON public.profiles;
CREATE POLICY "Users view own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
DROP POLICY IF EXISTS "Users update own profile" ON public.profiles;
CREATE POLICY "Users update own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
-- Policies for public.sessions
DROP POLICY IF EXISTS "Users manage own sessions" ON public.sessions;
CREATE POLICY "Users manage own sessions" ON public.sessions FOR ALL USING (auth.uid() = user_id);
-- Policies for public.messages
DROP POLICY IF EXISTS "Users manage own messages" ON public.messages;
CREATE POLICY "Users manage own messages" ON public.messages FOR ALL USING (
session_id IN (SELECT id FROM public.sessions WHERE user_id = auth.uid())
OR (auth.jwt() ->> 'role' = 'service_role')
);
-- Policies for public.session_assets
DROP POLICY IF EXISTS "Users view own assets" ON public.session_assets;
CREATE POLICY "Users view own assets" ON public.session_assets FOR SELECT USING (
session_id IN (SELECT id FROM public.sessions WHERE user_id = auth.uid())
);
DROP POLICY IF EXISTS "Service role manages assets" ON public.session_assets;
CREATE POLICY "Service role manages assets" ON public.session_assets FOR ALL USING (true);
-- Policies for public.jobs
DROP POLICY IF EXISTS "Users manage own jobs" ON public.jobs;
CREATE POLICY "Users manage own jobs" ON public.jobs FOR ALL USING (
auth.uid() = user_id OR user_id IS NULL OR (auth.jwt() ->> 'role' = 'service_role')
);
-- 7. Storage Policies (Bucket: video)
-- (Run this in Supabase Dashboard if not allowed in migration)
-- INSERT INTO storage.buckets (id, name, public) VALUES ('video', 'video', true) ON CONFLICT (id) DO NOTHING;
-- CREATE POLICY "Service Role manage videos" ON storage.objects FOR ALL TO service_role USING (bucket_id = 'video');
-- CREATE POLICY "Public read videos" ON storage.objects FOR SELECT TO public USING (bucket_id = 'video');
-- Grant permissions to public/authenticated
GRANT ALL ON public.profiles TO authenticated;
GRANT ALL ON public.sessions TO authenticated;
GRANT ALL ON public.messages TO authenticated;
GRANT ALL ON public.jobs TO authenticated;
GRANT ALL ON public.session_assets TO authenticated;
GRANT ALL ON public.session_assets TO service_role;