-- Create roles if they don't exist DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'authenticated') THEN CREATE ROLE authenticated NOLOGIN; END IF; IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'anon') THEN CREATE ROLE anon NOLOGIN; END IF; END $$; CREATE SCHEMA IF NOT EXISTS storage; -- Grant usage GRANT USAGE ON SCHEMA storage TO authenticated, anon; GRANT USAGE ON SCHEMA public TO authenticated, anon; CREATE TABLE IF NOT EXISTS storage.buckets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, public BOOLEAN DEFAULT false, owner UUID REFERENCES public.users(id), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS storage.objects ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, bucket_id TEXT REFERENCES storage.buckets(id), name TEXT NOT NULL, owner UUID REFERENCES public.users(id), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), last_accessed_at TIMESTAMPTZ DEFAULT now(), metadata JSONB, UNIQUE (bucket_id, name) ); -- Grant table access (RLS will filter rows) GRANT ALL ON TABLE storage.buckets TO authenticated, anon; GRANT ALL ON TABLE storage.objects TO authenticated, anon; ALTER TABLE storage.buckets ENABLE ROW LEVEL SECURITY; ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY; -- Helper to allow public access to public buckets CREATE POLICY "Public Buckets are viewable by everyone" ON storage.buckets FOR SELECT USING ( public = true ); -- Helper to allow authenticated users to view their own buckets CREATE POLICY "Users can view their own buckets" ON storage.buckets FOR SELECT TO authenticated USING ( owner = current_setting('request.jwt.claim.sub', true)::uuid ); -- Objects policies depend on bucket public status or object owner CREATE POLICY "Public Objects are viewable by everyone" ON storage.objects FOR SELECT USING ( bucket_id IN (SELECT id FROM storage.buckets WHERE public = true) ); CREATE POLICY "Users can view their own objects" ON storage.objects FOR SELECT TO authenticated USING ( owner = current_setting('request.jwt.claim.sub', true)::uuid ); CREATE POLICY "Users can insert their own objects" ON storage.objects FOR INSERT TO authenticated WITH CHECK ( owner = current_setting('request.jwt.claim.sub', true)::uuid );