-- Profile-Avatar storage bucket. -- -- Layout: /.webp -- Public read so peers can see each other's avatar without auth roundtrip -- (avatars are non-sensitive). Write/update/delete restricted to the owning -- user via path prefix matching their auth.uid(). insert into storage.buckets (id, name, public) values ('profile-avatars', 'profile-avatars', true) on conflict (id) do nothing; -- Read: anyone authenticated can view any avatar (public bucket also lets -- unauth fetch by URL but our RLS keeps the table-level policy explicit). drop policy if exists profile_avatars_select on storage.objects; create policy profile_avatars_select on storage.objects for select to authenticated, anon using (bucket_id = 'profile-avatars'); -- Write only into your own folder (first path segment must equal auth.uid()). drop policy if exists profile_avatars_insert_own on storage.objects; create policy profile_avatars_insert_own on storage.objects for insert to authenticated with check ( bucket_id = 'profile-avatars' and (storage.foldername(name))[1] = auth.uid()::text ); drop policy if exists profile_avatars_update_own on storage.objects; create policy profile_avatars_update_own on storage.objects for update to authenticated using ( bucket_id = 'profile-avatars' and (storage.foldername(name))[1] = auth.uid()::text ) with check ( bucket_id = 'profile-avatars' and (storage.foldername(name))[1] = auth.uid()::text ); drop policy if exists profile_avatars_delete_own on storage.objects; create policy profile_avatars_delete_own on storage.objects for delete to authenticated using ( bucket_id = 'profile-avatars' and (storage.foldername(name))[1] = auth.uid()::text );