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 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 de tenants/{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ête filename="...". 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'exclusion where('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_SETTINGS voient 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 documents configuré sur Cellar Clever Cloud en prod, MinIO en dev (console : http://localhost:9001).

Corrections

  • buildTemporaryUrlsUsing court-circuité par le vendor : AwsS3V3Adapter::temporaryUrl() de Flysystem surcharge la méthode parente sans honorer le callback enregistré via Storage::buildTemporaryUrlsUsing(). Solution : génération directe de URL::temporarySignedRoute() dans le RelationManager; la configuration morte dans AppServiceProvider a été retirée.
  • Vérification de permission manquante : AssociationController::downloadDocument() n'exigeait pas VIEW_SETTINGS — n'importe quel utilisateur authentifié pouvait télécharger. Ajout de abort_unless(VIEW_SETTINGS, 403).
  • Rôle MEMBRE avait VIEW_SETTINGS : la permission a été retirée du RoleSeeder. Seuls les rôles avec accès paramètres (Admin, Secrétaire…) conservent VIEW_SETTINGS.
  • Badge « Statut » vide dans Filament v4 : ->badge() ignore le rendu quand la colonne brute est null, même avec formatStateUsing. 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/js 9 → 10, eslint-plugin-vue 9 → 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-core sur la même version.
  • Déclaration ambiante LaunchKit : extraction de la déclaration de module https://esm.sh/@bworlds/launchkit@1 dans un fichier dédié launchkit.d.ts sans imports (requis en TS6 pour les modules URL).
  • Types AppPageProps : ajout de l'interface Tenant et du champ optionnel tenant? dans les props globales, exposant le nom du tenant côté frontend.
  • Script typecheck : ajout de vue-tsc --noEmit comme script npm pour vérification des types en CI.

Corrections

  • MemberUsers/Index.vue : affichage du nom des utilisateurs membres corrigé (memberUser.member.first_name au lieu de memberUser.first_name, qui était toujours undefined).
  • TwoFactorChallenge.vue : import useTranslations manquant ajouté.
  • TwoFactorSetupModal.vue : ajout de error-bag="confirmTwoFactorAuthentication" sur le <Form> Inertia pour que errors?.code soit correctement scopé au named bag Fortify.
  • OrganizationalGroupController : description utilise (?? null) ?: null pour convertir la chaîne vide en null sans déclencher d'avertissement PHP quand le champ est absent.
  • types/index.d.ts : ajout du champ slug manquant sur l'interface Tenant.
  • Integrations/Show.vue : type flash complété avec error?: 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 (statut Open) 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 depuis PropositionRow.vue et RubriqueCard.vue. Gère le sentinel __none__, le label conditionnel et l'état désactivé (aucun cours dans la saison).

Corrections

  • UpdatePropositionRequest — contrainte season_id sur course_id : la validation Rule::exists vérifie maintenant le season_id de la rubrique parente, alignant la mise à jour sur la création. Un course_id d'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 UI SelectItem. Remplacement par le sentinel __none__ converti en null cô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 via refreshDemoMeetings() 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 via refreshDemoMeetings() 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 objet Money en euros décimaux. Remplace les 14 expressions inline (int)->getAmount()/100 disséminées dans les controllers.
  • Trait HasMoneyAmount (app/Http/Requests/Concerns/) : mutualise la logique prepareForValidation() euro→centimes pour StorePaymentRequest, StorePropositionRequest et UpdatePropositionRequest.

Modifications

  • Unification des types monétaires : le VO domaine Registration\Domain\ValueObjects\Money est supprimé. Les entités Registration et Payment (couche domaine DDD) utilisent directement Money\Money (moneyphp), alignant la couche domaine avec la couche Eloquent.
  • Mappers simplifiés : RegistrationMapper et PaymentMapper passent désormais $model->amount_due / $model->amount directement aux entités sans conversion intermédiaire.

Corrections

  • prepareForValidation() — guard is_numeric() : ajout d'un contrôle is_numeric() avant MoneyFormatter::parseDecimal() dans les 3 FormRequests. Une chaîne non numérique ne déclenchera plus une ParserException non gérée (HTTP 500).
  • Plafond de validation monétaire : règle max:999999999 ajoutée sur les champs amount des 3 FormRequests pour rejeter des valeurs absurdes.
  • MoneyCast::get() — valeur non numérique en base : lève désormais UnexpectedValueException si la valeur DB n'est pas numérique, au lieu de retourner silencieusement Money(0).
  • MoneyCast::set() : lève désormais InvalidArgumentException sur une valeur non numérique et non Money au lieu d'un cast silencieux (int).
  • HasMoneyAmount — montant zéro : remplacement de filled() par !== null dans prepareForValidation(). filled(0) retournant false, une proposition à 0,00 € skippait la conversion euro→centimes et échouait à la validation integer avec un message cryptique.
  • StoreRegistrationRequest — ajustement zéro : même correction pour adjustment_amount : un ajustement à 0 est maintenant converti (0 centimes) au lieu d'être ignoré.
  • MoneyFormatter::parseDecimal() — cache statique : DecimalMoneyParser et ISOCurrencies sont 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 collection payments à 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) et Draft (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é par previous('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.