Commit graph

34 commits

Author SHA1 Message Date
254ec5bf34 fix: le champ taken_at des statements utilisait la date du jour au lieu de la date saisie par l'utilisateur 2026-03-18 23:06:37 +01:00
56eafe4068 feat: page détail prises de position d'une personnalité sur un sujet (/p/[slug]/s/[subjectSlug]) 2026-03-17 00:38:31 +01:00
b7f381828f feat: permettre le renvoi du lien d'invitation quand le token Supabase a expiré (24h)
Le token OTP Supabase expire après 24h (max autorisé) mais l'invitation applicative reste valide 7 jours. Quand le lien est expiré, l'invité peut maintenant demander un nouveau lien en un clic au lieu d'être bloqué. L'email est inclus dans l'URL d'invitation (urlquery-encodé) pour éviter de le redemander.
2026-03-13 00:33:28 +01:00
af3985f86e refactor: formulaires single-entity (personnalité, position, statement séparés)
Remplace les wizards multi-étapes par des formulaires créant une seule entité chacun.
Supprime les use cases composés (create-public-figure-with-statement, contribute-statement,
create-position-with-statement) et leurs actions/composants associés.
Ajoute FormSuccess, CSS partagé form-with-guide, types partagés domain/use-cases/types.
Ajoute le bouton « Ajouter une position » sur la page sujet.
2026-03-12 00:56:48 +01:00
e852731ae7 fix: afficher les erreurs de validation par champ dans le formulaire de sujet
Le use case createSubjectUseCase retournait un message générique « Données invalides » au lieu de FieldErrors par champ. Alignement sur le pattern des autres use cases (create-public-figure, create-position) avec propagation des erreurs dans l'action et le formulaire.
2026-03-12 00:22:49 +01:00
74d359db72 feat: rendre Wikipedia optionnel avec sources de notoriété alternatives
La création de personnalité accepte désormais soit une URL Wikipedia, soit 2+ sources de notoriété (URLs valides). Le formulaire affiche conditionnellement les champs de sources quand Wikipedia est vide, avec des guides UX sur chaque champ.
2026-03-10 01:15:38 +01:00
7f9efc5ee2 feat: refonte page /p avec vue SQL pré-agrégée, recherche et index A-Z
Remplace le findAll() + getStats() par personnalité (843 requêtes) par une vue SQL v_public_figure_activity_summary (2-3 requêtes). La page affiche maintenant 4 sections : recherche, top 10 actives, activité récente, et index alphabétique. Renomme aussi subject_activity_summary en v_subject_activity_summary pour uniformiser la convention de nommage des vues.
2026-03-10 01:10:44 +01:00
fcfe77117a feat: rendre wikipedia_url optionnel et ajouter notoriety_sources
Le critère de notoriété accepte désormais soit une page Wikipedia, soit deux sources indépendantes (notoriety_sources). Cela permet d'ajouter des personnalités publiques notables qui n'ont pas de page Wikipedia.
2026-03-10 01:10:41 +01:00
3b63a7b98b feat: page profil /me avec dashboard compact
- Identité (nom, email) avec bouton Inviter
- Carte réputation avec score, rang, barre de progression vers le prochain rang
- Lien vers l'historique de réputation
- Le nom dans le header devient un lien vers /me
- Ajout getNextRankThreshold dans permissions
2026-03-08 00:12:30 +01:00
5d4fdcbd14 feat: table reputation_events comme source de vérité pour la réputation
Remplace le pattern addReputation (fetch+update non atomique) par un INSERT dans reputation_events avec trigger PostgreSQL qui maintient le cache contributors.reputation.

- Entité ReputationEvent avec types RewardableAction et RelatedEntityType
- Interface recordEvent + getHistory dans ReputationRepository
- Migration SQL : table, index, trigger, RLS
- Migration des 7 use cases vers recordEvent
- Ajout invitation_bonus dans les récompenses
2026-03-04 23:54:39 +01:00
61dd7ab30e feat: page historique de réputation (/reputation)
Page protégée affichant le score, le rang et la liste chronologique des mouvements de réputation du contributeur connecté. Ajout d'un lien « Réputation » dans le header.
2026-03-04 19:46:08 +01:00
ee13b5c31d feat: afficher la citation et la source au lieu de la description de position sur la page personnalité 2026-03-01 00:15:14 +01:00
080824011d feat: pré-remplissage du formulaire de contribution et CRUD sujets
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.
2026-02-28 00:02:38 +01:00
a283c4c083 feat: système d'invitation par les contributeurs Éloquent (1000+ pts)
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.
2026-02-27 23:56:20 +01:00
b0c46ae393 feat: tri sidebar par date de prise de position, suppression des as any et bloc « dernières ajoutées » 2026-02-27 02:06:08 +01:00
fc13ccad85 feat: formulaire unifié de contribution avec upload admin, gestion d'erreurs Sentry et validation date-fns
- 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
2026-02-24 01:22:56 +01:00
067123ffa5 feat: formulaire unifié « Nouvelle prise de position » avec upload photo atomique
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.
2026-02-18 13:50:46 +01:00
e2d0a20b45 feat: vérifier que la page Wikipedia existe et est une biographie
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/.
2026-02-17 00:16:21 +01:00
5840afa824 feat: refuser une date de preuve dans le futur 2026-02-17 00:14:44 +01:00
7f2aa066c6 feat: wizard « Nouvelle personnalité » avec premier statement obligatoire
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
2026-02-16 23:24:11 +01:00
60cbab6f2e feat: wizard « Nouvelle position » avec premier statement obligatoire
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).
2026-02-13 13:27:51 +01:00
8be2d8f45c chore: reformater les fichiers existants avec Prettier 2026-02-13 13:24:07 +01:00
db13d96add fix: ajouter les fichiers manquants et corriger les imports cassés
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).
2026-02-13 11:25:50 +01:00
d7e83f95b9 feat: ajouter une prise de position sur un sujet existant
- 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
2026-02-13 11:13:57 +01:00
29d1700006 feat: vue SQL subject_activity_summary pour la page d'accueil
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.
2026-02-12 22:40:21 +01:00
bab3c0f011 feat: implémenter le système de réputation avec rangs et permissions
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.
2026-02-12 18:12:21 +01:00
ebf0b38b0b feat: authentification Supabase, entité Contributor, inscription par URL secrète
- Middleware SSR pour rafraîchir les sessions auth
- Route callback /api/auth/callback (échange code PKCE + création contributor)
- LoginModal branché sur signInWithPassword
- SignupModal + page /inscription/[token] protégée par SIGNUP_SECRET_TOKEN
- AuthSection : écoute onAuthStateChange, affiche nom + déconnexion
- Entité domaine Contributor (id, reputation) avec tests TDD
- Migration : rename user_profiles → contributors, suppression colonne name
- Tests colocated avec le code (plus de dossier __tests__/)
- Composant SwitchLink extrait dans components/ui
2026-02-12 01:59:47 +01:00
78fdf7f23e chore: installer et configurer Prettier, formater tout le codebase
Installe prettier, configure .prettierrc (singleQuote, no semi, trailingComma, LF) et .prettierignore. Ajoute les scripts format et format:check. Applique le formatage sur tous les fichiers sources.
2026-02-11 22:10:26 +01:00
3b2f6bfc47 feat: rendre la sidebar "Dernières prises de position" dynamique
Remplace les données en dur par une requête Supabase. Ajoute findLatest(limit) au StatementRepository avec le type LatestStatement. Le composant LastStatements devient un server component async avec Suspense, affiche les avatars et les liens vers les personnalités et sujets.
2026-02-11 18:43:23 +01:00
c611015f17 feat: ajouter les pages détail personnalité et sujet
Crée les pages /p/[slug] et /subjects/[slug] qui étaient des liens morts
depuis les pages index. Ajoute le StatementRepository (domain + infra)
pour les requêtes jointes statements/positions/sujets/personnalités.

Composants partagés extraits : FigureAvatar, ErrorDisplay.
La page personnalité affiche les prises de position groupées par sujet
avec label explicite "Sa position :". La page sujet affiche les positions
avec les avatars des personnalités concernées.
2026-02-10 12:32:40 +01:00
dc02039849 feat(avatars): utiliser Supabase Storage avec convention {slug}.jpg
- Configure le bucket avatars avec seeding automatique dans config.toml
- Ajoute rewrite Next.js /avatars/* vers Supabase Storage
- Supprime pictureUrl des entités (dérivé du slug)
- Corrige les erreurs TypeScript dans subject-repository-supabase
- Migre les repositories vers Effect avec types brandés
2026-02-06 17:33:19 +01:00
85cc220e58 feat(db): enforce required fields for public_figures with auth seeding
- Add migration to make wikipedia_url, picture_url, created_by NOT NULL
  - Update public-figure repository to handle Option types correctly
  - Regenerate database types after schema constraints
2025-07-24 12:10:01 +02:00
cf635430f2 feat(subjects): migrate general layout and Subjects page 2025-07-17 15:29:50 +02:00
7b819d1417 refactor: migrate Ruby domain entities to modern Effect Schema
- Port Subject, PublicFigure, Position, Statement entities from Ruby backend
- Generate Supabase TypeScript types
- Preserve existing business rules (reputation, validation)
2025-07-10 00:18:34 +02:00