Skip to content

Les coordonnées des bénévoles se voient enfin - #56

Merged
flocom merged 1 commit into
mainfrom
claude/remove-apel-sensitive-data-73l5iu
Sep 19, 2026
Merged

flocom merged 1 commit into
mainfrom
claude/remove-apel-sensitive-data-73l5iu

Conversation

@flocom

@flocom flocom commented Sep 19, 2026

Copy link
Copy Markdown
Owner

La réponse à la question posée

Oui, les numéros sont bien enregistrés. La chaîne d'écriture est intacte de bout en bout : la route publique /api/signup écrit phone, getEventWithDetails le charge, la page le passe au composant, l'export CSV le sort. Une inscription réelle de production porte bien son numéro.

Le problème était entièrement à l'affichage, sous trois couches :

Couche Effet
Un autre onglet (?onglet=benevoles) L'aperçu n'affiche qu'un compteur « N inscriptions » — il prouve que les gens sont là sans dire qui
Un <details> replié « Voir les N personnes inscrites » : rien tant qu'on n'a pas cliqué
text-slate-400 sur bg-slate-50 2,45:1 mesuré, pour un seuil lisible de 4,5:1 — la moitié de ce qu'il faut

Qui cherchait un numéro concluait qu'il n'avait pas été enregistré.

L'incohérence de fond

Les réunions avaient reçu le bon traitement : téléphone affiché d'emblée, cliquable en tel:. Les événements ne l'avaient jamais eu. Mêmes personnes, même besoin — joindre quelqu'un la veille — deux traitements opposés.

Les événements sont maintenant alignés sur les réunions :

  • les inscrits s'affichent directement sous leur créneau, plus de pli ;
  • téléphone et e-mail chacun sur sa ligne, cliquables, à 7,24:1 ;
  • « Aucune coordonnée laissée » quand la personne n'en a pas donné, au lieu du silence ;
  • cibles tactiles portées à 44 px des deux côtés — c'est l'écran qu'on consulte debout, la veille, sur un téléphone.

Au passage, sur les mêmes écrans

  • la barre d'actions d'un créneau était en shrink-0 et débordait de 115 px à 320 px de large ;
  • ses trois boutons, l'état vide des créneaux, « Personne pour l'instant » et « Fiche événement » étaient tous sous le seuil de contraste ;
  • les rouges Tailwind par défaut passent au coral de la maison.

Deux fuites refermées

Trouvées en auditant ces écrans, toutes deux réelles :

list_event_signups renvoyait le cancelToken. L'outil MCP utilisait signups: true, donc toutes les colonnes. Un jeton d'annulation n'est pas une donnée mais un pouvoir : qui le détient peut désinscrire la personne sans être authentifié. L'outil énumère maintenant ses colonnes, comme getEventWithDetails le fait déjà délibérément.

getEventByShareToken chargeait la ligne entière sur une route publique. Seul signups.length est lu, mais la requête ramenait nom, e-mail, téléphone et jeton. Elle ne charge plus que l'identifiant. La règle de confidentialité n'existait qu'en commentaire ; elle est maintenant dans la requête.

Vérifications

Sur une instance réelle, avec quatre inscrits couvrant les quatre cas (les deux coordonnées / téléphone seul / e-mail seul / aucune) :

  • tout est visible sans aucun clic ;
  • contraste passé de 2,45:1 à 7,24:1 ;
  • 3 liens tel: et 3 mailto: fonctionnels ;
  • plus aucun texte sous 4,5:1 sur l'onglet Bénévoles ni sur l'onglet Présences ;
  • plus aucune cible sous 44 px ;
  • aucun débordement de 320 à 1920 px (contre 115 px à 320 px avant) ;
  • npx tsc --noEmit, npx eslint src --max-warnings=0, npm run build : verts.

Hors périmètre, signalé

Trois incohérences réelles trouvées pendant l'audit, non traitées ici parce qu'elles engagent un choix de comportement, pas un correctif d'affichage :

  1. le cron de rappel filtre sur isNotNull(email) — un inscrit qui n'a laissé qu'un téléphone n'est jamais rappelé, alors que le réglage promet de « prévenir les inscrits » ;
  2. « Écrire aux bénévoles » ne joint que les porteurs d'e-mail, sans le dire ;
  3. la page Confidentialité promet « vous désinscrire via le lien reçu par e-mail », alors que le formulaire accepte un téléphone seul — cette personne n'a aucun moyen de se retirer.

🤖 Generated with Claude Code

https://claude.ai/code/session_014SfQYBU4xXTeSEHKhHQXdD


Generated by Claude Code

Les numéros de téléphone étaient bien enregistrés — la route publique
/api/signup les écrit, getEventWithDetails les charge, la page les passe
au composant, et le CSV les exporte. Une inscription réelle de production
porte bien son numéro. Mais à l'écran, ils étaient sous trois couches :

- un autre onglet (?onglet=benevoles), alors que l'aperçu n'affiche qu'un
  compteur « N inscriptions » qui prouve que les gens sont là sans dire
  qui ;
- un <details> replié, « Voir les N personnes inscrites » ;
- une ligne en text-slate-400 sur bg-slate-50, mesurée à 2,45:1 pour un
  seuil lisible de 4,5:1 — la moitié de ce qu'il faut.

Qui cherchait un numéro concluait qu'il n'avait pas été enregistré.

Les réunions, elles, avaient reçu le bon traitement : téléphone affiché
d'emblée, cliquable en tel:. Les événements sont désormais alignés
dessus, et le pli est supprimé :

- les inscrits s'affichent directement sous leur créneau ;
- téléphone et e-mail sur leur propre ligne, cliquables, à 7,24:1 ;
- « Aucune coordonnée laissée » quand la personne n'en a pas donné, au
  lieu du silence ;
- cibles tactiles portées à 44 px, des deux côtés — c'est l'écran qu'on
  consulte debout, la veille, pour joindre quelqu'un.

Au passage, sur les mêmes écrans : la barre d'actions d'un créneau était
en shrink-0 et débordait de 115 px à 320 px de large ; ses trois boutons,
l'état vide des créneaux, « Personne pour l'instant » et « Fiche
événement » étaient tous sous le seuil de contraste ; et les rouges
Tailwind par défaut passent au coral de la maison.

Deux fuites refermées, trouvées en auditant ces écrans :

- list_event_signups renvoyait `signups: true`, donc le cancelToken. Ce
  n'est pas une donnée mais un pouvoir : qui le détient peut désinscrire
  la personne sans être authentifié. L'outil énumère maintenant ses
  colonnes, comme le fait déjà getEventWithDetails.
- getEventByShareToken, qui alimente une page PUBLIQUE, chargeait la
  ligne d'inscription entière alors que seul son nombre est lu. Elle ne
  charge plus que l'identifiant : la règle de confidentialité n'était
  écrite qu'en commentaire, elle est maintenant dans la requête.

Vérifié sur une instance réelle, sur quatre inscrits couvrant les quatre
cas (les deux coordonnées, téléphone seul, e-mail seul, aucune) : tout
est visible sans aucun clic, plus aucun texte sous 4,5:1 sur les deux
onglets, plus aucune cible sous 44 px, et aucun débordement de 320 à
1920 px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SfQYBU4xXTeSEHKhHQXdD
@flocom
flocom merged commit ea56adb into main Sep 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants