-- Le Tribunal — schéma V1 (table profiles + RLS + bucket avatars) -- À exécuter dans l'éditeur SQL du projet Supabase. -- 1. Table profiles ---------------------------------------------------- create table if not exists public.profiles ( id uuid primary key references auth.users (id) on delete cascade, pseudo text not null, slug text not null, avatar_url text, points integer not null default 0, created_at timestamptz not null default now() ); -- Unicité du pseudo affiché (insensible à la casse) et du slug technique. create unique index if not exists profiles_pseudo_lower_key on public.profiles (lower(pseudo)); create unique index if not exists profiles_slug_key on public.profiles (slug); alter table public.profiles enable row level security; -- Lecture : tout utilisateur authentifié peut voir tous les profils (leaderboard). create policy "Profiles are viewable by authenticated users" on public.profiles for select to authenticated using (true); -- Création : un utilisateur ne peut créer que sa propre ligne. create policy "Users can insert their own profile" on public.profiles for insert to authenticated with check (auth.uid() = id); -- Modification : un utilisateur ne peut modifier que sa propre ligne. create policy "Users can update their own profile" on public.profiles for update to authenticated using (auth.uid() = id) with check (auth.uid() = id); -- Aucune policy delete => suppression interdite en V1. -- RLS est au niveau ligne : on verrouille aussi la colonne `points` au niveau -- colonne pour qu'un utilisateur ne puisse jamais la modifier via l'app, -- même en modifiant sa propre ligne (les points seront gérés plus tard côté admin). revoke update on public.profiles from authenticated; grant update (pseudo, slug, avatar_url) on public.profiles to authenticated; -- 2. Bucket avatars ------------------------------------------------------- insert into storage.buckets (id, name, public) values ('avatars', 'avatars', true) on conflict (id) do nothing; -- Bucket public => la lecture se fait via l'URL publique, pas besoin de policy SELECT. -- Upload : un utilisateur ne peut créer que le fichier `{user_id}.`. create policy "Users can upload their own avatar" on storage.objects for insert to authenticated with check ( bucket_id = 'avatars' and split_part(name, '.', 1) = auth.uid()::text ); -- Remplacement de la photo (upsert) : même règle en update. create policy "Users can update their own avatar" on storage.objects for update to authenticated using ( bucket_id = 'avatars' and split_part(name, '.', 1) = auth.uid()::text ) with check ( bucket_id = 'avatars' and split_part(name, '.', 1) = auth.uid()::text );