-- Profile-Banner: optional 3:1 hero image shown above the avatar in the -- UserProfilePopover and on the settings preview. Mirrors the -- profile-avatars bucket layout (separate bucket, owner-folder RLS, -- public read) so peers can fetch banners without an auth roundtrip. -- -- Layout: /.webp (target: 1500x500 WebP, <=8MB original) alter table public.profiles add column if not exists banner_url text; insert into storage.buckets (id, name, public) values ('profile-banners', 'profile-banners', true) on conflict (id) do nothing; drop policy if exists profile_banners_select on storage.objects; create policy profile_banners_select on storage.objects for select to authenticated, anon using (bucket_id = 'profile-banners'); drop policy if exists profile_banners_insert_own on storage.objects; create policy profile_banners_insert_own on storage.objects for insert to authenticated with check ( bucket_id = 'profile-banners' and (storage.foldername(name))[1] = auth.uid()::text ); drop policy if exists profile_banners_update_own on storage.objects; create policy profile_banners_update_own on storage.objects for update to authenticated using ( bucket_id = 'profile-banners' and (storage.foldername(name))[1] = auth.uid()::text ) with check ( bucket_id = 'profile-banners' and (storage.foldername(name))[1] = auth.uid()::text ); drop policy if exists profile_banners_delete_own on storage.objects; create policy profile_banners_delete_own on storage.objects for delete to authenticated using ( bucket_id = 'profile-banners' and (storage.foldername(name))[1] = auth.uid()::text );