wall_notes_today() devient wall_notes_for_date(p_date default null) — même garantie d'anonymat qu'avant, juste paramétrée par jour plutôt que figée sur aujourd'hui. Nouvelle RPC wall_note_days() (dates ayant au moins une note, sans contenu ni auteur) peuple un sélecteur de jour au-dessus de la grille, visible par tous — pas seulement les Archontes via l'historique complet, qui lui révèle l'auteur. wall_note_reaction_counts() gagne le même paramètre p_date. Le compteur "X/12 aujourd'hui" et l'éligibilité à publier restent toujours basés sur aujourd'hui, peu importe le jour consulté.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
L'Agora sert déjà de page d'accueil de fait (/ y redirige) mais n'offrait aucun accès direct aux autres pages sans passer par le menu déroulant du chip. Ajoute une rangée de raccourcis (Icare, Corne d'Abondance, Char, Mur de la Honte, Urne, Crieur) juste au-dessus du classement, responsive (3 colonnes mobile, 6 en ligne sur écran plus large), mêmes icônes que le menu du header pour rester cohérent.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
post_wall_note() n'a plus de vérification de rôle : un Archonte peut désormais publier une note anonyme comme n'importe quel Citoyen. La policy Storage d'upload sur wall-images perd aussi son filtre par rôle (sinon possible de poster une note mais pas d'y joindre une image). Limite quotidienne relevée de 10 à 12 notes pour couvrir tout le groupe plutôt que les seuls Citoyens.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
duration_ms/actions/merges restaient entièrement déclaratifs (calculés et envoyés par le client en une fois à la fin), donc falsifiables par un appel RPC direct. Le client envoie maintenant un ping toutes les 5s pendant la partie (ping_game_run), horodaté par le serveur, jamais par le client. submit_icarus_score/submit_melon_score corrèlent le nombre de pings et leur écart réel avec la durée annoncée (parties ≥ 15s uniquement) et signalent toute incohérence dans game_cheat_flags (missing_pings, ping_span_mismatch) — toujours en signalement silencieux, jamais de blocage, comme pour le reste de l'anti-triche.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
submit_icarus_score/submit_melon_score (appliquées directement en base, jamais commitées) sont récupérées mot pour mot via pg_get_functiondef : signalement dans game_cheat_flags plutôt que rejet serveur, le score reste toujours accepté. L'ancienne couche par rejet strict (icarus_runs/start_icarus_run) devenue orpheline est explicitement supprimée plutôt que laissée à traîner. CLAUDE.md documente le nouveau mécanisme (V12) et n'a plus aucune mention de l'ancien.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5000 restait trop haut pour être un vrai plafond réaliste : Icare abaissé à 500 (calculé sur le rythme le plus rapide théoriquement atteignable dans le jeu), Corne à 2000 (estimation plus prudente, économie de score plus dure à borner). Ajoute icarus_runs/start_icarus_run() : le serveur enregistre l'instant réel de début de partie et rejette un score incohérent avec le temps écoulé, sans jamais faire confiance à une durée envoyée par le client. Corrige aussi le nombre de jetons de /urne, peu lisible en gold-bright sur fond marbre (passe à text-sea, même convention qu'Icare/Corne).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Un score falsifié envoyé directement à submit_icarus_score/submit_melon_score pouvait se convertir en vraies gloires au Tribunal (plafond abaissé de 1 000 000 à 5000, contrainte + RPC). Les fonctions cron-only award_*_points_if_due() n'étaient protégées que par un commentaire, pas un vrai REVOKE. Le bucket avatars n'avait aucune limite de taille/type. La banque complète des questions du Char (spoiler du jeu) était lisible par tout Citoyen via /char ou un appel direct — RLS restreinte aux juges, /char passe désormais par la RPC chariot_revealed_question().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
La bordure était posée directement sur le conteneur aux coordonnées
physiques (300x420) : à cause du box-sizing, la bordure mangeait sur
l'espace intérieur réel (292x416) sans que matter-js le sache, donc les
pièces pouvaient visuellement dépasser le cadre. La bordure vit
maintenant sur un conteneur externe non dimensionné, qui s'ajuste
automatiquement autour du conteneur physique sans réduire sa zone utile.
Ajoute aussi l'échelle de repère (ordre de fusion, taille proportionnelle
au rayon) et le second aperçu de la pièce suivante, travaillés en même
temps.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Petit badge "Puis" à côté du score, taille d'affichage fixe (juste
informatif, pas de position à viser) — la file glisse d'un cran à chaque
lâcher : ce qui était annoncé en second devient la pièce à viser.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TIER_OVERRIDES (id de profil → index de palier) + applyTierOverrides()
placent d'abord les Citoyens fixés à la main, puis remplissent le reste
dans l'ordre alphabétique existant. Épicure est placé en position 7.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nouveau mini-jeu à /corne : des avatars de Citoyens tombent dans un bac
(physique matter-js), deux avatars de même taille qui se touchent
fusionnent en un plus gros, jusqu'au débordement soutenu (5s de grâce,
pièces clignotantes pour prévenir) qui met fin à la partie. Même
mécanique de gloires que Le Vol d'Icare (record personnel, classement,
gel + attribution automatique au Tribunal via pg_cron).
Un palier de taille par Citoyen (pas les Archontes) plutôt qu'un nombre
arbitraire : citizens[tier] donne l'association palier → Citoyen, fixe
pour tout le monde (les Citoyens sont triés par pseudo côté serveur, un
ordre déterministe). Rendu en DOM pour réutiliser le composant Avatar
existant (étendu pour accepter une taille en pixels arbitraire) plutôt
que de redessiner des images sur canvas — position et rotation de chaque
pièce appliquées en impératif depuis la boucle physique, jamais via
setState.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
La fenêtre de 3-8 colonnes du bouclier est maintenant une vraie distance :
chaque colonne rencontrée décompte, qu'elle soit touchée (cassée au lieu
de tuer) ou franchie sans contact (non cassée) — avant, seules les
colonnes touchées consommaient le bouclier, qui pouvait donc durer bien
plus longtemps que prévu.
Ajoute aussi des filets de vitesse continus autour d'Icare pendant toute
la durée du bouclier (pas seulement au bond initial de cueillette), pour
que la sensation d'accélération reste lisible même si Icare est figé.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le nombre de charges (colonnes cassables) est désormais tiré entre 3 et 8
à chaque cueillette, au lieu d'un nombre fixe. Pendant que le bouclier est
actif, Icare est immobile (gravité coupée, taps/barre d'espace sans
effet) et le défilement accéléré (×1,7) : impossible d'agir sur la
trajectoire jusqu'à épuisement des charges, où le contrôle reprend.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rare et exceptionnel (intervalle large de 15-25 colonnes, pas de plafond
par partie) : ramasser l'éclair donne un bouclier de 5 charges — toucher
une colonne (mortel normalement) la casse au contact et consomme une
charge, une par une, plutôt que de détruire un nombre fixe de colonnes
d'un coup à la cueillette. Cueillette animée d'un bond en avant d'Icare
avec traînée de vitesse, halo pulsant sur l'éclair, éclat de particules
sur chaque colonne cassée et liseré doré tant que le bouclier est actif.
Ajoute aussi le support clavier (barre d'espace = tap) pour jouer au
clavier sur ordinateur.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Chaque note peut désormais porter une image facultative : compressée et
redimensionnée côté client (resizeImageToBlob, sans forcer un carré comme
pour les avatars) avant l'upload, avec une limite dure côté bucket
Supabase (3 Mo, webp/jpeg/png uniquement) en filet de sécurité. Le chemin
de stockage ne contient jamais le user_id, contrairement aux avatars,
pour ne pas faire fuiter l'auteur via l'URL publique de l'image.
Ajoute aussi des réactions emoji (👍😂😱❤️🔥) sur chaque note, avec le
même principe d'anonymat que le reste du Mur : le total par emoji est
public (wall_note_reaction_counts), mais personne ne voit qui a réagi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Un Citoyen peut désormais laisser un motif facultatif en déposant son
jeton (toujours deux étapes avant l'envoi). Le classement permet de
consulter les justifications reçues par une personne via une nouvelle RPC
urn_vote_reasons() — même principe que wall_notes_today : le contenu est
public, l'auteur ne l'est jamais, ce qui préserve la garantie de L'Urne
que personne (Archontes compris) ne voit qui a voté pour qui.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.env.docker.example suit le nouveau domaine. README/CLAUDE.md décrivaient
encore un déploiement Vercel jamais réellement utilisé : corrigés pour
refléter le vrai pipeline self-hosted (Docker Compose + Traefik + CI Gitea
Actions via webhook).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le pseudo temporaire fixe "Nouveau membre" entrait en collision (contrainte
unique) dès qu'une 2e personne était invitée avant que la 1re ait fini son
inscription ; il inclut maintenant un suffixe d'uuid. Le token d'invitation
pouvait aussi s'établir sur n'importe quelle page (pas seulement /signup),
laissant certains comptes connectés sans jamais voir le formulaire de mot
de passe — /signup affiche désormais un état de chargement au lieu d'un
écran vide, et le proxy renvoie systématiquement vers /signup tant que le
compte n'est pas finalisé.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/calendrier disparaît de la navigation (route toujours fonctionnelle
pour les Archontes qui y accèdent directement) : la date du Tribunal,
seule info largement utile au quotidien, est reprise en en-tête de
/leaderboard. Extrait la logique de décompte dans un helper partagé
src/lib/tribunal-date.ts plutôt que de la dupliquer.
Corrige au passage un espace JSX manquant sur /urne oublié lors du
dernier commit ("Tu as voté pour Xaujourd'hui").
Nouvelle page /urne : vote quotidien inspiré du vote à l'urne de
l'Athènes antique. Chaque Citoyen dépose un jeton par jour sur une
autre personne (jamais lui-même), avec confirmation à deux temps
avant l'envoi — le vote est définitif pour la journée, aucune RPC de
modification. Les jetons s'accumulent sur toute la semaine dans un
classement public et cumulatif, identique pour tout le monde y
compris les Archontes : contraste volontaire avec Le Mur de la Honte,
ici personne (Archontes compris) ne voit qui a voté pour qui, seul le
total par personne est public.
Nouvelle table urn_votes (append-only, comme points_log) + deux RPC :
urn_vote_counts() agrège les votes sans jamais exposer une ligne
individuelle, cast_urn_vote() applique les règles (pas de vote pour
un juge ni pour soi-même, un vote par jour). Les Archontes ne votent
pas et ne peuvent pas recevoir de jetons.
Nouvelle page /mur : chaque Citoyen peut publier une note anonyme par
jour (dix places max sur le mur, remis à zéro chaque jour — filtrage
par date, jamais de suppression). L'anonymat n'est qu'à moitié réel :
les Archontes voient une section "Historique complet" (filtrable par
jour) avec l'auteur de chaque note, cohérent avec le thème du site où
les Archontes ont un ascendant sur les Citoyens.
Nouvelle table wall_notes + deux RPC : wall_notes_today() ne renvoie
jamais l'auteur (seul moyen de garantir l'anonymat côté serveur, la
RLS ne pouvant pas masquer une colonne pour certaines lignes) et
post_wall_note() applique les règles (un juge ne publie pas, une note
par jour, mur plafonné à 10). Pas de gel lié à la date du Tribunal :
contrairement au Char, c'est une mécanique de toute la semaine.
Nouvelle table chariot_submission_history (append-only, comme
points_log) : chariot_submissions ne garde que la valeur actuelle
(upsert), donc sans ce journal les Archontes ne voyaient jamais les
versions précédentes d'une question modifiée plusieurs fois.
submit_chariot_question() y écrit désormais à chaque changement réel.
Sur /char/questions, chaque suggestion affiche un lien "Historique (N)"
(visible seulement si la personne a déjà modifié sa proposition) qui
déplie les versions précédentes avec leur date.
Chaque Citoyen peut proposer une question pour Le Char depuis /profile
(upsert via submit_chariot_question, figée dès la date du Tribunal
comme les scores d'Icare). Les Archontes modèrent ces suggestions
directement sur /char/questions (ajouter à la banque ou rejeter).
/admin affiche maintenant l'email de chaque membre via une nouvelle
RPC admin_list_members(), seule façon d'exposer auth.users.email sans
passer par la service_role key côté client.
Corrige au passage deux bugs découverts pendant les tests : la
policy interne de admin_list_members() référençait id/role sans les
qualifier, ambigus avec les colonnes du RETURNS TABLE (erreur
Postgres 42702) ; et l'auteur d'une suggestion s'affichait toujours
comme "un Citoyen" car le embed profiles(...) avait été mal retypé en
tableau alors qu'il est retourné en objet à l'exécution.
Déplace La Roulette de sa page dédiée vers une section de /char (tout
l'outillage de la soirée du Tribunal au même endroit) et retire la
route /roulette. Corrige un bug de superposition où le pointeur doré
de la roulette passait devant le menu déroulant du header (isolation
de contexte d'empilement manquante). Renomme "Le Conseil des
Archontes" en "Admin" avec une police monospace, rupture volontaire
avec le thème grec pour cette page technique.
Page /char (16:9, projetée) pour piloter les deux jeux physiques du
Tribunal : Le Char (2 colonnes de 3 emplacements côte à côte avec un
VS et une illustration de char vu du dessus, sélection en un clic,
duels, compteur et classement des passages) et Le Gardien du Silence
(tirage aléatoire parmi les Citoyens, minuteur avec reroll auto et
manuel). Banque de questions gérée séparément sur /char/questions
(pensée pour être pilotée depuis un téléphone pendant que /char est
projetée depuis un ordinateur).
Après retour d'expérience, la course de char (vue du dessus, piste
générée par jour) laisse place à un Flappy Bird grec plus simple et
plus lisible sur téléphone : Icare vole entre des colonnes de temple,
touche l'écran pour battre des ailes, échec net au premier contact
(score remis à zéro).
Record personnel all-time (plus de piste quotidienne ni de fantômes) :
les scores se figent dès que la date du Tribunal est atteinte, puis les
gloires du top 3 sont attribuées automatiquement via une tâche
planifiée pg_cron, comme pour l'ancienne Course du Char.
schema.sql nettoie explicitement l'ancienne Course du Char (tables,
RPC, tâche planifiée) avant de poser le nouveau schéma, puisqu'elle
avait déjà été appliquée en prod.
Premier mini-jeu compétitif du Tribunal (/course) : piste 2D générée
de façon déterministe à partir de la date du jour (identique pour tout
le monde, jamais stockée côté serveur), pilotage au joystick tactile
virtuel, murs + obstacles qui ralentissent temporairement sans jamais
stopper la course, fantômes du top 3 du jour. Chacun rejoue autant
qu'il veut, seul le meilleur temps compte.
Moteur de jeu maison (src/lib/chariot/) : canvas + requestAnimationFrame,
sans dépendance externe, dans la continuité de l'existant (roulette).
Navigation : nouvelle entrée "La Course du Char" (IconChariot), route
protégée par le proxy comme le reste de l'app.
Ferme l'auto-inscription publique : l'app repose désormais sur le
mécanisme d'invitation natif de Supabase (Authentication → Users →
Invite user) plutôt que sur un formulaire /signup ouvert à tous.
- /login : retire le lien « Créer un compte ».
- /signup : entièrement repensée. Ce n'est plus un formulaire d'auto-
inscription (email + mot de passe) mais une page de FINALISATION de
compte invité. Au montage, vérifie s'il existe une session (établie
par le clic sur le lien d'invitation reçu par email) :
* pas de session → message « invitation requise » ;
* session + profil déjà finalisé (pseudo réel, pas le défaut
"Nouveau membre" posé par le trigger handle_new_user) → redirige
directement vers le leaderboard ;
* session + profil à finaliser → formulaire pseudo + mot de passe
+ photo, qui appelle `updateUser({ password })` puis met à jour
`profiles` (au lieu de `signUp()`).
- proxy : /signup retiré de AUTH_PATHS — un compte fraîchement invité a
déjà une session active et doit pouvoir rester sur cette page pour la
finaliser, sans être renvoyé au leaderboard par le redirect prévu pour
les utilisateurs déjà connectés.
- README/CLAUDE.md : documentent la désactivation de "Allow new users
to sign up", la configuration Site URL/Redirect URLs (→ /signup) pour
que le lien d'invitation atterrisse au bon endroit, et le flux
d'invitation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Boutons de validation des points :
- Les icônes ✓/✕ étaient trop grandes (40px) et dupliquées entre le
podium et le reste du classement. Factorisées dans un composant
partagé PointsConfirmControls (32px, icône 16px, olive/oxblood,
aria-label + tooltip), utilisé à l'identique par JudgePointControls
sur le podium ET dans la liste.
Nouvelle page /calendrier — "Le Calendrier des Dieux" :
- Modèle de données : days (date, dieu, domaine), events (titre, type,
heure, lieu, created_by forcé par trigger), settings (ligne unique,
date du Tribunal). RLS : lecture ouverte à tout authentifié, écriture
(insert/update/delete) réservée au rôle judge par policies dédiées —
jamais un simple masquage des boutons côté client.
- 8 préréglages de divinités (Dionysos, Arès, Athéna, Aphrodite, Hermès,
Poséidon, Hadès, Zeus) avec domaine, couleur d'accent et emblème SVG ;
un Archonte peut aussi saisir une divinité libre.
- Bannière avec compte à rebours avant la date du Tribunal, éditable par
les Archontes. Journées en cartes (jour courant mis en évidence,
jours passés estompés, jour du Tribunal en accent oxblood), liste
d'événements avec icône par type (activité/défi/épreuve/tribunal).
Mode édition (ajout/modification/suppression avec confirmation)
réservé aux Archontes. Realtime sur les trois tables.
- Ajouté au menu déroulant du header, route protégée par le proxy.
Rendu des icônes dynamiques (GodEmblem, EventTypeIcon) via branchement
JSX explicite plutôt que variable de composant résolue à l'exécution,
pour respecter react-hooks/static-components.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Remplace le thème générique (tokens navy/gold/ivory re-thématisables par
édition) par une direction artistique fixe et codée en dur : tribunal
égéen de nuit — marbre, or, mer sombre, sceaux de cire.
Fondations (globals.css, layout.tsx) :
- Polices next/font/google : Cinzel (titres, tracking large), Cormorant
Garamond (citations italiques), Manrope (interface).
- Nouveaux tokens couleur : ink/ink-2 (fond mer de nuit), marble/marble-2
(surfaces claires), gold/gold-bright (accents), oxblood (blâmes/erreurs),
olive (honneurs/succès), sea, text-marble/text-mut (texte sur marbre —
jamais de doré en texte courant, contraste insuffisant).
- Classes utilitaires : .marble-surface (texture par dégradés, pas
d'image de bruit), .meander-divider (frise à méandre grecque en SVG
data-URI).
Composants d'ornement (aucune image bitmap) :
- components/laurel-wreath.tsx : couronne de laurier calculée par
trigonométrie (deux arcs symétriques de feuilles), réutilisée en logo,
favicon (icon.svg régénéré avec les mêmes coordonnées) et couronne du
rang 1 du podium.
- components/diamond-divider.tsx : séparateur ◆ avec filets dégradés.
Header global (components/header.tsx, remplace nav-bar.tsx) :
- Logo laurier + "LE TRIBUNAL" à gauche (cliquable vers le leaderboard).
- Chip utilisateur à droite : avatar (bordure dorée), pseudo, badge de
rôle (Archonte/Citoyen), points de gloire, menu déroulant (Mon profil,
Le Conseil des Archontes si juge, Se déconnecter).
- Onglets L'Agora / Le Crieur, frise à méandre en séparateur.
- Responsive : nom du site et pseudo masqués sous le breakpoint sm,
l'avatar reste toujours visible.
Vocabulaire diégétique (toujours avec le terme fonctionnel à côté) :
juges → Archontes, membres → Citoyens, leaderboard → L'Agora, journal →
Le Crieur (décrets avec sceau de cire oxblood), points positifs/négatifs
→ Honneurs/Blâmes, points → gloires, section admin → Le Conseil des
Archontes.
Avatar : bordure dorée, couleur de fallback dérivée d'un hash du pseudo
(au lieu d'une couleur fixe).
Toutes les pages (login, signup, leaderboard/podium, journal, admin,
profil) sont passées sur les nouveaux tokens/polices/vocabulaire.
README.md et CLAUDE.md : section "Ré-thématisation" remplacée par
"Direction artistique" documentant la palette, les polices et les
ornements ; toute mention du système de re-thème par édition retirée.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Design & UX :
- Renomme "Administration" en "Admin" (nav, page, docs).
- Logo original (marteau de juge stylisé navy/or) en favicon (src/app/icon.svg,
remplace le favicon.ico par défaut de create-next-app) et dans la navbar
(components/logo.tsx).
- Navbar : menu hamburger sur mobile (les liens débordaient à partir de
~4 entrées sur petit écran).
- Leaderboard : lignes en deux niveaux sur mobile (infos membre / contrôles
juges) au lieu d'un seul flex-wrap qui devenait illisible.
- Contrôles de points juges (JudgePointControls) : boutons et champ montant
réduits en mode compact pour tenir dans les colonnes du podium sur petit
écran.
- Podium : scroll horizontal de secours (overflow-x-auto) si le contenu
dépasse malgré tout sur très petits écrans.
- Table admin : pseudo/avatar sur une ligne, rôle/statut/actions sur une
autre en mobile (le flex-1 sur l'input pseudo n'avait aucun effet en
layout colonne).
Correctif sécurité/fonctionnel :
- storage.objects n'avait que des policies INSERT et UPDATE pour le bucket
avatars, pas de policy SELECT. Postgres a besoin de lire la ligne
existante pour évaluer la clause USING d'un UPDATE : sans SELECT, tout
remplacement de photo (upsert) échouait avec "new row violates row-level
security policy", même si les policies INSERT/UPDATE étaient correctes.
Ajout d'une policy SELECT publique sur le bucket avatars (cohérent avec
le fait que le bucket est déjà public en lecture).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
V2 — authentification et administration :
- Authentification par email + mot de passe (email confirmé, un compte
par email), abandon de l'email interne dérivé du pseudo.
- Rôles public/judge sur profiles, section Administration (juges
uniquement, vérifiée côté serveur) pour gérer les membres.
- Verrou de pseudo : modifiable une fois par son propriétaire puis figé,
contournable par un juge.
- RLS étendue par un trigger BEFORE UPDATE (enforce_profile_update) pour
verrouiller les colonnes sensibles (role, points, pseudo_locked, pseudo
figé) — la RLS seule ne peut pas exprimer une règle par colonne.
V3 — points, journal, podium, progression, photo :
- RPC award_points() (SECURITY DEFINER) : seul point d'écriture de la
colonne points, vérifie le rôle juge côté serveur, delta signé sans
plancher à 0, trace chaque opération dans points_log.
- Leaderboard temps réel (Supabase Realtime) avec podium top 3
(égalités gérées), flèches de progression (previous_rank), et
contrôles de points juges avec confirmation explicite (plus de
debounce auto) avant envoi.
- Page /journal ("le crieur") : fil live et public des attributions de
points.
- Recadrage photo carré + compression client (react-easy-crop + canvas)
au signup et sur le profil.
- Passe de polish visuel : cartes/boutons cohérents, lien actif dans la
nav, podium retravaillé.
schema.sql, README.md et CLAUDE.md mis à jour en conséquence (schéma
idempotent, instructions SMTP/rôles/migration, conventions RLS+trigger
documentées pour les futures colonnes sensibles).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>