Journal des modifications
Les évolutions de Cohez.io, de la plus récente à la plus ancienne.
173 versions publiées.
Versions 141 à 150 sur 173
0.5.10.0 — 2026-05-06
Ajouts
- Sélecteur de saison sur la liste des cours : un menu déroulant apparaît automatiquement quand plusieurs saisons existent, permettant de naviguer entre les saisons sans quitter la page. Le badge de statut (active / brouillon / clôturée) est affiché pour chaque saison.
- Sélection de saison par URL : le paramètre
?season=<uuid>permet de partager ou mémoriser le lien vers une saison précise. Les UUIDs invalides ou appartenant à un autre tenant sont silencieusement ignorés. - Saison par défaut intelligente : la saison dont les dates encadrent aujourd'hui est sélectionnée en priorité ; à défaut, la saison la plus récente (y compris clôturée) est utilisée.
0.5.9.0 — 2026-05-05
Ajouts
- Nettoyage S3 automatique : quand un document est remplacé par une nouvelle version, l'ancien fichier est désormais supprimé du stockage Cellar. Les fichiers obsolètes n'accumulent plus d'espace.
Modifications
- Téléchargement via URL pré-signée : les téléchargements de documents (paramètres et admin) passent par une URL temporaire Cellar (5 min) avec
Content-Disposition: attachment— le fichier se télécharge directement depuis Cellar sans transiter par le serveur PHP. - Chemins de stockage par slug : les nouveaux fichiers uploadés via Filament sont stockés sous
tenants/{slug}/au lieu detenants/{id}/, ce qui rend les chemins lisibles dans la console Cellar.
Corrections
- Injection HTTP via
Content-Disposition: le nom de fichier original était intégré verbatim dans l'en-têtefilename="...". Les caractères",\, CR et LF sont maintenant sanitisés pour prévenir l'injection d'en-têtes HTTP. - Timing de l'observer : l'observer passait de
creating(avant INSERT) àcreated(après INSERT) — évite de supprimer l'ancien fichier S3 si la transaction échoue. L'exclusionwhere('id', '!=', $document->id)empêche l'auto-supersession du nouveau document. - Bouton de téléchargement sur documents archivés : le bouton de téléchargement dans Filament est maintenant masqué pour les documents ayant un
superseded_at, évitant de générer des URLs signées pour des fichiers potentiellement supprimés.
0.5.8.0 — 2026-05-05
Ajouts
- Gestion documentaire par tenant : les admins de la plateforme peuvent uploader des PDFs (contrat, CPV, DPA…) via Filament → page Tenant → onglet Documents. Le nom du document est libre et le nom de fichier d'origine est conservé.
- Archivage automatique : uploader un document portant le même nom archive silencieusement l'ancien (
superseded_at). Plus besoin de supprimer manuellement. - Téléchargement depuis les paramètres : les membres avec la permission
VIEW_SETTINGSvoient et téléchargent les documents actifs depuis Paramètres › Mon association. - Téléchargement admin sécurisé : les liens de téléchargement dans Filament sont des URLs signées (HMAC, validité 30 min) qui streament le PDF sans exposer le chemin S3.
- Stockage S3 privé : disk
documentsconfiguré sur Cellar Clever Cloud en prod, MinIO en dev (console : http://localhost:9001).
Corrections
buildTemporaryUrlsUsingcourt-circuité par le vendor :AwsS3V3Adapter::temporaryUrl()de Flysystem surcharge la méthode parente sans honorer le callback enregistré viaStorage::buildTemporaryUrlsUsing(). Solution : génération directe deURL::temporarySignedRoute()dans leRelationManager; la configuration morte dansAppServiceProvidera été retirée.- Vérification de permission manquante :
AssociationController::downloadDocument()n'exigeait pasVIEW_SETTINGS— n'importe quel utilisateur authentifié pouvait télécharger. Ajout deabort_unless(VIEW_SETTINGS, 403). - Rôle MEMBRE avait
VIEW_SETTINGS: la permission a été retirée duRoleSeeder. Seuls les rôles avec accès paramètres (Admin, Secrétaire…) conserventVIEW_SETTINGS. - Badge « Statut » vide dans Filament v4 :
->badge()ignore le rendu quand la colonne brute estnull, même avecformatStateUsing. Corrigé avec->state(fn($r) => ...)pour calculer la valeur avant l'évaluation Filament.
0.5.7.0 — 2026-05-04
Modifications
- Migration TypeScript 6 : passage de TypeScript 5 à 6.0.3. Les génériques
usePage<T>()remplacés par des assertions de type explicites sur les computed, les paramètres Wayfinder multi-routes corrigés en syntaxe objet{ param: value }, et les types implicites annotés explicitement. - Migration ESLint 10 : passage de ESLint 9 à 10.3.0,
@eslint/js9 → 10,eslint-plugin-vue9 → 10. La configuration flat config existante reste compatible. - Migration vue-tsc v3 : passage de vue-tsc 2 à 3.2.8 (Volar language-tools), avec alignement de
@vue/language-coresur la même version. - Déclaration ambiante LaunchKit : extraction de la déclaration de module
https://esm.sh/@bworlds/launchkit@1dans un fichier dédiélaunchkit.d.tssans imports (requis en TS6 pour les modules URL). - Types AppPageProps : ajout de l'interface
Tenantet du champ optionneltenant?dans les props globales, exposant le nom du tenant côté frontend. - Script
typecheck: ajout devue-tsc --noEmitcomme script npm pour vérification des types en CI.
Corrections
MemberUsers/Index.vue: affichage du nom des utilisateurs membres corrigé (memberUser.member.first_nameau lieu dememberUser.first_name, qui était toujoursundefined).TwoFactorChallenge.vue: importuseTranslationsmanquant ajouté.TwoFactorSetupModal.vue: ajout deerror-bag="confirmTwoFactorAuthentication"sur le<Form>Inertia pour queerrors?.codesoit correctement scopé au named bag Fortify.OrganizationalGroupController: description utilise(?? null) ?: nullpour convertir la chaîne vide ennullsans déclencher d'avertissement PHP quand le champ est absent.types/index.d.ts: ajout du champslugmanquant sur l'interfaceTenant.Integrations/Show.vue: typeflashcomplété avecerror?: string.
0.5.6.0 — 2026-05-04
Ajouts
- Liaison proposition ↔ cours : une proposition de cotisation peut désormais être rattachée à un cours de la saison en cours. Le formulaire de création et d'édition d'une proposition expose un sélecteur de cours (
CourseSelect.vue— composant réutilisable). La valeur est persistée en base (course_id) et renvoyée au frontend (courseId,courseName). - Campagnes liées sur la fiche cours : l'onglet détail d'un cours affiche désormais les campagnes ouvertes dont au moins une proposition est reliée à ce cours (
linkedCampaigns). Seules les campagnes actives (statutOpen) apparaissent ; les doublons (un cours lié via plusieurs propositions de la même campagne) sont dédupliqués. - Bouton "Cours" dans la liste des saisons : chaque ligne de saison propose un lien direct vers les cours associés, dans
settings/Seasons/Index.vue. EpgvSeeder— cours démo : deux cours EPGV (Gym Douce et Pilates) avec créneaux hebdomadaires, rattachés à la campagne de cotisation 2025-2026. Douze membres inscrits répartis entre les deux cours.
Modifications
CourseSelect.vue: le sélecteur de cours extrait en composant réutilisable depuisPropositionRow.vueetRubriqueCard.vue. Gère le sentinel__none__, le label conditionnel et l'état désactivé (aucun cours dans la saison).
Corrections
UpdatePropositionRequest— contrainteseason_idsurcourse_id: la validationRule::existsvérifie maintenant leseason_idde la rubrique parente, alignant la mise à jour sur la création. Uncourse_idd'une autre saison était accepté en update.- Champ
course_id— valeur vide interdite : le formulaire utilisait une chaîne vide''comme valeur "aucun cours", rejetée par Reka UISelectItem. Remplacement par le sentinel__none__converti ennullcôté serveur.
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.3.0 — 2026-04-30
Ajouts
- BWORLDS LaunchKit : monitoring temps réel, page de statut publique et session replay désormais actifs. Le SDK se charge depuis le CDN sans alourdir le bundle JS.
0.5.2.0 — 2026-04-29
Ajouts
MoneyFormatter::toDecimal(Money): float: nouveau helper centralisé pour convertir un objetMoneyen euros décimaux. Remplace les 14 expressions inline(int)->getAmount()/100disséminées dans les controllers.- Trait
HasMoneyAmount(app/Http/Requests/Concerns/) : mutualise la logiqueprepareForValidation()euro→centimes pourStorePaymentRequest,StorePropositionRequestetUpdatePropositionRequest.
Modifications
- Unification des types monétaires : le VO domaine
Registration\Domain\ValueObjects\Moneyest supprimé. Les entitésRegistrationetPayment(couche domaine DDD) utilisent directementMoney\Money(moneyphp), alignant la couche domaine avec la couche Eloquent. - Mappers simplifiés :
RegistrationMapperetPaymentMapperpassent désormais$model->amount_due/$model->amountdirectement aux entités sans conversion intermédiaire.
Corrections
prepareForValidation()— guardis_numeric(): ajout d'un contrôleis_numeric()avantMoneyFormatter::parseDecimal()dans les 3 FormRequests. Une chaîne non numérique ne déclenchera plus uneParserExceptionnon gérée (HTTP 500).- Plafond de validation monétaire : règle
max:999999999ajoutée sur les champsamountdes 3 FormRequests pour rejeter des valeurs absurdes. MoneyCast::get()— valeur non numérique en base : lève désormaisUnexpectedValueExceptionsi la valeur DB n'est pas numérique, au lieu de retourner silencieusementMoney(0).MoneyCast::set(): lève désormaisInvalidArgumentExceptionsur une valeur non numérique et nonMoneyau lieu d'un cast silencieux(int).HasMoneyAmount— montant zéro : remplacement defilled()par!== nulldansprepareForValidation().filled(0)retournantfalse, une proposition à 0,00 € skippait la conversion euro→centimes et échouait à la validationintegeravec un message cryptique.StoreRegistrationRequest— ajustement zéro : même correction pouradjustment_amount: un ajustement à 0 est maintenant converti (0 centimes) au lieu d'être ignoré.MoneyFormatter::parseDecimal()— cache statique :DecimalMoneyParseretISOCurrenciessont instanciés une seule fois par process (lazy static) au lieu d'être recréés à chaque appel.Registration::totalPaid— mise en cache : l'attribut Eloquent utilise->shouldCache()pour éviter de ré-itérer la collectionpaymentsà chaque accès (typiquement 3× par ligne dans les vues liste).
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.