Set up the required database tables and policies for Launchtoday’s profile and feedback features
Launchtoday comes with pre-built profile and feedback screens that require specific database tables and security policies to function. This guide provides the necessary SQL setup that powers these features:
The profiles table that drives the Profile screen, including user avatars and profile information
The feedback table that enables the Feedback submission screen
For a quick setup, you can run the complete SQL script below in your Supabase SQL editor (the URL should look like this: https://supabase.com/project/*your-project-id*/sql/new):
Copy
-- Create a table for public profilescreate table profiles ( id uuid references auth.users on delete cascade not null primary key, updated_at timestamp with time zone, username text unique, avatar_url text, website text, bio text, has_seen_onboarding boolean, full_name text, constraint username_length check (char_length(username) >= 3));-- Set up Row Level Security (RLS)alter table profiles enable row level security;create policy "Public profiles are viewable by everyone." on profiles for select using (true);create policy "Users can insert their own profile." on profiles for insert with check ((select auth.uid()) = id);create policy "Users can update own profile." on profiles for update using ((select auth.uid()) = id);-- Create feedback tablecreate table feedback ( id bigint primary key, user_id uuid references auth.users not null, type text, title text, description text, created_at timestamp with time zone);-- Set up Row Level Security (RLS) for feedback tablealter table feedback enable row level security;-- Add policies for feedback tablecreate policy "Users can view their own feedback." on feedback for select using ((select auth.uid()) = user_id);create policy "Users can insert their own feedback." on feedback for insert with check ((select auth.uid()) = user_id);-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.create function public.handle_new_user()returns triggerset search_path = ''as $$begin insert into public.profiles (id, full_name, avatar_url) values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); return new;end;$$ language plpgsql security definer;create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user();-- Set up Storage!insert into storage.buckets (id, name) values ('avatars', 'avatars');-- Set up storage policiesCREATE POLICY "allow_avatar_reads"ON storage.objects FOR SELECTUSING ( bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text);CREATE POLICY "allow_avatar_uploads"ON storage.objects FOR INSERTWITH CHECK ( bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text AND (auth.uid())::text = (storage.foldername(name))[1]);CREATE POLICY "allow_avatar_updates"ON storage.objects FOR UPDATEUSING ( bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text AND (auth.uid())::text = (storage.foldername(name))[1]);CREATE POLICY "allow_avatar_deletes"ON storage.objects FOR DELETEUSING ( bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text AND (auth.uid())::text = (storage.foldername(name))[1]);
First, let’s set up the profiles table that stores user information:
Copy
-- Create profiles tablecreate table profiles ( id uuid references auth.users on delete cascade not null primary key, updated_at timestamp with time zone, username text unique, avatar_url text, website text, bio text, has_seen_onboarding boolean, full_name text, constraint username_length check (char_length(username) >= 3));-- Enable RLS and set up profile policiesalter table profiles enable row level security;create policy "Public profiles are viewable by everyone." on profiles for select using (true);create policy "Users can insert their own profile." on profiles for insert with check ((select auth.uid()) = id);create policy "Users can update own profile." on profiles for update using ((select auth.uid()) = id);
What this does:
Creates a profiles table linked to auth.users
Enables row-level security
Sets up policies for viewing, creating, and updating profiles
Set up automatic profile creation when users sign up:
Copy
create function public.handle_new_user()returns trigger as $$begin insert into public.profiles (id, full_name, avatar_url) values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); return new;end;$$ language plpgsql security definer;create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user();
What this does:
Creates a trigger function that runs when new users sign up
Automatically creates profile entries for new users
create table feedback ( id bigint primary key, user_id uuid references auth.users not null, type text, title text, description text, created_at timestamp with time zone);-- Enable RLS and set up feedback policiesalter table feedback enable row level security;create policy "Users can view their own feedback." on feedback for select using ((select auth.uid()) = user_id);create policy "Users can insert their own feedback." on feedback for insert with check ((select auth.uid()) = user_id);
What this does:
Creates a feedback table for user submissions
Enables row-level security
Sets up policies so users can only view and create their own feedback
Finally, set up the storage system for profile pictures:
Copy
-- Create avatar storage bucketinsert into storage.buckets (id, name) values ('avatars', 'avatars');-- Set up storage policiesCREATE POLICY "allow_avatar_reads" ON storage.objects FOR SELECT USING (bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text);CREATE POLICY "allow_avatar_uploads" ON storage.objects FOR INSERT WITH CHECK ( bucket_id = 'avatars'::text AND auth.role() = 'authenticated'::text AND (auth.uid())::text = (storage.foldername(name))[1] );-- Similar policies for updates and deletes...
What this does:
Creates a storage bucket for avatars
Sets up policies for reading, uploading, updating, and deleting avatars