Aller au contenu
Candidater

Journal des modifications

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

173 versions publiées.

Versions 161 à 170 sur 173

0.4.1.0 - 2026-04-14

Ajouts

  • Chiffrement des secrets tenant — les clés API HelloAsso (hello_asso_client_secret, hello_asso_webhook_secret) sont maintenant chiffrées au repos dans la colonne settings JSON du tenant via un cast Eloquent EncryptedSettingsCast. Toute clé dont le nom se termine par _secret est automatiquement chiffrée en écriture et déchiffrée en lecture (AES-256-CBC via APP_KEY). L'accès depuis le code applicatif est transparent.
  • Rotation d'APP_KEY — support de APP_PREVIOUS_KEYS pour déchiffrer les secrets chiffrés avec une ancienne clé sans interruption de service. La commande php artisan settings:reencrypt-secrets re-chiffre tous les secrets sous la clé courante pour permettre de vider APP_PREVIOUS_KEYS après rotation.
  • Migration de données idempotente — la migration encrypt_tenant_settings_secrets chiffre les secrets existants en clair dans la base de production. L'opération est idempotente (les blobs déjà chiffrés sont ignorés) et peut être réexécutée sans risque.
  • Commande de re-chiffrement en deux phases — settings:reencrypt-secrets opère en phase 1 (lecture et validation de tous les secrets) puis phase 2 (écriture), de sorte qu'une erreur de déchiffrement sur un tenant annule l'opération avant qu'une seule écriture ait lieu.
  • UX intégrations — masquage des secrets existants — le formulaire de configuration HelloAsso affiche un placeholder "Configuré — laisser vide pour conserver" lorsqu'un secret est déjà enregistré, évitant d'exposer la valeur et signalant clairement que le champ peut être laissé vide.
  • Confirmation du mot de passe sur la page intégrations — la sauvegarde des identifiants HelloAsso requiert maintenant la confirmation du mot de passe courant de l'utilisateur.

Sécurité

  • Les secrets API HelloAsso ne sont plus stockés en clair dans la base de données. La colonne settings contient désormais des blobs chiffrés AES-256-CBC pour toutes les valeurs dont la clé se termine par _secret.

0.4.0.0 - 2026-04-14

Ajouts

  • Formulaire d'inscription public — consentements RGPD — les inscriptions publiques collectent désormais les consentements newsletter, partage de données et droit à l'image. Si la personne existe déjà en base, ses consentements sont mis à jour en mode opt-in uniquement (jamais de rétrogradation). La date de consentement est enregistrée lors de toute acceptation.
  • Formulaire d'inscription public — acceptation des documents — le formulaire recueille l'acceptation des statuts et du règlement intérieur. Ces acceptations sont obligatoires pour valider la soumission et sont stockées sur l'adhésion créée.
  • Formulaire d'inscription public — responsables légaux (tuteurs) — les membres mineurs peuvent désormais avoir un ou plusieurs responsables légaux renseignés directement depuis le formulaire public. Le premier tuteur est automatiquement marqué comme contact principal (is_primary_contact). L'interface permet d'ajouter le premier responsable en un seul clic.
  • Formulaire d'inscription public — adresse ligne 2 — le champ adresse ligne 2 est maintenant disponible dans le formulaire public, mappé vers la Person créée ou mise à jour.

Corrections

  • Normalisation des données — emails des tuteurs — les emails des responsables légaux sont normalisés (minuscules + trim) lors de la préparation de la requête, cohérent avec le traitement des emails du membre et du payeur. Prévient les doublons liés à la casse.
  • is_primary_contact — premier tuteur — le premier responsable légal est automatiquement désigné contact principal (index 0), les suivants ne le sont pas.
  • DRY — calcul de la minorité — la logique de détection d'un membre mineur (age < 18 ou présence de tuteurs) était dupliquée dans PersonDeduplicationService. Extraite dans une méthode privée resolveIsMinor().
  • Design — polices et composants design system — activation de font-display pour Fraunces sur le PublicLayout, attribut crossorigin sur le lien stylesheet Bunny Fonts, suppression des astérisques redondants sur les champs, alignement des composants Select et Button sur le design system.
  • UX — ouverture automatique du premier tuteur — lorsqu'on clique sur le bouton d'ajout de tuteur, le formulaire s'ouvre directement au lieu d'afficher un accordéon vide.

Modifications

  • Couverture de tests : ajout de la validation du chemin opt-in RGPD pour les personnes existantes (33 tests, 106 assertions).

0.3.2.3 - 2026-04-13

Corrections

  • Sécurité — validation serveur du montant unitaire — le contrôleur d'inscription publique acceptait n'importe quel unit_amount sans vérification, permettant à un utilisateur malveillant de soumettre 0 € pour une proposition à prix fixe. La FormRequest impose maintenant que le unit_amount corresponde exactement au amount de la proposition pour les types fixed, et soit nul pour les types free. Les propositions custom (montant libre) acceptent tout montant ≥ 0.
  • Bug — propositions gratuites bloquaient le formulaire — dans CampaignPropositionSelector.vue, les propositions de type free n'initialisaient pas unit_amount lors de la sélection (radio ou checkbox). Le JSON envoyé ne contenait pas la clé unit_amount, déclenchant l'erreur de validation required côté serveur et laissant l'utilisateur bloqué à l'étape 2 avec une erreur impossible à corriger. Le champ unit_amount est maintenant systématiquement initialisé à 0 pour tous les types non-fixed.
  • UX — navigation automatique vers l'étape en erreur — après une soumission rejetée par le serveur, l'utilisateur restait bloqué à l'étape 4 (récapitulatif) sans voir les erreurs de validation sur les étapes précédentes. Des watchers Vue naviguent maintenant automatiquement vers l'étape 1, 2 ou 3 dès qu'une erreur serveur est détectée sur les champs correspondants. Le watcher de l'étape 1 inclut désormais un guard currentStep.value > 1 pour éviter une navigation intempestive.

0.3.2.2 - 2026-04-13

Corrections

  • Redirection HelloAsso — TypeError corrigé en production — le formulaire d'inscription publique retournait RedirectResponse mais Inertia::location() retourne SymfonyResponse lors d'une requête XHR Inertia. Sans ce correctif, la redirection vers HelloAsso déclenchait un TypeError PHP 8 en production dès qu'un tenant avait ses identifiants HelloAsso configurés, empêchant tout paiement via HelloAsso. Le type de retour de store() est maintenant SymfonyResponse (compatible avec tous les chemins de retour existants).
  • Champ montant libre — affichage en euros et stockage en centimes — dans le sélecteur de propositions, les champs de montant libre (type custom) affichaient les centimes bruts (ex : 5000 au lieu de 50,00 €) et sauvegardaient la valeur en euros au lieu des centimes. Le correctif divise par 100 à l'affichage et multiplie par 100 à la saisie, alignant le comportement avec le reste du système. Un attribut max="999999.99" est ajouté pour bloquer les valeurs aberrantes côté client.
  • Tests HelloAsso — compatibilité environnement sandbox — les fakes Http::fake() dans les tests de retour et d'erreur HelloAsso utilisaient le domaine de production (api.helloasso.com) en dur. Avec HELLOASSO_SANDBOX=true, ces tests tentaient une vraie requête réseau. Les patterns sont alignés sur *.helloasso* pour couvrir production et sandbox de manière identique aux helpers existants.

0.3.2.1 - 2026-04-10

Corrections

  • Page de succès HelloAsso — message affiché selon l'état du paiement — après un paiement HelloAsso, les utilisateurs dont le paiement est encore en cours de traitement voyaient à tort le message "Un email de confirmation vous a été envoyé". La page affiche maintenant une icône horloge et un message "Votre paiement est en cours de traitement" quand le paiement n'est pas encore confirmé, et ne bascule vers le message de confirmation qu'une fois le paiement validé. Le titre de la page s'adapte également (Paiement en cours de traitement ou Inscription confirmée).

0.3.2.0 - 2026-04-10

Corrections

  • Crash 500 sur la liste des membres — les numéros de téléphone invalides en base (hérités de données importées ou saisies avant validation) provoquaient une InvalidPhoneNumberException lors de la reconstruction du domaine. Un mécanisme de quarantaine (hydratePhone()) isole maintenant ces valeurs sans bloquer l'affichage.
  • Normalisation des formats de téléphone à la saisie — les utilisateurs peuvent saisir 06 12 34 56 78, 06.12.34.56.78, +33612345678, 0033612345678 ou un numéro mobile à 9 chiffres sans le 0 initial ; le numéro est automatiquement converti au format canonique 0XXXXXXXXX avant validation. Concerne les formulaires membre, tuteur légal, inscription admin et inscription publique.
  • Regex de validation plus stricte — l'ancre \z remplace $ dans le pattern /^0\d{9}\z/ pour rejeter les valeurs avec caractère de fin de ligne masqué.

Ajouts

  • Migration de nettoyage des téléphones — normalise ou nullifie les numéros existants en base qui ne respectent pas le format 0XXXXXXXXX, avec log warning pour chaque valeur supprimée.

0.3.1.0 - 2026-04-09

Ajouts

  • Paiement HelloAsso en ligne — depuis le formulaire public d'inscription, les visiteurs peuvent désormais payer directement via HelloAsso Checkout. L'association configure ses identifiants OAuth2 et son slug dans les settings, et le bouton "Payer en ligne" apparaît automatiquement sur le wizard.
  • Page Intégrations (/settings/integrations) — les administrateurs saisissent leur Client ID, Client Secret, slug HelloAsso et secret webhook depuis une interface dédiée. Les secrets ne sont jamais réexposés en frontend après enregistrement.
  • Webhook HelloAsso (POST /webhook/helloasso/{tenantId}) — endpoint vérifié par signature HMAC-SHA256. Marque le paiement comme reçu, fait passer l'inscription en Paid, et envoie le mail de confirmation exactement une fois (idempotence via confirmation_email_sent_at).
  • URL de retour HelloAsso (/register/{token}/helloasso/return) — après paiement, vérifie l'état du checkout intent via l'API HelloAsso. Si payé, confirme l'inscription immédiatement. Si l'API est indisponible, affiche un message "en cours de traitement" et laisse le webhook finaliser.
  • Page d'erreur HelloAsso (/register/{token}/helloasso/error) — affichée si le paiement échoue ou si l'API HelloAsso retourne une erreur. L'inscription orpheline est supprimée automatiquement pour permettre une nouvelle tentative.
  • Service HelloAssoClient — client HTTP OAuth2 avec cache du token (25 min), support sandbox via HELLOASSO_SANDBOX=true, deux méthodes : createCheckoutIntent() et getCheckoutIntent().
  • Index payments_reference_index — index standalone sur payments.reference pour les requêtes de fallback du webhook (la contrainte unique UNIQUE(reference, method) existante ne suffit pas pour les lookups par reference seul).

Sécurité

  • La valeur redirectUrl retournée par HelloAsso est validée contre une liste d'origines autorisées (helloasso.com / helloasso-sandbox.com) avant redirect()->away() pour se prémunir d'une compromission de l'API côté HelloAsso.
  • Le webhook est exclu du CSRF Laravel et vérifié par HMAC-SHA256 à la place (X-Helloasso-Signature).
  • Rate limiter du webhook keyé sur tenantId (120 req/h) plutôt que sur l'IP (HelloAsso partage un pool IP entre toutes les organisations).

0.3.0.0 - 2026-04-08

Ajouts

  • Formulaire public d'inscription — les associations peuvent générer un lien public (token signé, expirable) depuis les paramètres d'une campagne. Ce lien donne accès à un wizard en 4 étapes (informations membre, chargement des propositions, sélection + payeur, récapitulatif) accessible sans compte. Aucun compte HelloAsso requis.
  • Token public de campagne (CampaignPublicToken) — modèle avec expiration configurable, génération via Str::uuid()->toString() (UUID v4, col char(36)), révocation instantanée depuis les settings. Un token révoqué retourne 410.
  • Déduplication silencieuse — si l'email soumis correspond à une Person existante dans le tenant, le service réutilise le membre ou crée un Member lié sans jamais révéler au visiteur si son compte existait.
  • Détection des doublons d'inscription — si le même membre tente de s'inscrire deux fois à la même campagne, une erreur de validation claire est retournée sur le champ member_email. Contrainte unique (member_id, campaign_id) ajoutée en base.
  • Mail de confirmation (PublicRegistrationConfirmationMail) — envoyé en queue après inscription réussie si un email est fourni, avec récapitulatif des propositions sélectionnées et du mode de paiement.
  • Page de confirmation (/register/{token}/success) — page dédiée après soumission réussie, protégée par le même middleware token.
  • Branding dans le layout public — le nom de l'association est affiché au-dessus du titre de la page pour que le visiteur sache à quelle organisation il s'inscrit.
  • Throttling — les routes publiques d'inscription sont limitées à 10 req/min par IP pour limiter l'abus.

Modifications

  • Middleware ResolveCampaignPublicToken — vérifie désormais que la campagne est en statut Open (en plus du contrôle d'expiration du token). Une campagne Draft ou Closed retourne 410.
  • PersonDeduplicationService — is_minor calculé dynamiquement depuis dateNaissance (Carbon::age < 18) au lieu d'être codé à false.

Corrections

  • Migration add_unique_member_campaign_to_registrations : guard contre les doublons existants avant d'appliquer la contrainte unique (évite un crash silencieux en production si des données corrompues sont présentes).

0.2.1.0 - 2026-04-07

Ajouts

  • Système de design Cohez.io — identité visuelle définie et codée : polices Fraunces (titres) + Geist (interface) + Geist Mono (données financières), chargées via Bunny Fonts (GDPR-compliant). Palette de couleurs basée sur le vert sauge (#2D6A4F) comme couleur brand, fond crème #FAF9F7, neutrals chauds — différenciant dans la catégorie face au bleu corporate omniprésent (AssoConnect, HelloAsso).
  • Composant EmptyState (@/components/ui/empty-state) — état vide réutilisable : icône Lucide + titre + description + slot pour CTA optionnel. Appliqué sur les listes de membres, groupes, réunions.
  • Composant ConfirmDialog (@/components/ui/confirm-dialog) — dialogue de confirmation avant toute action destructive. Remplace entièrement les confirm() natifs (qui bloquent les events browser). Utilisé pour la désactivation/suppression de membres et groupes.
  • FlashToast (@/components/layout/FlashToast) — notification toast bottom-right consommant automatiquement flash.success et flash.error depuis les props Inertia partagées. Intégré dans AppSidebarLayout.
  • Bannière alerte impayés sur le tableau de bord — si des inscriptions non payées existent, une bannière rouge s'affiche en haut de page avec un lien direct vers la liste filtrée.
  • DESIGN.md — documentation complète du design system : couleurs avec rationale, typographie, espacement, border radius, motion, composants, patterns UI, responsive, accessibilité et journal de décisions.

Modifications

  • Dashboard — agenda de la semaine en empty state explicite quand aucune réunion n'est planifiée ; bannière impayés avec filtre URL correct.
  • Pages membres et groupes — états vides cohérents avec le composant EmptyState au lieu de textes inline.
  • Wizard d'inscription — garde contre 0 campagnes disponibles avec empty state explicite ; correction de l'affichage du récapitulatif sur mobile.

Corrections

  • Suppression du </div> en trop dans le wizard d'inscription (registrations/Create.vue).
  • Le lien "impayés" du dashboard utilisait un format de query params incorrect pour Wayfinder ({ status: 'unpaid' } → { query: { status: 'unpaid' } }).
  • FlashToast : ajout du onUnmounted pour nettoyer le timer, ajout de break-words sur le message pour éviter l'overflow sur les messages longs.

0.2.0.0 - 2026-04-03

Ajouts

  • Responsables légaux pour membres mineurs — les membres peuvent être marqués comme mineurs (toggle sur la fiche membre). Le secrétaire peut ensuite associer un ou plusieurs responsables légaux (parent, tuteur légal, autre…) via une interface dédiée : recherche de personne existante, création d'une nouvelle personne, ou sélection depuis le wizard d'inscription. Chaque responsable légal porte un type de relation, un indicateur "contact principal" et des notes libres.
  • Gestion complète des responsables légaux depuis la fiche membre : ajout, modification (type de relation, contact principal, notes) et retrait — sans supprimer la personne sous-jacente.
  • Support des mineurs dans le wizard d'inscription — lors de la création d'un nouveau membre mineur via le wizard, il est désormais possible d'ajouter directement ses responsables légaux à l'étape 2, en sélectionnant des personnes existantes.
  • Création de membre inline dans le wizard d'inscription — il n'est plus nécessaire de créer un membre avant de l'inscrire. Le wizard propose un toggle "Membre existant / Nouveau membre" à l'étape 2. En mode "Nouveau membre", le formulaire complet s'affiche directement, et la création du membre + l'inscription sont atomiques (une seule transaction).
  • Trait MemberValidationRules — les règles de validation des membres sont centralisées dans un trait partagé entre StoreMemberRequest et StoreRegistrationRequest (avec système de préfixe), éliminant la duplication.

Corrections

  • Correction du DTO CreateMemberRequest — la création d'un membre sans email (avec seulement un téléphone) provoquait une InvalidArgumentException. Le champ email est désormais nullable dans le DTO et l'use case.
  • Protection contre les doublons de responsables légaux — ajouter deux fois la même personne comme responsable légal depuis le wizard d'inscription retourne désormais une erreur de validation (422) au lieu d'une erreur serveur 500.
  • Recherche de personnes — les requêtes de moins de 2 caractères retournent une liste vide (évite l'exposition inutile de données personnelles).
  • Recherche insensible à la casse — la recherche de membres et de responsables légaux fonctionne désormais quelle que soit la casse (ex. "bec" trouve "BECQUE"). Corrige un comportement PostgreSQL où LIKE est case-sensitive.
  • Syntaxe Vue invalide dans MemberForm — :errors?= provoquait une erreur Vite bloquant l'affichage du formulaire. Corrigé en :errors=.
  • Wayfinder dans LegalGuardianSection — le toggle "mineur" utilisait route() (Ziggy, non disponible) au lieu de Wayfinder. Corrigé.
  • Input.vue accepte null — les champs optionnels typés string | null (nom, téléphone, date de naissance…) ne provoquent plus d'erreurs TypeScript.