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:
Valentin ROBIN
2026-07-11 14:52:18 +02:00
parent b216d59b94
commit 87cd286e5a
31 changed files with 8022 additions and 19 deletions
+76
View File
@@ -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
);