- ajoute la regle ^/api/mail avant ^/api pour expliciter l'authentification requise
- les checks fins ROLE_USER vs ROLE_CLIENT restent dans MailAccessChecker (chaque controller)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- dispatch MailSyncRequested au bus Messenger, retourne 202 immediat
- folderPath optionnel via body JSON pour sync ciblee
- en test : transport in-memory route le message en sync
- securite via MailAccessChecker
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- App\Message\MailSyncRequested (optionnel folderPath)
- App\MessageHandler\MailSyncRequestedHandler delegue a MailSyncService::syncFolder ou syncAll
- messenger.yaml : transport async via Doctrine DSN, retry 3x exponentiel, failure transport
- en test : transport in-memory (sync immediat)
- migration Version20260519220000 : cree messenger_messages table (idempotente, IF NOT EXISTS)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- downloadId = base64url(messageDbId:partNumber)
- Content-Disposition: attachment systematique (jamais inline pour eviter XSS via HTML attachments)
- X-Content-Type-Options: nosniff
- filename sanitise via basename pour eviter path traversal
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- POST /api/mail/messages/{id}/link-task body {taskId} : cree TaskMailLink (idempotent)
- DELETE /api/mail/messages/{id}/link-task/{taskId} : supprime le lien (204)
- GET /api/tasks/{id}/mails : liste les mails lies a une tache
- securite via MailAccessChecker, tests fonctionnels 401/403
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- cree une Task avec titre = subject du mail (max 255 chars)
- utilise findMaxNumberByProjectForUpdate pour numero (advisory lock PG)
- transaction wrapInTransaction pour eviter race conditions
- taskGroupId et priorityId optionnels via body JSON
- cree automatiquement le TaskMailLink (mail <-> tache)
- retourne 201 + taskId/taskNumber/taskTitle/messageId
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- POST /api/mail/messages/{id}/read body {read: bool} - synchro IMAP + BDD
- POST /api/mail/messages/{id}/flag body {flagged: bool} - synchro IMAP + BDD
- IMAP-side non bloquant : BDD est mise a jour meme si IMAP fail (resync au prochain cycle)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- recupere headers + body + attachments via ImapMailProvider::fetchMessage
- cache Symfony pool cache.app, cle mail_body_{md5(messageId)}, TTL 300s
- attachments serialises sans contenu binaire, avec downloadId base64url(messageDbId:partNumber)
- 503 si IMAP indisponible, 404 si message inconnu
- les tests read/flag ROLE_CLIENT/auth seront ajoutes en Task 10 (route deja existante)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ensureCanAccessMail : refuse ROLE_CLIENT pur (sans ROLE_ADMIN)
- ensureIsAdmin : helper pour endpoints config
- service utilise par tous les controllers metier mail
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- endpoint ROLE_ADMIN qui teste la connexion IMAP via listFolders
- retourne ok:bool + foldersCount ou error sanitise (pas de leak interne)
- priority:1 obligatoire pour eviter conflit avec route API Platform {id}
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ApiResource MailSettings expose les operations Get + Patch sur /api/mail/configuration
- Provider + Processor relient le DTO a l'entite MailConfiguration (singleton)
- password en write-only (jamais retourne) + hasPassword en lecture
- chiffrement password via TokenEncryptor (sodium)
- securite ROLE_ADMIN sur les deux operations
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ajoute symfony/messenger ^8.0 et symfony/doctrine-messenger ^8.0 pour la sync mail async
- ajoute symfony/browser-kit + css-selector en dev pour tests fonctionnels WebTestCase
- ENCRYPTION_KEY ajoutee dans phpunit.dist.xml pour permettre le chiffrement en test
- MESSENGER_TRANSPORT_DSN configure (Doctrine), messenger.yaml minimal (sera enrichi en Task 12)
- fix(orm) : ClientTicket - migre uniqueConstraints en attribut separe (Doctrine ORM 4 deprecation)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend :
- POST /api/me/regenerate-api-token : nouveau controller, ROLE_USER (exclut CLIENT)
- User.apiToken exposé via groupe me:read sur GET /api/me
Frontend :
- Section 'Token API MCP' sur /profile (masquée pour les CLIENT du portail)
- Boutons Copier + Régénérer avec modal de confirmation
- Service api-token + DTO mis à jour + clés i18n fr
- Pousse les filtres projet et tag a l'API (au lieu d'un filtrage client-side
partiel sur la page courante) pour eviter les resultats incomplets en cas
de pagination
- Ajoute les watchers selectedProjectId/selectedTagId qui declenchent un reload
- Mode liste : navigation et plage de chargement passent a 1 mois (au lieu
d'une fenetre de 7 jours qui rendait le mode liste inutilisable)
- Renomme l'option vide du filtre User en "Tous" (etait "User", ambigu)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
En mode kanban, selectionner un statut dans le filtre Status vidait toutes
les autres colonnes ET le backlog (tasks?.status?.id !== selectedId) : le
filtre etait redondant avec les colonnes et cassait la vue.
Conditionne l'affichage du filtre Status a viewMode === 'list' et reset le
filtre lors du retour en kanban.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Avant, seul le KPI "Heures sur la periode" reagissait au filtre Utilisateur ;
"Taches totales", "Mes taches actives" et tous les graphiques tache restaient
inchanges. Le computed tasks ne filtrait que par projet, et myTasks etait
hardcode sur auth.user.id (cf ticket LST40).
Ajoute un effectiveUserId (selectedUser ?? auth.user) et applique le filtre
user a tasks pour propager dans tous les charts et KPIs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Le rich text editor étant désormais fourni par @malio/layer-ui, les
dépendances @tiptap/* et tiptap-markdown directes dans Lesstime
(héritage de l'ancien éditeur local) ne servent plus et causaient un
doublon de tiptap-markdown (0.8.10 + 0.9.0) qui faisait planter
l'init Nuxt avec une erreur d'export default sur markdown-it-task-lists.
- Suppression des deps @tiptap/extension-link, @tiptap/extension-placeholder,
@tiptap/pm, @tiptap/starter-kit, @tiptap/vue-3, tiptap-markdown
- Ajout de markdown-it-task-lists à vite.optimizeDeps.include pour
forcer Vite à gérer correctement l'interop CJS du module
Co-Authored-By: RuFlo <ruv@ruv.net>
Inclut les couleurs de texte et surlignage façon Jira dans
<MalioInputRichText> (toolbar étendue avec popover en palette).
Co-Authored-By: RuFlo <ruv@ruv.net>