Scaffold V1: auth, profils et leaderboard
Next.js 16 + Tailwind + Supabase (Auth, Postgres, Storage). Connexion par pseudo/mot de passe via email interne dérivé, RLS avec points protégés au niveau colonne, pages login/signup/leaderboard/profile. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
-- 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}.<ext>`.
|
||||
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
|
||||
);
|
||||
Reference in New Issue
Block a user