-- Enable UUID extension CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- Create users table CREATE TABLE IF NOT EXISTS public.users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), auth_provider_id TEXT, username TEXT UNIQUE NOT NULL, email TEXT UNIQUE NOT NULL, avatar_url TEXT, bio TEXT, is_public_profile BOOLEAN DEFAULT false, countdown_start_date TIMESTAMPTZ, countdown_end_date TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Create goals table CREATE TABLE IF NOT EXISTS public.goals ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), owner_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, title TEXT NOT NULL, description TEXT, progress INTEGER DEFAULT 0 CHECK (progress >= 0 AND progress <= 100), location_lat DOUBLE PRECISION, location_lng DOUBLE PRECISION, location_name TEXT, image_url TEXT, completed BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Create goal_steps table CREATE TABLE IF NOT EXISTS public.goal_steps ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), goal_id UUID NOT NULL REFERENCES public.goals(id) ON DELETE CASCADE, title TEXT NOT NULL, is_done BOOLEAN DEFAULT false, order_index INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Create followers table CREATE TABLE IF NOT EXISTS public.followers ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, follower_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(user_id, follower_id) ); -- Create activities table CREATE TABLE IF NOT EXISTS public.activities ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, type TEXT NOT NULL, payload JSONB, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Create notifications table CREATE TABLE IF NOT EXISTS public.notifications ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, type TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, scheduled_for TIMESTAMPTZ, delivered_at TIMESTAMPTZ ); -- Create indexes CREATE INDEX IF NOT EXISTS idx_goals_owner_id ON public.goals(owner_id); CREATE INDEX IF NOT EXISTS idx_goal_steps_goal_id ON public.goal_steps(goal_id); CREATE INDEX IF NOT EXISTS idx_followers_user_id ON public.followers(user_id); CREATE INDEX IF NOT EXISTS idx_followers_follower_id ON public.followers(follower_id); CREATE INDEX IF NOT EXISTS idx_activities_user_id_created_at ON public.activities(user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON public.notifications(user_id); -- Enable Row Level Security ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; ALTER TABLE public.goals ENABLE ROW LEVEL SECURITY; ALTER TABLE public.goal_steps ENABLE ROW LEVEL SECURITY; ALTER TABLE public.followers ENABLE ROW LEVEL SECURITY; ALTER TABLE public.activities ENABLE ROW LEVEL SECURITY; ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY; -- RLS Policies for users CREATE POLICY "Users can select their own profile" ON public.users FOR SELECT USING (auth.uid() = id); CREATE POLICY "Users can update their own profile" ON public.users FOR UPDATE USING (auth.uid() = id) WITH CHECK (auth.uid() = id); -- RLS Policies for goals CREATE POLICY "Users can read their own goals" ON public.goals FOR SELECT USING (auth.uid() = owner_id); CREATE POLICY "Users can insert their own goals" ON public.goals FOR INSERT WITH CHECK (auth.uid() = owner_id); CREATE POLICY "Users can update their own goals" ON public.goals FOR UPDATE USING (auth.uid() = owner_id) WITH CHECK (auth.uid() = owner_id); CREATE POLICY "Users can delete their own goals" ON public.goals FOR DELETE USING (auth.uid() = owner_id); -- RLS Policies for goal_steps CREATE POLICY "Users can read steps for their own goals" ON public.goal_steps FOR SELECT USING ( EXISTS ( SELECT 1 FROM public.goals g WHERE g.id = goal_id AND g.owner_id = auth.uid() ) ); CREATE POLICY "Users can insert steps for their own goals" ON public.goal_steps FOR INSERT WITH CHECK ( EXISTS ( SELECT 1 FROM public.goals g WHERE g.id = goal_id AND g.owner_id = auth.uid() ) ); CREATE POLICY "Users can update steps for their own goals" ON public.goal_steps FOR UPDATE USING ( EXISTS ( SELECT 1 FROM public.goals g WHERE g.id = goal_id AND g.owner_id = auth.uid() ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.goals g WHERE g.id = goal_id AND g.owner_id = auth.uid() ) ); CREATE POLICY "Users can delete steps for their own goals" ON public.goal_steps FOR DELETE USING ( EXISTS ( SELECT 1 FROM public.goals g WHERE g.id = goal_id AND g.owner_id = auth.uid() ) ); -- RLS Policies for followers CREATE POLICY "Users can read their follower relationships" ON public.followers FOR SELECT USING (auth.uid() = user_id OR auth.uid() = follower_id); CREATE POLICY "Users can follow others" ON public.followers FOR INSERT WITH CHECK (auth.uid() = follower_id); CREATE POLICY "Users can unfollow or remove followers" ON public.followers FOR DELETE USING (auth.uid() = user_id OR auth.uid() = follower_id); -- RLS Policies for activities CREATE POLICY "Users can read their own activity" ON public.activities FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own activity events" ON public.activities FOR INSERT WITH CHECK (auth.uid() = user_id); -- RLS Policies for notifications CREATE POLICY "Users can read their own notifications" ON public.notifications FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can receive their own notifications" ON public.notifications FOR INSERT WITH CHECK (auth.uid() = user_id); CREATE POLICY "Users can delete their own notifications" ON public.notifications FOR DELETE USING (auth.uid() = user_id); -- 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; -- Triggers for updated_at CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON public.users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_goals_updated_at BEFORE UPDATE ON public.goals FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();