Aller au contenu
Candidater

Journal des modifications

Les évolutions de Cohez.io, de la plus récente à la plus ancienne.

51 versions correspondent à « adhérent ».

Versions 1 à 10 sur 51

0.25.16.0 — 2026-10-06

Ajouts

  • Fiche de traitement /dpa (#357, 2026-10-06). Le DPA signé par les associations (article 2.3) renvoie à une fiche consultable en ligne. Elle existe désormais, en version 2026-10. Elle décrit les fonctionnalités et les données traitées par chacune, les fonctionnalités optionnelles (vérification santé, enregistrement audio, identification des adhérents connus) et les garanties de l'assistance par IA. Elle liste aussi les sous-traitants ultérieurs (Clever Cloud, OVHcloud, Brevo, Laravel Nightwatch, Mistral AI), les mesures de sécurité et l'historique des versions. Elle annonce la phase de test (beta) et signale la gouvernance comme en cours de développement. La page est en noindex, hors sitemap, avec un lien dans le pied de page.
  • Contrat et facturation des associations abonnées dans /confidentialite (#357, 2026-10-06). Cette nouvelle section décrit le traitement dont l'éditeur est responsable : données du représentant, de l'association, du contrat signé et des factures, bases légales (6.1.b, 6.1.c), durées de conservation (contrat + 5 ans, pièces comptables 10 ans). Les destinataires sont Subnoto (signature électronique), Qonto (banque, factures, comptabilité) et l'administration fiscale. La facturation se fait par virement, sans prestataire de paiement en ligne.
  • Journal des modifications public /changelog (#357, 2026-10-06). La vitrine publie ce fichier, dix versions par page, avec une recherche plein texte qui ignore casse et accents (les pages de résultats sont en noindex) : suggestions de recherche, bouton d'effacement, mots trouvés surlignés, pagination numérotée. Les intitulés de section sont traduits (Ajouts, Modifications, Corrections…). Lien « Journal des modifications » dans le pied de page ; page indexable et au sitemap, 404 sur les sous-domaines de tenant et d'administration. Dans le back-office des associations, la version en cours s'affiche à gauche du bouton « Aide » et ouvre le journal dans un nouvel onglet. Les quatre mentions de l'ancien nom du produit sont réécrites dans le fichier.

Modifications

  • Conditions générales reprises du contrat d'abonnement (#357, 2026-10-06). /conditions-generales suit désormais la numérotation du contrat signé par les Partenaires Fondateurs (articles 1 à 18, et 3 bis). La phase de test vient en premier, et le contrat signé prévaut en cas de différence. Trois clauses contredisaient le contrat et sont corrigées :

    • la reconduction suit le rappel de l'article L.215-1 du Code de la consommation, au lieu d'un préavis de 30 jours ;
    • les remboursements au prorata et le droit de rétractation de 14 jours sont rétablis ;
    • la responsabilité est plafonnée à 500 € (5 000 € pour les données), sans exclure les pannes de l'hébergeur.

    Seul le tarif Partenaire Fondateur y figure.

  • « Partenaire Fondateur » remplace « association pilote » (#357, 2026-10-06). Le site reprend le nom du contrat, sur l'accueil, /tarifs, /merci et les pages légales, ainsi que dans le mail de candidature. La période se nomme « phase de test ». Le bouton de la barre de navigation devient « Candidater ». L'objectif Matomo « Candidature pilote » et la clé vitrine.pilot_seats_total ne changent pas.

  • Polices auto-hébergées (#357, 2026-10-06). Fraunces, Geist et Geist Mono sont servies depuis les assets de l'application (@fontsource, sous-ensemble latin) au lieu de Bunny Fonts. Aucun service de polices tiers ne reste dans la CSP ni dans le cache PWA.

  • Bandeaux « document de travail » et « non opposable » retirés des pages légales (#357, 2026-10-06). Les pages restent en noindex jusqu'à leur relecture juridique.

Corrections

  • Mentions légales d'une entreprise individuelle (#357, 2026-10-06). « Adresse » remplace « Siège social », et le téléphone de l'éditeur est affiché (LCEN). Il se règle avec la variable VITRINE_LEGAL_PHONE, à définir sur Clever Cloud ; vide, la ligne n'apparaît pas.

0.25.12.0 — 2026-09-29

Ajouts

  • Aide en ligne : rubrique Adhérents complétée (#334, 2026-09-29). Deux guides pour les dirigeants : « Fiche et statuts » (retrouver un adhérent, lire sa fiche, le badge d'adhésion comme seul repère fiable, le champ Statut figé à la création, désactiver sans rien effacer) et « Doublons : que faire » (d'où viennent les doublons, garder la fiche la plus ancienne, désactiver l'autre, pas d'outil de fusion). Les guides décrivent le comportement actuel, limites comprises : une fiche désactivée compte encore pour l'identification (« Déjà adhérent ? » reste muet face à deux fiches identiques) et pour l'e-mail d'un salarié, et la date de création d'une fiche n'est affichée nulle part. Chemins figés par des tests ; captures dans une PR suivante.

Corrections

  • Aide « Identification des adhérents » : une fiche non reconnue affiche « Non adhérent » et non « en attente », et la fiche en double se désactive au lieu d'être supprimée, ce qu'aucun écran ne permet.

0.25.8.0 — 2026-09-28

Ajouts

  • Aide en ligne publique sur cohez.io/aide (#329, 2026-09-28). Pages d'aide écrites en Markdown dans resources/help/ (front matter : titre, description, ordre, date de mise à jour), rendues dans le gabarit du site vitrine avec navigation par rubrique, fil d'Ariane et ancres sur les titres. Pages indexables, listées dans le sitemap avec leur date de mise à jour ; fermées sur les sous-domaines des associations et de l'admin. Première page : « Identification des adhérents sur le formulaire » (rubrique Adhérents). Des tests bloquent une page au front matter invalide, un lien ou une ancre cassés, une image sans texte alternatif.

0.25.6.1 — 2026-09-28

Corrections

  • Dédoublonnage des personnes sans e-mail par identité civile (#324, 2026-09-28). Une inscription publique ou une ligne d'import sans e-mail, mais avec nom et date de naissance, rattache désormais l'adhérent à la fiche existante de même prénom, nom et date (casse et espaces ignorés) au lieu de créer un doublon ; la fiche portant déjà un Member est préférée, son e-mail n'est jamais modifié. Sans nom ou sans date, une nouvelle fiche est créée comme avant ; la date doit être identique (une fiche sans date n'est pas rattachée). Le garde-fou d'adhésion active et le préflight d'import suivent la même règle : une ligne sans e-mail rattachable n'est plus bloquante (« réutilisée ») ; sans nom ou sans date, elle reste bloquante. Les doublons déjà en base ne sont ni fusionnés ni corrigés.
  • Repli civil borné : consentements jamais appliqués, contact principal jamais rétrogradé (#324, 2026-09-28). Sur ce repli civil sans e-mail, la mise à jour d'une fiche retrouvée n'applique plus l'opt-in des consentements RGPD (import et funnel public) ; dans le funnel public, le contact principal (LegalGuardian) déjà déclaré pour un mineur n'est plus rétrogradé par une soumission qui le retrouve sans e-mail — un nouveau responsable ne devient principal que si le mineur n'en a encore aucun. Le chemin e-mail garde son comportement actuel (opt-in des consentements, rétrogradation de l'ancien contact principal).

0.25.5.3 — 2026-09-27

Corrections

  • Dédoublonnage des personnes : une date de naissance absente d'un côté ne crée plus de doublon (#321, 2026-09-27). À e-mail et prénom égaux (casse et espaces ignorés), PersonIdentityMatcher::whereDedupKey() traite une date de naissance absente — sur la fiche ou dans la saisie — comme compatible : le funnel d'inscription publique et l'import HelloAsso retrouvent une fiche créée sans date (back-office, import) au lieu d'en créer une seconde, et complètent sa date sans jamais écraser une date existante. Deux dates renseignées et distinctes restent deux personnes (fratries, jumeaux). Une fiche sans date qui n'est que payeur ou responsable légal (sans adhésion) n'est pas rapprochée d'une saisie datée, pour ne pas rattacher un enfant homonyme à la fiche de son parent. Quand plusieurs fiches correspondent, celle qui porte déjà un Member est retenue, puis celle dont la date est exactement celle saisie (preferringMemberThenExactBirthdate()). Un nouveau Member créé sur une fiche datée retrouvée sans date saisie tire son statut mineur de la date de la fiche. Le contrôle de doublon d'inscription, le garde-fou d'adhésion active et le préflight d'import (« Réutilisée » au lieu de « Ambiguë », message dédié pour la fiche payeur / responsable légal) suivent la même règle. L'import résout les adhérents d'un panier avant son payeur et ses représentants : un adhérent qui paie pour lui-même retrouve sa fiche sans date au lieu d'en créer une seconde ; le préflight bloque une fiche sans date ni adhésion dont l'identité est payeur ou représentant d'une autre commande du fichier (issue dépendante de l'ordre des commandes), et son message d'ambiguïté cite de préférence la fiche datée. Le garde-fou d'adhésion active et le contrôle « déjà inscrit » ignorent une fiche sans date quand une fiche à la date saisie porte déjà une adhésion : une fille datée n'est plus bloquée par l'inscription de sa mère homonyme sans date sur l'e-mail familial. Les doublons déjà en base ne sont ni fusionnés ni corrigés.

0.25.5.2 — 2026-09-26

Corrections

  • Unicité de l'e-mail adhérent en back-office insensible à la casse et aux espaces stockés (#320, 2026-09-26). EloquentMemberRepository::emailExistsInTenant (et findByEmail) compare désormais LOWER(TRIM(persons.email)) : un e-mail enregistré avec des majuscules ou des espaces (import HelloAsso, données historiques) n'échappe plus au contrôle d'unicité à la création ou à la modification d'un adhérent.

0.25.5.0 — 2026-09-25

Ajouts

  • Les pièces santé sont rangées par saison, et la fiche adhérent affiche un bloc de conformité par saison active (#317, 2026-09-25). Une pièce appartient désormais à une saison : clé (member_id, season_id, document_type), une attestation par (adhérent, saison), avec la campagne d'inscription quand elle est connue (member_documents.campaign_id). SeasonHealthProof est l'oracle unique d'une saison (certificat courant + historique) et GoverningCampaignResolver raisonne par saison. Dans une saison, le certificat au valid_until le plus tardif reste courant ; un dépôt qui expire plus tôt entre en historique, et le remplacement ne supprime jamais de fichier. Le back-office choisit explicitement la saison (et la campagne) au dépôt ; dépôt et retrait sont refusés (404) sur une saison close. Un certificat déjà expiré à la date du dépôt est signalé (CertificateState, statut StaleCertificate). Le tunnel public n'échoue plus sur une seconde attestation pour la même saison.
  • Page « Archives santé » : consultation motivée et journalisée des pièces des saisons closes (#317, 2026-09-25). Nouvelle permission nominative view_archived_health_documents, accordée par utilisateur (case « Archives santé » dans les réglages utilisateur) et jamais attribuée par défaut, même au rôle admin. Ouvrir une pièce archivée exige un motif d'au moins 10 caractères, journalisé dans member_document_accesses (reason, context = archive) avant l'envoi du premier octet ; 403 sans permission, 422 sans motif, 404 hors phase archivée, AdminUser refusé.
  • health:unanchored-documents liste les pièces santé sans saison et permet de les rattacher (--attach) (#317, 2026-09-25). Lecture seule par défaut ; ces pièces ne sont jamais purgées automatiquement.

Modifications

  • La conservation des pièces santé est une durée par saison : fin de saison + N ans (#317, 2026-09-25). tenants.health_retention_years (5 par défaut) et HealthRetention définissent trois phases — active, archivée, supprimée — utilisées partout (fiche, téléchargements, archives, purge). health:purge-documents ne purge plus à l'expiration du certificat (+ 30 jours) : elle supprime fichiers, lignes et attestations des saisons arrivées en fin de conservation, par lots, tenant par tenant. Le fichier est supprimé avant sa ligne : un échec de stockage laisse la ligne en place et la suppression est retentée la nuit suivante. La commande renvoie FAILURE dès qu'un tenant échoue, et la tâche planifiée est protégée contre le chevauchement. ⚠️ Une date de fin de saison erronée dans le passé déclenche une purge prématurée et irréversible.
  • Migration de données (#317, 2026-09-25). Les pièces existantes sont rattachées à leur saison, les doublons par saison résolus par supersession, les index uniques posés par saison. La réponse d'attestation « au moins une positive » (has_positive) est retirée : une réponse positive appelle un certificat.

Notes de déploiement

  • En production, post_build.sh relance PermissionSeeder et RoleSeeder : rien à faire. Sur une base de développement non re-seedée, la nouvelle permission manque et la page des réglages utilisateur renvoie une 500 (PermissionDoesNotExist) : relancer ces deux seeders.

0.25.4.0 — 2026-09-25

Ajouts

  • Identification d'un adhérent déjà connu dans le funnel d'inscription publique (#296, 2026-09-25). Un adhérent qui a déjà un dossier dans l'association peut désormais s'identifier avant de s'inscrire à une nouvelle proposition : il saisit son e-mail, reçoit un code à usage unique, et le funnel pré-remplit son identité, ses représentants légaux et ses acceptations à partir du dossier retrouvé, sans dédoublonner un nouveau Person.

Corrections / Sécurité

  • Durcissement de bout en bout de l'identification adhérent, à l'issue d'une revue de sécurité de la PR #296 (2026-09-25). L'identité rapprochée est désormais liée côté serveur (aucun identifiant de personne fourni par le client n'est fait confiance) et filtrée par tenant (applyIdentifiedMember) ; le rapprochement civil passe par un PersonIdentityMatcher partagé et normalisé (casse, espaces) au lieu de comparaisons dupliquées ; une adhésion active déjà en cours bloque désormais la soumission, avec repli sur l'identité rapprochée quand nécessaire ; l'e-mail d'une personne identifiée n'est ni écrasé ni modifiable côté front tant qu'elle reste identifiée ; un seul contact principal subsiste parmi les responsables légaux, l'ajout d'un nouveau responsable principal rétrogradant l'ancien. Sur le canal d'identification lui-même : le code envoyé est désormais lié au jeton public de la campagne qui l'a émis, réservé atomiquement à chaque tentative (5 maximum), à usage unique une fois vérifié avec succès, vérifié à coût constant (anti-énumération), et un délai minimal de 60 secondes s'impose entre deux envois de code. Un jeton XSRF est relu via un helper partagé (readXsrfToken) plutôt que dupliqué. La déduplication insensible à la casse de PersonDeduplicationService (trouvaille F3, doublons silencieux en base) reste hors périmètre de cette PR et fait l'objet d'un plan séparé.

0.25.3.2 — 2026-09-24

Corrections

  • Un certificat médical valide n'est plus écrasé par un dépôt (#310, 2026-09-24). StoreMemberDocument::persist() archivait le certificat actif et supprimait son fichier sans comparer les dates. Un certificat valide pouvait donc disparaître de trois façons : dépôt d'une pièce plus ancienne, dépôt par un rôle sans accès santé, ou dépôt anonyme via le funnel public quand la dédup rattache un adhérent existant. Désormais, le certificat qui expire le plus tard gagne (valid_until ≥ celui de l'actif) ; sinon, la pièce entre directement en historique et le back-office l'indique par un message dédié. Le remplacement ne supprime plus aucun fichier : health:purge-documents purge à expiration. Seule l'action « Retirer » supprime encore le fichier immédiatement.

0.25.1.0 — 2026-09-16

Ajouts

  • Le sélecteur de coach d'un cours distingue désormais un salarié d'un adhérent, et se cherche au clavier au lieu de se parcourir dans une liste déroulante (#289, 2026-09-16). CoachPicker remplace le <select> par une combobox recherchable, filtrée côté client, qui classe les personnes assignables en trois sections — salarié actif, adhérent, autre — car deux homonymes de statuts différents étaient jusqu'ici impossibles à départager. Une fois la sélection faite, un rappel discret sous le champ garde trace de la catégorie retenue, sans jamais affirmer à tort qu'une personne n'est « ni salariée ni adhérente ». CourseLabelBadge et CourseLabelDot réduisent la couleur libre d'un label de cours à un simple repère visuel plutôt qu'à un porteur de texte : mesurée sur les 13 labels existants, 7 des 8 couleurs distinctes tombaient sous le contraste de lecture minimal en thème clair, 4 sur 8 en thème sombre.
  • Un cours sans proposition (offre / tarif) liée explique désormais où en créer une, au lieu de faire disparaître la carte qui l'affiche (#289, 2026-09-16). La carte des propositions liées disparaissait entièrement quand le cours n'en avait aucune ; elle reste maintenant affichée avec un état vide qui indique le chemin — créer la proposition depuis une campagne, dans une rubrique existante — via un bouton vers la liste des campagnes de la saison, sous la même permission view_settings que la page courante.
  • PRODUCT.md est ajouté au dépôt (#289, 2026-09-16). Contexte produit durable — audiences, raison d'être, positionnement, contraintes d'exploitation, engagements de marque, principes produit — destiné à servir de référence aux travaux de conception à venir.

Corrections

  • La page des salariés sépare enfin les fiches salariés des comptes du back-office qui n'en ont pas, et le compteur de ces derniers reste juste sous recherche et filtre (#289, 2026-09-16). Les deux populations étaient auparavant présentées comme une seule liste, sans dire ce qu'il fallait faire de la seconde ; chacune a désormais sa section nommée et son propre état vide. Le compteur affiché s'appuie sur une requête de base partagée avec la liste, pour ne plus jamais diverger d'elle, et signale le plafond de 500 résultats plutôt que de le taire.
  • La liste des cours d'une saison et le sélecteur de personnes assignables à un cours restent rapides quel que soit l'effectif du tenant (#289, 2026-09-16). La liste passait tous les cours de la saison en une seule requête et calculait les effectifs inscrits sur leur totalité ; elle est désormais paginée à 20 cours, comme la liste des salariés. Le calcul des personnes assignables (jusqu'à environ 700 attendues chez Cholet Water-Polo) n'est plus exécuté à chaque affichage de la page mais seulement à l'ouverture de la modale « Modifier le cours », qui reste utilisable pendant son chargement.
  • La configuration d'un cours ne peut plus renvoyer une page d'erreur blanche pour un dossier salarié incomplet, les formulaires de cours se soumettent désormais à la touche Entrée, le bouton de création ne s'affiche plus à qui n'a pas le droit de créer, et la liste des cours redirige vers la dernière page valide au lieu d'afficher un écran vide après suppression (#289, 2026-09-16). Une personne dont le dossier salarié avait perdu son rattachement (fiche supprimée) faisait planter le calcul des personnes assignables. Les dialogues de cours (création, modification, créneau) purgent désormais leur saisie et leurs erreurs sur toute fermeture — croix, touche Échap ou clic hors de la boîte —, pas seulement sur le bouton « Annuler » ; leur pied de page passe à l'intérieur du <form> avec un bouton type="submit", car il soumettait auparavant par un simple @click hors formulaire, insensible à la touche Entrée. CourseController::index() expose désormais canCreate, comme EmployeeController, pour ne plus afficher un déclencheur qui échouait ensuite en 403. Une page de liste devenue hors bornes après suppression de cours affichait silencieusement « Aucun cours pour cette saison » ; elle redirige maintenant vers la dernière page valide.
  • La hiérarchie des titres de page est rétablie sur l'ensemble de l'application (#289, 2026-09-16). Aucune des pages de l'espace connecté ne portait de véritable titre de niveau 1, et les titres de carte démarraient directement en niveau 3 sans parent (RGAA 9.1 / WCAG 1.3.1, 2.4.6) : un lecteur d'écran ne pouvait pas se repérer dans le plan d'une page par ses titres.
  • L'indicateur de focus clavier redevient visible et suffisamment contrasté sur les champs, boutons et menus — à l'exception connue du sélecteur de code 2FA —, et le mouvement réduit demandé par l'utilisateur est désormais respecté (#289, 2026-09-16) (RGAA 10.7 / WCAG 1.4.11 et 2.4.7). L'ancien anneau semi-transparent tombait sous le seuil de contraste requis et restait invisible en mode contraste élevé de Windows ; il est remplacé par un contour opaque. De nombreux composants neutralisaient cet anneau localement sans le savoir : un simple outline-none prioritaire en CSS suffit à l'annuler, une trappe corrigée composant par composant au fil de cette branche. Le réglage système « préférence pour un mouvement réduit » est maintenant honoré globalement ; l'indicateur de chargement (spinner), qui se figeait après un seul tour sous ce réglage et laissait croire à un plantage, continue de tourner lentement.
  • Les messages de confirmation et d'erreur (« toasts ») sont désormais annoncés aux lecteurs d'écran, et restent affichés le temps de les lire (#289, 2026-09-16) (RGAA 7.5 / WCAG 4.1.3). Le message apparaissait uniquement à l'écran ; il est maintenant porté par une région vocale dédiée. Sa durée d'affichage passe de 4 secondes fixes à 6 (succès) ou 9 (erreur), et se met en pause tant que la souris ou le clavier reste sur le toast.
  • Le lien d'évitement vers le contenu principal est ajouté, et la cible tactile du bouton qui replie la barre latérale est agrandie à 44 px sous mobile (#289, 2026-09-16) (RGAA 12.7). Le lien « Aller au contenu » est le premier élément focusable de la mise en page et amène le focus sur le <main> réel de la page ; il portait lui-même un focus:outline-none local qui annulait l'indicateur de focus global, désormais retiré.
  • Les boîtes de dialogue ne débordent plus de l'écran sans pouvoir défiler, et le contraste des bordures de champ atteint le seuil requis (#289, 2026-09-16). Une boîte plus haute que la fenêtre rendait son bouton de validation inatteignable en paysage téléphone ou à fort zoom (WCAG 1.4.10) ; elle est désormais bornée en hauteur avec défilement interne. La bordure des champs de formulaire, mesurée jusqu'à 1,49:1 sur certains fonds, passe à plus de 3:1 (WCAG 1.4.11).
  • Plusieurs écrans (dialogue de créneau, en-tête et liste des salariés) ne débordent plus horizontalement à 320 px de large (#289, 2026-09-16) (WCAG 1.4.10 Reflow). Le dialogue « Nouveau créneau » imposait deux colonnes fixes qui écrasaient champs et libellés à 320 px ; il adopte désormais le motif déjà en place ailleurs — une colonne par défaut, deux au-delà du point de rupture sm. L'en-tête et les lignes de la liste des salariés recevaient le même traitement incomplet ; les deux sections s'empilent désormais à l'identique en largeur réduite.

Notes techniques

  • L'indicateur de focus de InputOTPSlot (écrans de saisie du code 2FA) reste non conforme, et ne peut pas être corrigé côté application. L'élément réellement focusé est un <input> caché posé par la librairie sous-jacente, dont l'outline est fixé en ligne : hors de portée d'une règle CSS globale ou locale.
  • MeetingReportEditor.vue est volontairement resté hors du retrait des outline-none. Son éditeur est un contenteditable dont la boîte de focus ne coïncide pas avec l'anneau porté par le conteneur : retirer outline-none y aurait ajouté un second anneau visible autour du premier.
  • Deux échecs de contraste préexistants restent hors périmètre : le survol du variant outline du bouton et le texte de substitution (« placeholder ») des champs restent sous 4,5:1 sur certains fonds (WCAG 1.4.3), constatés en corrigeant la bordure des champs mais non traités ici.