Journal des modifications
Les évolutions de Cohez.io, de la plus récente à la plus ancienne.
14 versions correspondent à « réunion ».
Versions 1 à 10 sur 14
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
successetwarning, dans toute l'application (#318, 2026-09-26). Blanc sur#27AE60ou#C68C00plafonnait à 2,9:1 ; les tokens passent à#1F7A3Eet#8A6100en 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,TextareaetSelectne posentaria-describedbyque si l'aide ou l'erreur visée existe ;Selectaccepte 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).
StreamMemberDocumentne posait pas deContent-Type: la pièce partait entext/html. Elle est maintenant servie en PDF, JPEG ou PNG selon son extension (liste blanche, repliapplication/octet-stream), avecX-Content-Type-Options: nosniff. Formats acceptés, attributaccept, 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 siADMIN_DOMAINdiffère ; une réponse d'erreur déjà en JSON n'est jamais remplacée par la page HTML ; tous les appelsfetchJSON du front (funnel public, groupes, utilisateurs, représentants légaux, réunion live) envoientAccept: 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 avantSubstituteBindings. - 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é à
/healthexact (#322, 2026-09-28).location /healthétait un préfixe et interceptait/health-archives, qui répondaithealthyau lieu d'afficher la page Archives santé en local. Aucun effet sur Clever Cloud.
0.25.0.0 — 2026-09-04
Ajouts
- Le registre des salariés existe, et un salarié peut participer à une réunion sans qu'on lui fabrique une fiche d'adhérent (#277, 2026-09-02). Nouvelle table
employeeset pivotemployee_employee_types— un salarié cumule plusieurs types —, enumsEmployeeTypeetEmployeeStatus,EmployeePolicy, pages InertiaEmployees/Index|Show|Form.users.employee_id(nullable) relie un compte à sa fiche RH ;meeting_participants.person_idajoute un quatrième mode de participation, mutuellement exclusif des trois autres. Un rôlecoachet une permissionview_own_coursesouvrent un calendrier en lecture seule, vers lequel la connexion redirige directement : il n'expose que les métadonnées des cours, aucune donnée personnelle d'adhérent. - Les comptes
user_type = 'employee'sans fiche RH sont listés sur le registre, en mode dégradé (#280, 2026-09-02).EmployeeController::index()exposeunlinkedStaff— les comptes du tenant dontemployee_idest nul —, rendus avec un badge « Sans fiche RH » et un bouton « Créer la fiche ». Aucune donnée n'est écrite et aucun backfill n'est lancé : c'est un révélateur d'un écart existant, pas une migration. Le formulaire ne pré-remplitperson_idque si un seulpersons.emailcorrespond (comparaison en minuscules, en une requête, sans N+1). La section disparaît dès qu'un filtre de statut est posé, et au-delà de la première page, où elle n'aurait plus de sens. - Kit de formation EPGV 44 et profils de règlement du jeu de démonstration (#273, 2026-08-27).
Docs/Formations/EPGV-44/reçoit un déroulé animateur, des fiches pratiques et un support projeté. Côté données,EpgvSeederrépartit les inscriptions sur des profils de règlement contrastés — 7 soldées, 2 partielles, 1 chèque annoncé mais non encaissé, 2 sans aucun paiement — pour que le tableau de bord de démonstration affiche 3 impayés plutôt qu'un jeu uniformément soldé, qui ne montrait aucun des écrans de relance.createPaymentReceived()etcreatePaymentPending()acceptent désormais des paramètres optionnels. - Comptes et réunion de formation du tenant
demo-epgv-44(#275, 2026-08-27). Six comptesadmin(mot de passepassword), un helpercreateEmployeeUser(), et la réunion « Présentation et formation Cohézio » avec ses six participants : la démonstration part d'un tenant peuplé au lieu d'écrans vides.
Corrections
- Les compteurs du tableau de bord ignoraient le statut des inscriptions (#278, 2026-09-01).
seasonRegistrations,unpaidCountetunpaidMemberspassent par deux helpers privés qui appliquentwhereNotIn('status', RegistrationStatus::terminalStatuses()). Mesuré sur une copie de la production : 527 inscriptions de saison annoncées pour 467 réelles, et 69 impayés annoncés pour 13. Un dirigeant relançait donc cinq fois trop de monde.collectedAmountn'est volontairement pas filtré : un paiementreceivedreste encaissé après l'annulation de l'inscription qui l'a motivé — ne pas « compléter » ce correctif en l'y ajoutant. - Une inscription annulée interdisait toute réinscription du même membre sur la même campagne (#279, 2026-09-03). La contrainte UNIQUE totale
(member_id, campaign_id)est remplacée par un index unique partiel,where status not in ('cancelled', 'abandoned'). Mesuré surlezards-animes: 60 couples (membre, campagne) ne portaient plus que des inscriptions annulées — 60 personnes bloquées, avec unSQLSTATE 23505pour seule explication.RegistrationDuplicateCheckerest aligné surterminalStatuses(); c'est un no-op fonctionnel aujourd'hui, la méthode ne rendant quecancelled— l'index partiel EST le correctif.abandonedest nommé d'avance à dessein :statusest unvarchar(255)et non un enum PostgreSQL, l'ajouter àterminalStatuses()suffira le jour venu. - Findings de la revue de code du registre des salariés (#281, 2026-09-02). Treize sur quatorze corrigés. Le tableau de bord vide désormais
unpaidMembers,recentActivityetclosingSoonCampaignscôté serveur pour les rôles sansview_members: uncoachrecevait la charge utile complète et on ne comptait que sur le front pour ne pas l'afficher.mapPerson()est réduit à id / prénom / nom / e-mail, avec un test qui fige la forme exacte de la charge utile (sansetc()), pour qu'un champ rajouté fasse rougir la suite. Sont également corrigés : la double invitation sur une même fiche salarié, l'unicité d'un participant par réunion, l'eager-load departicipants.persondansGenerateMeetingReportJob, le plafonnement deunlinkedStaff(), la validation d'employee_iden query-string comme UUID du tenant, et la seconde sortie de connexion de Fortify — celle du 2FA — qui ne redirigeait pas le coach. - La liste des adhérents annonçait « En attente » à des adhérents dont l'adhésion court (#283, 2026-09-04). Le badge et la pilule de filtre portant l'axe administratif (
members.status) sont retirés demembers/Index.vueet deMemberFilters.vue; il ne reste que l'état dérivé des périodes dememberships. Motif : aucun écran n'écrit cette colonne — ni la création, ni le formulaire d'édition, et les boutons Désactiver / Réactiver touchentis_active—, si bien qu'elle restait figée sur sa valeur de création. Le trou est dans le front, pas dans le domaine :Member::changeStatus(),UpdateMemberUseCaseet la routemembers.update-statussavent l'écrire dès que la charge utile porte le champ. Le paramètrestatusreste donc honoré côté serveur etapplyFiltersle reconduit d'une requête à la suivante, sans quoi un signet le portant n'aurait survécu qu'à un seul chargement.PersonMemberTab.vueaffiche encore le badge hérité : hors périmètre, connu.MembersLegacyStatusAxisHiddenTestverrouille le retrait sur le source — le réexposer suppose d'abord qu'un écran pose la valeur.
Notes techniques
- Cette version est d'abord un rattrapage de documentation. Les sept premières PR ci-dessus sont parties en production entre le 27 août et le 3 septembre 2026 sans commit de release ; chacune est datée de son merge. Seule #283 est livrée par cette version : elle n'était pas déployée quand ce fichier a été écrit, et c'est pour ne pas reproduire le retard de documentation qu'il vient de combler qu'elle y figure. Les sept premières sont regroupées sous un seul numéro plutôt que réparties sur des versions intermédiaires que
VERSIONn'a jamais portées et qu'aucun déploiement n'a servies. Le segment mineur bouge parce que le registre des salariés ajoute des tables et un module. Course::coachEmployee()a été renomméefindActiveCoachEmployee(), et ce n'est pas cosmétique. Une méthode au nom de relation qui rend unEmployeeau lieu d'uneRelationfait appelergetResults()par Eloquent dès qu'un eager-load ou un accès en propriété la croise : erreur fatale, pas avertissement.- Le
down()de la migration de l'index partiel lève uneRuntimeException. Restaurer une contrainte UNIQUE totale échouerait dès qu'un couple (membre, campagne) porte une inscription annulée et une active — soit exactement ce que cette version rend possible. La migration est à considérer comme irréversible en production. recentActivity()n'est toujours pas filtré par statut : les inscriptions annulées continuent d'y figurer. Connu, hors périmètre de #278, à traiter avant que la saison 2026-2027 passeActive.Employees/Form.vueexpose encoreperson_iden UUID brut. Connu, non corrigé : le champ attend un sélecteur de personne.- Les PR #225, #237 et #266 à #269 ne sont listées nulle part ici : toutes ont été mergées entre le 21 et le 24 août 2026, donc hors de la fenêtre couverte par cette version. #225 et #237 sont par ailleurs des montées de dépendances Dependabot, que ce fichier ne détaille jamais — il documente l'activation de Dependabot et les gates de CI, pas les bumps individuels ; #266 à #269 sont des changements internes sans effet sur l'application (fichiers temporaires Livewire ignorés, notes de roadmap, retrait des références JetBrains, discipline de workflow).
0.19.4.0 — 2026-07-17
Ajouts
- Éditeur WYSIWYG pour le compte-rendu de réunion en brouillon (
MeetingReportEditor.vue, Tiptap v3) : remplace le<Textarea>markdown brut par un éditeur riche (titres, listes, tableaux, citations, code, images, liens) tout en conservantcontenten markdown en base — aucun changement de schéma. Le PDF et l'e-mail du compte-rendu stylent désormais tableaux, citations et blocs de code au même format.
Corrections
- Préservation des images markdown dans l'éditeur WYSIWYG du CR (round-trip édition ↔ sauvegarde).
- Liens
javascript:neutralisés dans le rendu markdown du PDF du CR (allow_unsafe_links: false, alignement avec l'e-mail). - Taille maximale du contenu du compte-rendu (100 000 caractères) désormais appliquée côté serveur.
0.19.3.0 — 2026-07-15
Ajouts
- Affichage de l'ordre du jour sur la fiche réunion (
Show.vue) : chaque point de l'ordre du jour est désormais rendu (badge Traité/En attente, décision si renseignée, actions avec responsable résolu — utilisateur lié ou nom libre, échéance formatée). Auparavant la Card titrée « Ordre du jour » affichait en réalitémeeting.description(mislabel) ; cette section est renommée « Notes ». Le contrôleur charge désormaisagendaItems.actions.responsibleen eager-load, etMeetingAgendaItemexposestatus/status_labelen attributs calculés. - Compte-rendu de réunion généré par IA (Mistral) : à la clôture, le CR est désormais généré en arrière-plan par
GenerateMeetingReportJob— synthèse IA (MeetingReportSynthesizer) en chemin nominal, secours automatique sur le template déterministe existant en cas d'échec (timeout, erreur API), sans jamais bloquer ni faire échouer la clôture elle-même. La clôture (close()) devient elle-même atomique et idempotente (gardestatus != completed), tout comme la nouvelle action d'annulation d'une séance en cours (cancelLive(),POST /meetings/{id}/cancel-live) qui permet de revenir deliveàscheduleden cas d'erreur de manipulation. - Page de conduite en direct repensée (
Live.vue) : navigation par onglets (Ordre du jour / Notes / Transcription), notes de séance libres autosauvées (PATCH /meetings/{id}/notes) remplaçant l'ancienne saisie décision/action point par point, et chronomètre de séance qui survit désormais à un rechargement de page (started_atpersisté). - Champs lieu distant et téléphone sur les réunions (
meeting_link,phone) : une réunion peut désormais porter un lien de visioconférence et/ou un numéro d'appel, affichés sur la fiche et dans le formulaire. - Garde-fou séance bloquée : une commande planifiée quotidienne (
meetings:notify-stuck-live, 08:00 Europe/Paris) détecte les réunions restéesliveplus de 2h après leurends_atet notifie l'organisateur par email (MeetingStuckLiveMail) — notification uniquement, aucune mutation automatique de statut ou de données.
0.19.2.0 — 2026-07-15
Modifications
- Simplification de l'ordre du jour des réunions : les points de l'ordre du jour perdent la durée estimée, le responsable dédié et les horodatages de démarrage/clôture (
estimated_duration_minutes,responsible_user_id,started_at,ended_at), remplacés par un champdescriptionlibre. La progression pendant la conduite en direct (pending/actif/terminé) est désormais suivie côté client, sans persistance par point.
Corrections
- Garde de transition Draft → Live : l'ouverture de la page Live (
GET /meetings/{id}/live) ne transitionne plus que les réunionsscheduledverslive; une réuniondraftouverte directement en Live restedraftau lieu d'être basculée à tort.
0.14.0.0 — 2026-05-29
Ajouts
- Gestion des documents officiels de l'association : les administrateurs peuvent désormais déposer et supprimer les statuts et le règlement intérieur depuis les paramètres de l'association. Les documents sont stockés de façon privée sur S3 (Clever Cloud Cellar) avec des URLs temporaires signées (30 min). Un seul document actif par type est conservé ; un nouvel upload archive automatiquement le précédent.
- Consultation des documents depuis le formulaire public d'inscription : quand un document officiel est disponible, un lien « Lire les statuts » / « Lire le règlement intérieur » apparaît dans le formulaire d'inscription (étape Identité). Le lien reste accessible même si la campagne est clôturée, mais expire avec le token d'inscription.
- Audit de cohérence S3/DB (
php artisan documents:audit) : commande hebdomadaire qui détecte et peut supprimer (--delete) les fichiers orphelins présents sur S3 mais absents de la base de données.
Corrections
- ConfirmDialog : suppression silencieuse sur toute l'application :
ConfirmDialog.vueémettaitupdate:open(false)avantconfirm, ce qui effaçait l'identifiant de la ressource à supprimer avant que le handler parent ne soit exécuté. La suppression ne déclenchait jamais la requête serveur. Correction :confirmest émis en premier. Ce bug affectait les 17+ utilisations deConfirmDialogdans l'app (membres, groupes, réunions, documents, etc.). - Liens documents non cliquables dans le formulaire d'inscription public : les liens « Lire les statuts / règlement » utilisaient le composant
<Link>d'Inertia qui appellepreventDefault(), empêchant l'ouverture du PDF. Rétablis en<a target="_blank">.
0.13.2.1 — 2026-05-25
Modifications
- Documentation synchronisée avec le code : audit complet de
Docs/— corrections des décalages entre la documentation et l'implémentation réelle (enumPaymentMethod, statutAbandoned, champreply_to_emailvsemail, contrainterna VARCHAR(10), formatregistration_idsdans les exemples HelloAsso, champtranscriptdes réunions, routes actives des membres). Le fichierDocs/Development/Multi-Tenant-TODOs.mdest archivé dansDocs/Archive/. - Plans et specs gstack déplacés hors dépôt : les fichiers de planification générés par les outils IA (
Docs/superpowers/) sont désormais stockés hors du dépôt et n'apparaissent plus dans les diffs de PR.
0.5.5.0 — 2026-04-30
Ajouts
WaterPoloSeeder: seeder de démo pour l'association "Cholet Water-Polo" (demo-cholet-waterpolo), support de la démo alpha pour Laurent LECLERC (DG) et Charles PRÉVOST (trésorier). Crée un environnement complet de club aquatique : 70 membres (4 bureau avec comptes admin, 8 membres expirés 2024-2025, 26 adultes solo, 8 familles Cas 1 avec enfants, 4 familles Cas 2 avec parent non-membre), 3 cours actifs 2025-2026 (Adultes lundi+mercredi, U18 mardi+samedi, Jeunes mercredi+samedi) avec créneaux horaires et coach salarié, rubrique de cotisation FFN-compatible (adulte 85€, jeune 55€, dirigeant 40€) avec remise famille −10%, 3 groupes organisationnels (Bureau, Section Adultes, Section Jeunes), et 4 réunions de bureau (3 clôturées avec CRs + 1 planifiée). Le seeder est idempotent et recrée uniquement les réunions viarefreshDemoMeetings()si l'association existe déjà.
0.5.4.0 — 2026-04-30
Ajouts
EpgvSeeder: seeder de démo pour l'association "EPGV 44 — Vitafédé" (demo-epgv-44), utilisé pour le comité directeur du 19 mai 2026. Crée un environnement de démo complet : 4 membres bureau avec comptes utilisateurs (Annick AUDUREAU, Marie-Noëlle NIVEAU, Joëlle POIRIER, Pierre-Yves GARNIER), 4 membres comité directeur, 15 licenciés génériques (~25 au total), 3 groupes organisationnels (Bureau, Conseil d'Administration, Commission Vitafédé), et 4 réunions (3 Completed avec CRs + 1 Scheduled le 19 mai — réunion de démo live). Le seeder est idempotent : si l'association existe déjà, il recrée uniquement les réunions viarefreshDemoMeetings()en préservant membres et licences.
0.5.1.1 — 2026-04-28
Ajouts
- Responsables légaux dans les fiches enfants : les 60 enfants mineurs seedés (familles Cas1 et Cas2 du ClubAssoSeeder) ont désormais un responsable légal rattaché — père ou mère selon la parité, non-membre pour Cas2. Le tab "Responsables légaux" de PersonIdentityTab n'est plus vide en démo.
- Exceptions de créneaux : le calendrier du ClubAssoSeeder inclut maintenant deux exceptions — une annulation passée (Judo Loisir lundi, il y a 3 semaines, travaux électriques) et un report futur (Judo Enfant mercredi → jeudi dans 2 semaines, salle modifiée). La feature de gestion des exceptions est visible dès le premier démarrage de la démo.
- Diversité des statuts d'inscription : parmi les 56 adultes solo du ClubAssoSeeder, 3 inscriptions illustrent désormais des statuts distincts :
PendingValidation(en attente de validation),Cancelled(annulée) etDraft(brouillon non soumis). Le cycle de vie complet d'une inscription est maintenant représenté. - Réunions enrichies : les trois seeders de démo (ClubAsso, DemoLigue56, AssoCultureSeeder) alignent leurs réunions sur le cycle complet v0.5 — statuts, participants, compte-rendus validés, actions assignées,
next_meeting_at, et transcription Voxtral pour ClubAsso.
Corrections
- Dates Carbon des exceptions de créneaux :
next('Monday')remplacé parprevious('Monday')pour garantir une date passée même quand aujourd'hui est un lundi. La date de report (mercredi → jeudi) utilise désormais une variable partagée pour éviter toute divergence si le seeder s'exécute en chevauchement de minuit.