computeRanksBy(items, comparator) remplace la logique de classement
"ex-aequo partagent le rang" en la rendant générique ; computeRanks
devient un simple appel avec le comparateur points desc, sans rien
changer pour l'appelant existant. Podium accepte maintenant un prop
renderValue (+ valueLabel optionnel) à la place du "points/gloires" en
dur, pour pouvoir afficher un classement par temps (Course du Char)
avec le même composant que le classement par points.
Upload de photo (signup + profil) :
- Remplace le contrôle natif du navigateur par un composant entièrement
en français : input masqué (sr-only) déclenché par un vrai bouton
(icône appareil photo + « Choisir une photo »/« Changer ma photo »),
nom du fichier sélectionné affiché (tronqué) avec une croix pour le
retirer, « Aucune photo sélectionnée » sinon.
Header : plus jamais masqué sur mobile
- "LE TRIBUNAL" et le chip utilisateur (photo + pseudo + points) restent
visibles à toutes les tailles, y compris 320px — tailles de police et
troncature au lieu de `hidden`. Vérifié sans débordement horizontal à
320/375/414/768px.
Navigation : tout dans le menu déroulant
- Retire les onglets du header (ne garde que logo + chip). Le menu
déroulant du chip contient désormais toutes les pages (Le Classement,
La Roulette, Le Crieur, Mon profil, Le Conseil des Archontes si juge)
avec une icône chacune (components/icons.tsx), fermeture au clic
extérieur et à Échap, entrée de la page courante surlignée,
déconnexion séparée en oxblood.
Podium :
- Contrôles de points en icônes ✓/✕ rondes (40×40, olive/oxblood) sous
la carte du membre, aria-label + tooltip — uniquement sur le podium,
le reste du classement garde ses contrôles textuels.
- Refonte visuelle : socles marbre veiné avec arête lumineuse
(.pedestal-marble), chiffres romains gravés (toRoman(), .engraved),
couronne de laurier + halo doré sur le 1er, accents argent/bronze sur
2e/3e, points en gros chiffres dorés, animation d'entrée décalée par
socle (~600ms, respecte prefers-reduced-motion).
Nouvelle page /roulette :
- Tirage aléatoire uniforme calculé avant l'animation (le random ne sert
qu'à choisir, l'animation ne fait que le mettre en scène). Carrousel
horizontal des avatars avec décélération (cubic-bezier long), repère
central doré, révélation finale (couronne + halo + zoom) avec le
pseudo en Cinzel. Filtre Citoyens/tous, bouton Rejouer, dernier élu
affiché, prefers-reduced-motion affiche le résultat directement.
Route protégée par le proxy comme les autres pages.
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>