-- Migration : bucket Storage `event-photos` (privé) et policies RLS -- Réf. : docs/modele-donnees.md, docs/cahier-des-charges.md (section -- "Storage bucket"), CLAUDE.md ("lecture des photos jamais publique"). -- -- Logique inchangée par rapport à la version du 2026-09-15 (le passage au -- schéma `photobooth` ne concerne que Postgres/PostgREST : les policies -- storage.objects et la config du bucket sont indépendantes de l'exposition -- de schéma, cf. consigne de tâche). Seule différence : la fonction -- public.storage_event_photos_upload_allowed() vit désormais dans le -- fichier 20260916090400_create_public_functions.sql (regroupée avec les -- autres fonctions public.*) au lieu d'être définie ici. -- -- Décision actée (bucket privé) : le bucket `event-photos` est PRIVÉ -- (public = false). Aucune lecture publique/anonyme des fichiers. La -- consultation admin passe exclusivement par des URLs signées générées côté -- Edge Function `admin-gallery` (service_role). -- -- file_size_limit / allowed_mime_types (relecture sécurité 2026-09-15, -- conservés à l'identique) : -- - file_size_limit = 6 291 456 octets (6 Mo) = MAX_OUTPUT_BYTES dans -- src/e/upload.js (garde-fou côté client après compression). -- - allowed_mime_types = uniquement 'image/jpeg' : la pipeline de -- compression (browser-image-compression, fileType: "image/jpeg", y -- compris pour les HEIC convertis au préalable via heic2any) force -- systématiquement une sortie JPEG. ⚠️ À mettre à jour si le front -- change un jour cette pipeline. -- -- Convention de chemin utilisée côté front (src/e/upload.js) : -- {event_id}/{uuid}.{ext} -- ex : 8f3.../a1b2.jpg -- -- ⚠️ Ne pas appliquer depuis cet agent (Kévin applique lui-même). -- --------------------------------------------------------------------------- -- Bucket -- --------------------------------------------------------------------------- insert into storage.buckets (id, name, public, file_size_limit, allowed_mime_types) values ( 'event-photos', 'event-photos', false, 6291456, array['image/jpeg'] ) on conflict (id) do update set public = false, file_size_limit = excluded.file_size_limit, allowed_mime_types = excluded.allowed_mime_types; -- RLS est activé par défaut sur storage.objects sur les projets Supabase -- hébergés. Cette ligne est défensive (idempotente) pour les environnements -- où ce ne serait pas déjà le cas (ex. stack Supabase locale/self-managed). alter table storage.objects enable row level security; -- --------------------------------------------------------------------------- -- Policies storage.objects -- --------------------------------------------------------------------------- -- INSERT anonyme autorisé uniquement dans le bucket event-photos, et -- uniquement si l'event_id déduit du chemin est actif et non expiré -- (public.storage_event_photos_upload_allowed, définie dans -- 20260916090400_create_public_functions.sql). create policy "anon_insert_event_photos_if_event_active" on storage.objects for insert to anon with check ( bucket_id = 'event-photos' and public.storage_event_photos_upload_allowed(name) ); -- Aucune policy SELECT anon/authenticated sur ce bucket : lecture jamais -- publique. La consultation admin passe exclusivement par des URLs signées -- générées par l'Edge Function service_role `admin-gallery`, cf. -- supabase/functions/admin-gallery/index.ts. -- Aucune policy UPDATE : un invité ne modifie jamais un fichier déjà déposé. -- Aucune policy DELETE publique : la suppression des fichiers (job -- d'expiration J+7) passe par l'Edge Function service_role `expire-events`, -- hors RLS — cf. supabase/functions/expire-events/index.ts et -- 20260916090600_expire_events_job.sql.