Remplace le lien « Mode d'emploi » par « Contribuer » dans la navigation. La page /contribuer présente le fonctionnement de la plateforme, la réputation du contributeur connecté, et un renvoi vers le mode d'emploi et le dépôt source.
Pré-remplissage du formulaire de contribution depuis les pages /s/[slug] et /p/[slug] via searchParams (initialFigure, initialSubject). Le Combobox supporte un initialItem pour afficher la sélection par défaut.
Server actions et use cases pour le CRUD sujets (create, update, delete), page /s/ajouter avec NewSubjectForm. Mise à jour de CONTRIBUTING.md : une personnalité peut changer de position au fil du temps.
Permet aux contributeurs confirmés d'inviter de nouvelles personnes par email. L'invité reçoit un lien, choisit son mot de passe, et son compte est créé avec la moitié de la réputation de l'inviteur. L'inviteur reçoit +50 pts.
Domain : entité Invitation (Effect Schema), use cases inviteUser et acceptInvitation, permissions invite_user, ContributorRepository et InvitationRepository, extraction de DatabaseError dans errors.ts.
Infra : repositories Supabase, migration table invitations avec index unique partiel, RPC get_user_id_by_email, template email personnalisé.
UI : page /inviter avec formulaire, page /accepter-invitation avec choix de mot de passe (token consommé uniquement à la soumission), lien Inviter dans AuthSection, NoticeBanner pour les redirections avec message.
Correctifs issus de la revue de code : rollback de l'invitation si l'envoi d'email échoue, try/catch + Sentry dans inviteUserAction, ignoreDuplicates dans le callback auth pour ne pas écraser la réputation, exclusion de .direnv dans vitest.
- Upload photo via client admin Supabase (service role, bypass RLS) avec redimensionnement sharp (800px max, JPEG q85)
- Gestion d'erreurs propre dans les 5 repositories : helper dbError + Sentry.captureException
- Formulaire : try/catch/finally pour éviter UI bloquée, validation taille photo côté client (30 Mo max)
- Validation date avec date-fns (parseISO/isFuture) au lieu de construction manuelle
- bodySizeLimit 30mb pour les server actions
- Redirections UI vers /nouvelle-prise-de-position + bouton conditionnel sur /s
- Tests contribute-statement use case (21 tests) + findByWikipediaUrl dans les mocks existants
Remplace le <img> brut par le composant Image de Next.js dans FigureAvatar.
Les miniatures de 40px téléchargeaient l'image JPEG originale en pleine
résolution. Désormais : redimensionnement serveur, conversion WebP/AVIF,
lazy loading et srcset automatiques.
Corrige la faille critique RCE (CVSS 10.0) dans React Server Components
qui a permis l'exécution de code arbitraire sur le serveur de production
le 18 février (minage Monero via XMRig).
Formulaire unique /nouvelle-prise-de-position permettant de créer une prise
de position en sélectionnant ou créant à la volée une personnalité, un sujet
et une position. L'upload de la photo se fait AVANT la création des entités
pour éviter un état incohérent, et les erreurs d'upload remontent à Sentry.
Sentry est actif uniquement en production (DSN absent en dev → SDK inerte).
Capture automatique des erreurs Server Components, server actions,
middleware (via onRequestError) et côté client (error boundary global).
Appel à l'API MediaWiki pour valider que la page existe et possède la
catégorie « Wikipédia:Article biographique ». Interface WikipediaValidator
dans domain/services (port hexagonal), implémentation dans infra/.
Même logique atomique que le wizard position : on crée personnalité →
statement → evidence → réputation en une seule opération. La permission
add_personality requiert le rang Éloquent (1000+ pts).
- Use case create-public-figure-with-statement en TDD (13 tests)
- Server actions utilitaires (search-subjects, get-positions-for-subject)
- Wizard 2 étapes (personnalité + première prise de position)
- Page /p/ajouter avec auth check Éloquent
- Bouton conditionnel sur /p via le composant Button du design system
- Ajout de size="small" au composant Button
- Ajout de onSelect au Combobox pour le chargement dynamique
- Ajout de typecheck (tsc --noEmit) au script npm check
- Correction des fakes incomplets dans les tests existants
Ajoute un parcours en 2 étapes pour créer une position et son premier
statement atomiquement : étape 1 (titre + description), étape 2
(personnalité + preuve sourcée). La soumission crée position, statement,
evidence et accorde 100 pts de réputation (2×50).
Ajoute get-authenticated-contributor, reputation-repository et son
implémentation Supabase qui n'avaient pas été commités. Corrige aussi
le renommage createServerSupabaseClient → createSSRSupabaseClient dans
toutes les pages. Ajoute le script npm run check (lint+format+build).
- Use case create-statement avec validation par champ (TDD, 8 tests)
- Server actions : création de statement et recherche de personnalités
- Page /s/[slug]/ajouter avec formulaire complet
- Combobox avec downshift pour la recherche async de personnalités
- PositionRepository (interface + implémentation Supabase)
- createEvidence et searchByName ajoutés aux repos existants
- Bouton conditionnel sur la page détail sujet (visible si connecté·e)
- Erreurs de validation affichées sous chaque champ concerné
- Conservation du state du formulaire en cas d'erreur
- sitemap.ts dynamique avec pages statiques + sujets et personnalités depuis la DB
- robots.ts bloquant 22 crawlers IA (GPTBot, ClaudeBot, Google-Extended, etc.) tout en autorisant l'indexation par les moteurs de recherche
- TDMRep (W3C) : fichier .well-known/tdmrep.json + meta tags dans le layout pour réserver les droits de text/data mining (Directive européenne DSM)
- Mise à jour react et react-dom de 18.2 vers 19.2
- Mise à jour @types/react et @types/react-dom vers v19
- Suppression de styled-components (vestige inutilisé, 100% CSS Modules)
- Suppression du StyledComponentsRegistry et de l'option compiler.styledComponents
- Débloque useActionState et les form actions natives de React 19
Remplace les N+1 requêtes (1 + 4×N) par une seule requête sur une vue
PostgreSQL qui agrège sujets, stats et figures. Les sujets sont triés
par date de dernière prise de position (taken_at) décroissante.
5 rangs (Sophiste, Métèque, Éloquent, Idéaliste, Fondateur), matrice
complète des 19 actions, barème de points pour 28 actions. Le Contributor
délègue maintenant au système de permissions via contributorCanPerform.
Hook useCurrentUser pour l'affichage conditionnel côté client.
6 templates versionnés dans supabase/templates/ et référencés dans config.toml :
confirmation, réinitialisation mot de passe, changement d'email, invitation,
magic link, réauthentification.
Le callback transmet maintenant le détail de l'erreur (message Supabase)
dans le query param auth_error. Un composant AuthErrorBanner dans le layout
lit ce param et affiche un bandeau rouge fermable en haut de toutes les pages.
Le titre « LES PERSONNALITÉS RÉCENTES » n'avait pas de sens pour l'utilisateur. Remplacé par « LES PERSONNALITÉS » avec un tri par nombre de sujets décroissant.
Mise en place de metadataBase, title.template, openGraph et twitter dans le layout racine. Ajout de descriptions et meta OG spécifiques sur les pages dynamiques (sujets, personnalités).
Les pages /s, /p, /s/[slug] et /p/[slug] utilisaient le titre générique du layout. Chaque page a maintenant un titre spécifique via metadata ou generateMetadata.
Toutes les pages (accueil, sujets, personnalités, détails) utilisent maintenant
createServerSupabaseClient() au lieu du client statique SSG. Cela permet aux mises
à jour de contenu d'être visibles immédiatement sans rebuild.
Le seed.sql est réduit au minimum (auth.users de test uniquement), tout le contenu
étant désormais géré par le script d'import idempotent (npm run import:content).
Ajout du script import:content:production pour cibler la base de production.