-- Enable UUID extension CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- Users table (extends Supabase auth.users) CREATE TABLE IF NOT EXISTS public.users ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, email TEXT NOT NULL UNIQUE, credits INTEGER NOT NULL DEFAULT 100, subscription_tier TEXT NOT NULL DEFAULT 'free', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Enable RLS ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; -- Users can only read their own data CREATE POLICY "Users can view own data" ON public.users FOR SELECT USING (auth.uid() = id); -- Users can update their own data CREATE POLICY "Users can update own data" ON public.users FOR UPDATE USING (auth.uid() = id); -- Generations table CREATE TABLE IF NOT EXISTS public.generations ( id TEXT PRIMARY KEY, user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('text-to-video', 'image-to-video')), prompt TEXT NOT NULL, negative_prompt TEXT, image_url TEXT, model TEXT NOT NULL, resolution TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed')), video_url TEXT, error TEXT, credits_used INTEGER NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), completed_at TIMESTAMP WITH TIME ZONE ); -- Enable RLS ALTER TABLE public.generations ENABLE ROW LEVEL SECURITY; -- Users can only view their own generations CREATE POLICY "Users can view own generations" ON public.generations FOR SELECT USING (auth.uid() = user_id); -- Users can insert their own generations CREATE POLICY "Users can create own generations" ON public.generations FOR INSERT WITH CHECK (auth.uid() = user_id); -- Credit transactions table CREATE TABLE IF NOT EXISTS public.credit_transactions ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, amount INTEGER NOT NULL, type TEXT NOT NULL CHECK (type IN ('addition', 'deduction', 'refund')), description TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Enable RLS ALTER TABLE public.credit_transactions ENABLE ROW LEVEL SECURITY; -- Users can only view their own transactions CREATE POLICY "Users can view own transactions" ON public.credit_transactions FOR SELECT USING (auth.uid() = user_id); -- Create indexes for better performance CREATE INDEX IF NOT EXISTS idx_generations_user_id ON public.generations(user_id); CREATE INDEX IF NOT EXISTS idx_generations_created_at ON public.generations(created_at DESC); CREATE INDEX IF NOT EXISTS idx_credit_transactions_user_id ON public.credit_transactions(user_id); CREATE INDEX IF NOT EXISTS idx_credit_transactions_created_at ON public.credit_transactions(created_at DESC); -- Function to update updated_at timestamp CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Trigger to auto-update updated_at CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON public.users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- Function to create user profile on signup CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS TRIGGER AS $$ BEGIN INSERT INTO public.users (id, email, credits, subscription_tier) VALUES (NEW.id, NEW.email, 100, 'free') ON CONFLICT (id) DO NOTHING; RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Trigger to create user profile on auth signup CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user(); -- Storage bucket for uploaded images (for I2V) INSERT INTO storage.buckets (id, name, public) VALUES ('images', 'images', true) ON CONFLICT (id) DO NOTHING; -- Storage policy for images CREATE POLICY "Users can upload own images" ON storage.objects FOR INSERT WITH CHECK ( bucket_id = 'images' AND auth.uid()::text = (storage.foldername(name))[1] ); CREATE POLICY "Images are publicly accessible" ON storage.objects FOR SELECT USING (bucket_id = 'images');