Journal des modifications
Les évolutions de Cohez.io, de la plus récente à la plus ancienne.
14 versions correspondent à « réunion ».
Versions 11 à 14 sur 14
0.5.1.0 — 2026-04-28
Ajouts
- Transcription en temps réel (Voxtral) : pendant une réunion en direct, le bouton micro capture l'audio par chunks de 4 s et les envoie à Mistral Voxtral via un job en file d'attente. La transcription s'accumule dans le champ
transcriptde la réunion et est visible dans le compte-rendu final. - Provider de transcription configurable :
config/ai.phpexposedefault_for_transcription(valeur par défaut :mistral) pour faciliter le changement de provider sans toucher au code. - Transcription dans le compte-rendu : si une transcription est disponible, elle est incluse dans le compte-rendu généré (section dédiée, formatée en bloc citation pour éviter toute injection Markdown).
- Robustesse micro : les chunks vides (micro muet, coupure réseau) sont filtrés avant envoi — aucune requête inutile vers l'API, pas de transcription parasite. Capture du segment EBML WebM garantie avant le filtre de taille.
Corrections
- CSRF 419 sur
transcribe-chunk: Inertia ne génère pas de balise<meta name="csrf-token">— corrigé en lisant le cookieXSRF-TOKENvia l'en-têteX-XSRF-TOKEN(mécanisme natif Laravel/Sanctum). - Isolation tenant sur le job de transcription : la clause
WHERE tenant_id = ?garantit qu'un job ne peut pas écrire dans la réunion d'un autre tenant même en cas de collision d'ID. - Stockage privé des chunks audio : forçage du disque
local(privé) pour les fichiers audio temporaires — ils n'étaient pas exposés via URL publique dans le précédent comportement, mais cette garantie est maintenant explicite. - Nettoyage des fichiers audio orphelins : le fichier temporaire est désormais supprimé dans
failed()en plus dufinallydehandle()— évite l'accumulation sur le FS Bucket en cas de SIGKILL du worker. - Throttle
liveTranscript: le polling de transcription est limité à 30 req/min pour limiter la charge base de données. - Validation MIME des chunks : liste blanche stricte (
audio/webm,audio/ogg,audio/wav, etc.) — les formats non reconnus reçoivent une 422. - Race condition post-arrêt enregistrement : les chunks reçus après l'appel à
stopRecording()sont ignorés pour éviter les doubles uploads. - Accessibilité bouton micro : suppression de l'
aria-labelstatique qui écrasait le texte dynamique visible (violation WCAG 2.5.3).
0.5.0.0 — 2026-04-23
Ajouts
- Réunion en direct (Live) : nouvelle page de conduite de réunion en temps réel avec timer, navigation entre points de l'ordre du jour et affichage du temps écoulé. Chaque point peut être démarré, décidé et clôturé individuellement.
- Actions de réunion : les animateurs peuvent créer des actions (tâches) sur chaque point de l'ordre du jour en séance, avec titre, responsable et date d'échéance.
- Compte-rendu automatique : à la clôture d'une réunion, un compte-rendu Markdown est généré automatiquement à partir des décisions et actions enregistrées. La date de la prochaine réunion peut être saisie lors de la clôture.
- Export PDF du compte-rendu : les CR validés sont exportables en PDF avec mise en forme professionnelle (logo, titre, présences, ordre du jour, décisions, actions).
- Envoi email du compte-rendu : envoi idempotent du CR validé à tous les participants disposant d'une adresse email, avec protection contre les doublons d'envoi.
- Recherche de décisions : nouvelle page de recherche full-text (GIN index PostgreSQL) dans les décisions de toutes les réunions clôturées.
- Actions sur fiche membre : la fiche d'un membre affiche désormais les actions de réunion qui lui sont assignées, avec lien vers la réunion concernée.
- Enrichissement de l'ordre du jour : chaque point de l'ordre du jour accepte une durée estimée (1–480 min) et un responsable utilisateur ; le formulaire de création/édition expose ces champs.
Modifications
- Formulaire d'édition des réunions : l'ordre du jour est masqué et exclu de la soumission pour les réunions en cours (
live) ou clôturées (completed), évitant les erreurs 422. - Statut
livedans l'interface : les pages Index et Show affichent maintenant le statutliveavec un badgewarning; le type TypeScript est mis à jour en conséquence. - Validation
storeAction: le champresponsible_user_idest désormais validé et limité aux utilisateurs du tenant courant. emailReportatomique : l'envoi est protégé contre les doublons par unUPDATE … WHERE NULLatomique plutôt qu'une lecture puis écriture.- Email CR : le contenu Markdown du compte-rendu est converti en HTML avant envoi, les destinataires voient le texte formaté plutôt que la syntaxe brute.
Corrections
- Watcher Vue (
AgendaItemPanel) :[...undefined]corrigé en[...(item.actions ?? [])]lorsque la réponse API ne retourne pas la relationactions. - Réponse
updateAgendaItem: charge désormaisactions.responsibleavant de sérialiser, évitant les erreurs côté client. - Clé de pagination
v-fordans Decisions.vue rendue unique (label + url).
0.4.7.0 - 2026-04-22
Corrections
- Sécurité multi-tenant :
MeetingReportmanquait le traitBelongsToTenant— les comptes-rendus n'étaient pas filtrés par tenant. Migration de backfill ajoutée (tenant_idsurmeeting_reports). - Injection cross-réunion : il était possible d'envoyer l'ID d'un participant d'une autre réunion dans
updateAttendance. La validationRule::existsscopée surmeeting_idbloque désormais ces requêtes au niveau FormRequest. - N+1 sur la présence : les mises à jour de présence faisaient une requête SQL par participant. Remplacé par
batchUpdateAttendance()qui groupe les UPDATE par statut. - Dégradation du statut de rapport : fermer une réunion avec des notes écrasait silencieusement un rapport
ValidatedenDraftviaupdateOrCreate. Remplacé par un create/update explicite qui préserve le statut existant. - Double validation : il était possible de valider un rapport déjà validé. Garde
abort_unless(Draft)ajoutée. - Contenu vide validé : un rapport sans contenu (ou contenu en espaces) pouvait être validé. Garde
abort_if(blank())ajoutée. - Annulation impossible : tenter d'annuler une réunion déjà terminée ou annulée renvoyait une erreur non gérée. Retourne maintenant 422.
- Réactivité Vue : le contenu du rapport ne se synchronisait pas après une navigation Inertia. Watch ajouté sur
props.meeting.report?.content.
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 lesconfirm()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 automatiquementflash.successetflash.errordepuis les props Inertia partagées. Intégré dansAppSidebarLayout. - 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 duonUnmountedpour nettoyer le timer, ajout debreak-wordssur le message pour éviter l'overflow sur les messages longs.