Aller au contenu
Candidater

Journal des modifications

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

20 versions correspondent à « sécurité ».

Versions 1 à 10 sur 20

0.25.19.0 — 2026-10-07

Ajouts

  • Conditions d’utilisation /conditions-utilisation (#360, 2026-10-06). Ces conditions courtes (version 2026-10, dix articles) s’adressent à toute personne qui utilise Cohez.io : membre du bureau, salarié, bénévole, ou personne qui remplit un formulaire public d’une association. Elles couvrent l’accès, la sécurité du compte, le bon usage, les rôles (l’association est responsable de traitement, l’éditeur sous-traitant), les formulaires publics, la phase de test, la responsabilité, la suspension, les données personnelles et le droit applicable. La page est en noindex, hors sitemap, avec un lien dans le pied de page de la vitrine. Les comptes existants n’ont pas à les accepter de nouveau.
  • Journal d’acceptation des conditions d’utilisation (#360, 2026-10-06). Chaque acceptation ajoute une ligne à la table terms_acceptances (utilisateur, association, version du texte, date, parcours), jamais modifiée : quand les conditions évoluent, la preuve de chaque version acceptée est conservée. Ni adresse IP ni navigateur ne sont enregistrés ; l’inscription passe par un lien signé envoyé à l’adresse de la personne. Les lignes sont supprimées avec le compte ou avec l’association. La page affiche la version en vigueur, la même que celle enregistrée.
  • Pied de page du funnel d’inscription public (#360, 2026-10-06). Les pages publiques des associations affichent « Propulsé par Cohez.io · Conditions d’utilisation · Confidentialité », avec des liens absolus vers le domaine racine qui s’ouvrent dans un nouvel onglet.

Modifications

  • Case d’acceptation de l’inscription sur invitation (#360, 2026-10-06). La case renvoie désormais aux conditions d’utilisation et n’est plus présentée comme un consentement RGPD : la description indique que les données sont traitées par l’association avec Cohez.io et renvoie à la politique de confidentialité. Elle est exigée de tous, salariés compris (terms_accepted_at renseigné pour tout nouveau compte).
  • Preuve de l’acceptation déclarée comme traitement de l’éditeur (#360, 2026-10-06). La politique de confidentialité la décrit (section « Acceptation des conditions d’utilisation » : données, intérêt légitime, aucune adresse IP, durée), l’article 1 bis de la fiche /dpa la cite parmi les traitements dont l’éditeur est responsable (ligne d’historique du 6 octobre, version 2026-10 inchangée), et l’article 9 des conditions d’utilisation y renvoie.

0.25.17.0 — 2026-10-06

Modifications

  • Pages légales alignées sur le contrat final Partenaire Fondateur (version 2026-10) (2026-10-06). /conditions-generales reprend le contrat signé. Ajouts : la date d'effet (la garantie tarifaire de deux ans court à partir d'elle, plus de la signature), le socle essentiel (accès aux données, export CSV, gestion des membres et des cotisations), les obligations de moyens et la vigilance de l'association, un préavis de sortie de beta porté à deux mois avec la liste des avantages acquis, la propriété intellectuelle détaillée (contenus, retours, contributions protégeables, référence commerciale), la responsabilité réécrite (plafond réservé à l'association qui agit à des fins professionnelles, assurance MAIF), les neuf cas de remboursement au prorata, trente jours de consultation et d'export après la fin du contrat (l'accès n'est plus coupé), le nouvel article 15 bis (arrêt du service, non-reconduction par l'éditeur, transfert du contrat) et la valeur de l'exemplaire signé électroniquement. /dpa précise la conservation des sauvegardes (sept jours), la rétention chez Mistral AI (trente jours, détection des abus), l'archivage des pièces de santé en fin de saison, la résiliation ouverte par une objection à un nouveau sous-traitant et une nouvelle section « Fin du contrat ». /confidentialite décrit les traitements que l'éditeur mène pour son propre compte : sécurité du logiciel, prévention des abus et statistiques d'usage anonymisées. L'offre, la FAQ et la page tarifs font partir la garantie du début de l'abonnement.

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.6.0 — 2026-09-28

Ajouts

  • Page d'erreur applicative en français sur les espaces association (#318, 2026-09-26). Les 403, 404, 410 (et les 500 hors mode debug) des sous-domaines tenant affichent une page Inertia du Design System (errors/HttpError) au lieu de la page Laravel en anglais : titre et message par statut, bouton « Retour au tableau de bord » réservé aux utilisateurs connectés. Le 410 reste générique (« Ce lien ou ce document n'est plus disponible ») car il couvre aussi les liens publics expirés du funnel. Seul le code de statut est transmis à la page : ni message d'exception, ni chemin, ni trace. La vitrine, l'admin Filament et les réponses JSON gardent leur comportement d'origine ; si le rendu échoue, l'erreur est journalisée et la réponse d'origine est renvoyée.

Modifications

  • Contraste AA des couleurs de statut success et warning, dans toute l'application (#318, 2026-09-26). Blanc sur #27AE60 ou #C68C00 plafonnait à 2,9:1 ; les tokens passent à #1F7A3E et #8A6100 en clair (≥ 5:1 sous texte blanc et sur le fond de page), avec un texte foncé sur les badges en sombre. Tous les badges, pastilles et textes de statut changent de teinte (Dashboard, paniers, inscriptions, réunions, toasts).
  • Accessibilité de l'onglet Santé et de la page Archives santé (#318, 2026-09-26). Formats, taille maximale et plage de dates acceptés affichés sous le champ de dépôt, dérivés des règles serveur ; champ fichier vidé après un dépôt réussi ; boutons « Déposer » / « Enregistrer » actifs, validation à la soumission, erreurs annoncées (role="alert") et focus sur le premier champ en erreur ; erreur de saison reliée au sélecteur. Archives : titres de tableaux (<caption>), aide du motif reliée au champ, état de téléchargement. Icônes décoratives masquées aux lecteurs d'écran, noms accessibles distincts d'une saison à l'autre, mention « nouvel onglet », cibles tactiles de 44 px sur mobile.
  • Composants de formulaire (#318, 2026-09-26). Input, Textarea et Select ne posent aria-describedby que si l'aide ou l'erreur visée existe ; Select accepte une aide et une erreur reliées, et aligne sa valeur à gauche partout.

Corrections / Sécurité

  • Les pièces santé sont téléchargées avec leur vrai type de fichier (#318, 2026-09-26). StreamMemberDocument ne posait pas de Content-Type : la pièce partait en text/html. Elle est maintenant servie en PDF, JPEG ou PNG selon son extension (liste blanche, repli application/octet-stream), avec X-Content-Type-Options: nosniff. Formats acceptés, attribut accept, aide affichée et type servi viennent d'une source unique, HealthDocumentRules.
  • Page d'erreur applicative : correctifs de revue (#318, 2026-09-26). L'admin sur admin.{domaine} garde sa page d'origine même si ADMIN_DOMAIN diffère ; une réponse d'erreur déjà en JSON n'est jamais remplacée par la page HTML ; tous les appels fetch JSON du front (funnel public, groupes, utilisateurs, représentants légaux, réunion live) envoient Accept: application/json, pour recevoir le message d'erreur du serveur plutôt qu'une page ; un visiteur sans session (URL inexistante) se voit proposer « Retour à l'accueil ». Une fiche introuvable (404 levé à la résolution du modèle de la route, par exemple /members/{id} inconnu) garde l'utilisateur connecté et le nom de l'association : les middlewares Inertia passent désormais avant SubstituteBindings.
  • Onglet Santé et Archives : erreurs mieux rattachées (#318, 2026-09-26). L'erreur sur le représentant légal d'une attestation est affichée et reliée à son champ, et une erreur sans champ dédié est annoncée au niveau du formulaire. Dans les Archives, une pièce déjà supprimée (410), une erreur réseau ou un refus serveur s'affichent dans le dialogue sans marquer le motif invalide ; l'erreur « motif trop court » s'efface à la saisie.
  • Stack Docker de dev : healthcheck nginx limité à /health exact (#322, 2026-09-28). location /health était un préfixe et interceptait /health-archives, qui répondait healthy au lieu d'afficher la page Archives santé en local. Aucun effet sur Clever Cloud.

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.1.1 — 2026-09-17

Corrections

  • Deux créations ou mises à jour de fiche salarié concurrentes pouvaient contourner les gardes anti-doublon (#287, 2026-09-17). EmployeeController::store()/update() verrouillent désormais la Person visée (Employee::lockPersonForActiveConflictCheck()) et le compte utilisateur ciblé (lockForUpdate() + revérification) pendant la fenêtre check-then-write, en complément de la nouvelle contrainte unique users_employee_id_unique posée en filet de sécurité côté base.
  • La recherche de personne ou de compte par e-mail ratait les adresses accentuées en majuscules (#287, 2026-09-17). EmployeePersonResolver::resolve() et EmployeeController::linkStaffAccount() appliquaient mb_strtolower() (Unicode-aware) côté PHP à l'e-mail recherché mais LOWER() (ASCII-only sous PostgreSQL) côté SQL à la colonne — sur un e-mail comme PÉREZ@EXAMPLE.COM, les deux replis divergeaient et la recherche ratait la ligne existante, créant un doublon silencieux. LOWER() s'applique désormais aux deux opérandes, côté SGBD.

0.22.1.0 — 2026-07-31

Ajouts

  • Codes de réduction par campagne. Un adhérent saisit un code dans le formulaire public (ou un agent en back-office) et obtient une remise en pourcentage (1-100 %) sur son panier. Chaque code est configuré par campagne : ciblage optionnel par rubrique, quota d'utilisations, date d'expiration (inclusive). Techniquement, un code est une PricingRule dont la colonne code est non-null — même table, même moteur de calcul que les remises automatiques ; Campaign::pricingRules() filtre désormais whereNull('code') pour que les dix appelants existants ne voient jamais un code. CRUD back-office sur la carte campagne (créer, modifier, archiver, supprimer), saisie côté funnel avec badge de confirmation et remise reflétée dans le total affiché. Doc : Docs/Features/Promo-Codes.md.
  • Consommation par panier, pas par compteur. La table promo_code_redemptions enregistre une ligne par panier ; deux index uniques partiels portent les règles métier (un seul code par panier, une seule consommation active par panier). Le quota est gardé deux fois — pré-filtre dans CartPricingRules::resolveUsableCode() et garde post-verrou dans RedeemPromoCodeService — et la ligne est libérée à l'abandon du panier. La remise survit aux mutations de cours : MutateRegistrationCoursesService et CartMutationService recalculent avec CartPricingRules::forCart(), pas avec la relation filtrée.
  • Validation immédiate d'un panier ramené à 0 €. Un panier intégralement couvert par un code ne passe plus par HelloAsso : il est validé sur-le-champ, le moyen de paiement est réinitialisé et le mail de confirmation part sans ligne de reste à payer. Le code de réduction appliqué est tracé dans le snapshot de facture et affiché sur le détail panier.

Sécurité

  • Oracle d'existence de codes fermé. L'autorisation vivait dans le contrôleur, alors que Laravel résout rules() et withValidator() avant lui : n'importe quel utilisateur authentifié du tenant pouvait distinguer « code inexistant » de « code existant mais interdit » via les messages de validation. L'autorisation est remontée dans StorePromoCodeRequest::authorize(). Côté public, la réponse d'application d'un code est uniformisée et un seau anti-énumération partagé limite les tentatives.
  • Fuite de quota fermée. Le décompte pouvait être contourné en concurrence ; la consommation se fait maintenant sous verrou, dans une transaction gardée, et le prédicat est testé des deux côtés (code utilisable / code épuisé).

Modifications

  • La suite de tests ne peut plus atteindre PostgreSQL. La connexion pgsql est dé-configurée pour les tests et tests/Unit/TestDatabaseIsolationTest.php monte la garde — il vérifie aussi qu'aucune trace d'un flag d'opt-in ne revient dans le dépôt. Motif : un tel flag avait vidé la base de développement. Les agrégats sensibles à la divergence SQLite↔PostgreSQL se vérifient désormais à la main sur la base de dev, jamais via la suite.

0.20.1.0 — 2026-07-22

Ajouts

  • Ouverture/fermeture automatique des campagnes aux dates programmées : une campagne configurée avec opens_at/closes_at restait figée dans son statut tant qu'un admin ne cliquait pas manuellement sur « Ouvrir » ou « Clôturer » — elle pouvait rester Draft le jour J faute d'intervention, ou Open bien après sa clôture prévue. Les transitions Draft → Open et Open → Closed s'exécutent désormais automatiquement via des jobs différés (OpenCampaignJob/CloseCampaignJob), protégés par un guard atomique anti-TOCTOU (CampaignTransitionGuard::tryTransition, une seule requête UPDATE ... WHERE status = ... fait toute la protection contre les exécutions concurrentes). Un filet de sécurité horaire (campaigns:sync-status --safety-net) rattrape toute transition manquée (job perdu, queue non consommée) avec jusqu'à 1h de retard. Voir Docs/Features/Campaign-Auto-Open-Close.md. Action manuelle requise avant déploiement : reconfigurer CC_WORKER_COMMAND_0 sur Clever Cloud pour consommer la queue campaigns.

0.18.0.0 — 2026-06-29

Ajouts

  • Gérer le panier — CartMutationService : trois nouvelles opérations atomiques sur le panier, chacune sous verrou lockForUpdate global sur toutes les inscriptions du panier :
    • Ajouter un inscrit : sélection d'un membre existant (liste filtrée — inscrits actifs exclus) ou création inline d'un nouveau membre, avec choix du/des cours. Les tarifs multi-membres sont recalculés pour l'ensemble du panier à chaque ajout. La facture de chaque inscription déjà facturée est re-versionnée.
    • Déplacer un cours : transfert atomique d'un cours d'un inscrit vers un autre inscrit du même panier. Les deux inscriptions sont recalculées et leur facture re-versionnée dans la même transaction.
    • Supprimer le panier : annulation de toutes les inscriptions non-terminales avec remise à zéro des montants. Bloqué si des versements encaissés existent (atomique — vérification sous verrou).
  • Dialogs back-office sur la page « Détail du panier » : trois dialogs dédiés (Ajouter un inscrit, Déplacer un cours, Supprimer le panier) accessibles via un menu « Gérer le panier ». Les actions destructives nécessitent une confirmation explicite.
  • Sécurité — isolation tenant renforcée : les propositions sont désormais scopées explicitement au tenant du gestionnaire (via rubriques.tenant_id) dans les Form Requests et dans le contrôleur, en complément de la vérification campaign_id existante dans le service.

Corrections

  • Sécurité : la vérification de versements encaissés dans deleteCart est désormais effectuée à l'intérieur de la transaction sous lockForUpdate, éliminant une fenêtre de race condition entre la vérification et l'annulation des inscriptions.

0.17.0.0 — 2026-06-29

Ajouts

  • Panneau paiement inline dans le détail panier : récap des versements (montant, statut, méthode, dates prévue/reçue, référence, notes) et formulaire d'ajout directement sur la page détail panier — plus besoin d'ouvrir une modale ou de naviguer vers le plan de paiement.

Modifications

  • Enregistrer un versement redirige désormais vers la page d'origine (détail panier ou plan de paiement) au lieu de forcer la navigation vers le plan de paiement.
  • Le détail panier expose les données complètes des versements (dates, référence, notes) au lieu d'un simple statut.

Corrections

  • Sécurité : la redirection post-enregistrement de versement est désormais restreinte aux routes autorisées du panier (protège contre une éventuelle manipulation du header Referer).