Commit Graph

541 Commits

Author SHA1 Message Date
Matthieu
5da165f739 docs : corrige le déploiement prod (Docker) et documente les variables d'env mail
- README : section Variables d'environnement (ENCRYPTION_KEY, LOCK_DSN) + section Déploiement passée au flow Docker (deploy.sh)
- mail-cron-setup : sépare dev (make, php-lesstime-fpm) et prod (lesstime-app, docker compose exec), cron prod réel
- infra/prod/.env.example : ajoute ENCRYPTION_KEY et LOCK_DSN (manquaient, requis pour la sync mail)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:48:55 +02:00
gitea-actions
2bffff9b83 chore: bump version to v0.4.4
All checks were successful
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 57s
v0.4.4
2026-05-21 08:48:41 +00:00
d7af8ee138 Correctifs UI workflow — specs + implémentation (8 chantiers) (#6)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Suite à l'arrivée des workflows, correction des régressions UI et améliorations UX mail/modales (reviews Lucile Schnödt, Tristan Schnödtin).

**Specs & décisions :** `docs/superpowers/specs/2026-05-20-workflow-ui-fixes-design.md`
**Plan d'implémentation :** `docs/superpowers/plans/2026-05-21-workflow-ui-fixes.md`

Cette PR contient désormais **les specs ET l'implémentation complète**.

## Chantiers livrés

| # | Chantier | Détail |
|---|----------|--------|
| 2 | Sélecteur de statut filtré par workflow | `statusOptions` dérivé de `project.workflow.statuses`, statut courant conservé s'il est hors workflow |
| 1 | Drag & drop « Mes tâches » | handlers `@dragover/@drop` ; résolution par workflow/catégorie (0→refus, 1→PATCH, ≥2→popover `StatusPickerPopover`) |
| 4 | Couleurs | (a) migration Doctrine remettant les hex classiques sur le workflow Standard ; (b) entêtes kanban teintées via `STATUS_CATEGORY_COLOR` + contraste auto ; (c) couleur par défaut par catégorie dans `WorkflowDrawer` |
| 5 | Suppression du bouton « Lier un mail » | + retrait de `MailPickerModal` et i18n associée |
| 6 | Création de tâche depuis un mail | back : `assigneeId` + `statusId` (défaut = 1er statut du workflow), priorité retirée (TDD) ; front : `MailCreateTaskModal` sur `AppModal` + sélecteurs user/statut |
| 7 | Modale réutilisable | nouveau `components/ui/AppModal.vue` (footer sticky) ; footer de `TaskModal` sorti du form scrollable |
| 3 | Cartes responsive | badges en `flex-wrap` pleine taille (plus aucun débordement) |
| 8 | (dette) Sélecteur de catégorie en `MalioSelect` | la lib supporte les valeurs `string` ; note CLAUDE.md corrigée |

## Vérifications
- Build frontend OK ; PHPUnit **34 tests verts** (nouveau test fonctionnel TDD sur `create-task`).
- Vérif navigateur (Chrome MCP) sur **données prod importées en local** : #2, #3, #4, #5, #6, #7 confirmés.
- Revue de code finale : **APPROVED_WITH_NITS**.

## À noter
- ⚠️ **#1 (D&D)** : le drag & drop HTML5 natif n'est pas auto-testable → **test manuel requis**.
- 🗄️ **#4 (migration)** : `migrations/Version20260521094948.php` s'appliquera en **prod au prochain `make migration-migrate`**.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #6
2026-05-21 08:48:31 +00:00
gitea-actions
eb2adc9fdc chore: bump version to v0.4.3
All checks were successful
Build & Push Docker Image / build (push) Successful in 53s
Auto Tag Develop / tag (push) Successful in 7s
v0.4.3
2026-05-20 08:22:48 +00:00
Matthieu
4775cbf184 feat(ui) : palette de couleurs élargie + couleur personnalisée, fix champ code projet
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
ColorPicker : passe de 9 à 18 teintes prédéfinies (les 9 historiques
conservées en tête pour ne pas désassocier les couleurs existantes) et
ajoute une pastille « couleur personnalisée » (input natif type=color)
permettant n'importe quel hex. Partagé, donc bénéficie aussi aux tags,
priorités, groupes et workflows.

fix(project) : le champ code restait en minuscules. Le @input mutait
form.code à partir de l'ancienne valeur, puis l'émission update:modelValue
de MalioInputText l'écrasait avec la saisie brute → form.code en
minuscules (affiché en majuscules via CSS) → /^[A-Z]{2,10}$/ en échec →
création bloquée. Remplacé par un computed setter (source unique de
vérité : majuscules + lettres uniquement + max 10) et maxLength sur le
champ.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:22:38 +02:00
gitea-actions
8be96bce0c chore: bump version to v0.4.2
All checks were successful
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 27s
v0.4.2
2026-05-20 07:56:32 +00:00
Matthieu
fb97b8d4e3 fix(mail) : sync à la demande synchrone pour le bouton rafraîchir
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Route MailSyncRequested vers le transport sync au lieu d'async : la
synchro IMAP s'exécute pendant la requête HTTP du clic « rafraîchir »,
donc le re-fetch du front voit immédiatement les nouveaux mails, sans
worker messenger:consume à maintenir en prod. La sync de fond reste
assurée par le cron OS (app:mail:sync, synchrone, indépendant du bus).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 09:56:23 +02:00
gitea-actions
913d3b7d93 chore: bump version to v0.4.1
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 1m16s
v0.4.1
2026-05-20 07:48:17 +00:00
90bf46f598 Merge pull request 'feat(mail) : intégration mail OVH IMAP — boîte partagée, lecture, création/lien tâche' (#5) from feat/mail-integration into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Reviewed-on: #5
2026-05-20 07:45:31 +00:00
e5c5371c74 Merge branch 'develop' into feat/mail-integration 2026-05-20 07:45:09 +00:00
40a1d737f3 Merge pull request 'feat(help) : centre d'aide in-app /help avec 9 sections' (#4) from feat/in-app-help-doc into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Reviewed-on: #4
2026-05-20 07:44:43 +00:00
595b8f5be3 Merge pull request 'feat(workflow) : workflows de statuts par projet (kanban custom)' (#3) from feat/project-workflows into develop
All checks were successful
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 3m47s
Reviewed-on: #3
v0.4.0
2026-05-20 07:44:09 +00:00
a40d11503a feat(mail) : allège la barre d'actions du lecteur de mail
Boutons "Créer une tâche" / "Lier à une tâche" réduits (text-xs, padding compact),
suppression des actions "Marquer comme non lu" et "Marquer important".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:24:00 +02:00
760649170e docs : pointeur CLAUDE.md vers la doc d'intégration mail (reprise)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:22:36 +02:00
b0f05da84a docs(mail) : section "Statut & reprise" — handoff complet (bugs corrigés, points en suspens, commandes) pour reprise sur autre poste
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:22:11 +02:00
c75dfa0371 fix(mail) : synchro multi-dossiers fiable contre OVH
Trois causes racines révélées par une vraie synchro complète (139 dossiers) :
- contrainte UNIQUE globale sur message_id : fausse pour IMAP (un même Message-ID
  existe dans plusieurs dossiers) → violation → fermeture de l'EntityManager →
  cascade qui tuait tous les dossiers suivants. Migration : index simple à la place.
- 139 connexions IMAP (une par dossier) → throttling OVH (failed to authenticate) :
  réutilisation d'une seule connexion (closeConnection() ajouté à l'interface).
- état de connexion corrompu après un dossier en erreur (must be in SELECTED state) :
  reconnexion ciblée après chaque dossier en échec.
- garde anti-cascade : reset du ManagerRegistry + arrêt propre si l'EM se ferme.

Résultat : 456 messages sur 57 dossiers (avant : 188/30 puis crash). Les rares
dossiers à encodage spécial sont skippés proprement et réessayés au cycle suivant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:21:02 +02:00
c6fa5a534e feat(mail) : arbre des dossiers repliable — chevrons, sous-dossiers masqués par défaut
Seuls les dossiers racine sont affichés au départ ; chevron pour déplier/replier
chaque dossier ayant des sous-dossiers. Le clic sur le nom sélectionne toujours le dossier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:05:00 +02:00
17b5fa2340 fix(mail) : corrige le fetch IMAP réel contre OVH (listMessages cassé)
Quatre bugs révélés en testant contre une vraie boîte OVH (les tests mockaient
le provider, donc jamais exercés) :
- requête sans critère → "BAD parse error: zero-length content" : ajout de whereAll()
- getDate()/getSubject() renvoient des Attribute webklex v6, pas des scalaires : casts explicites
- séquence par défaut ST_MSGN → le peek() de webklex faisait un STORE par numéro de
  séquence rejeté par OVH ("flag could not be removed") : force ST_UID sur toutes les requêtes
- snippet via getTextBody() forçait un fetch de corps par mail (sync 179s + peek) :
  setFetchBody(false) au listing, snippet désormais optionnel

Sync INBOX : 9 messages en 1,6s (avant : échec en 179s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:57:17 +02:00
79d3414824 fix(mail) : aligne le contrat front/back pour le listing et le détail des messages
Le service appelait GET /mail/messages?folder=X (404) au lieu de la vraie route
/mail/folders/{path}/messages. Ajoute aussi une couche de mapping backend→DTO
(messages→items, fromAddress→fromEmail, toAddresses→toRecipients, détail plat→imbriqué)
pour réconcilier la dérive de contrat entre Phase 3 (API) et Phase 4 (DTOs front).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:46:21 +02:00
f313e74c9e fix(mail) : le test de connexion fonctionne même si la config est désactivée + remonte l'erreur IMAP réelle
Le guard enabled dans getClient() bloquait le test de connexion alors que le
workflow naturel est configurer → tester → activer. getClient(requireEnabled)
permet au nouveau testConnection() de se connecter sans exiger enabled=true.
Le controller (ROLE_ADMIN) renvoie désormais le détail de l'erreur pour faciliter
le diagnostic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:46:11 +02:00
7a682b4662 docs(mail) : checklist prod + sécurité, guide intégration complet, mention README 2026-05-20 00:59:31 +02:00
d6f430ca35 feat(mail) : clés i18n mail.sidebar.* + mail.admin.* (Phase 7) 2026-05-20 00:58:05 +02:00
4d7ff9be26 feat(mail) : sidebar — lien Messagerie + badge unread + polling lifecycle (start au login, stop au logout) 2026-05-20 00:57:41 +02:00
7c0d3372a9 feat(mail) : intègre onglet Mail dans pages/admin.vue 2026-05-20 00:57:19 +02:00
d36429f058 feat(mail) : AdminMailTab — form IMAP/SMTP/credentials + test connexion + indicateur hasPassword 2026-05-20 00:57:10 +02:00
28b673eec8 docs(mail) : plan détaillé Phase 7 — AdminMailTab, sidebar+badge, polling, doc finale (9 tasks)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:55:27 +02:00
bad292a316 feat(mail) : pages/mail.vue — branche handlers Phase 6 (MailCreateTaskModal + MailLinkTaskModal) 2026-05-20 00:50:31 +02:00
273234626f feat(mail) : onglet Mails dans TaskModal — liste mails liés, bouton lier, MailPickerModal 2026-05-20 00:49:57 +02:00
96c7d902e7 feat(mail) : MailPickerModal — sélection mail depuis dossier courant, liaison taskId 2026-05-20 00:48:37 +02:00
f62c790449 feat(mail) : MailLinkTaskModal — autocomplete tâches, filtre projet, debounce 300ms 2026-05-20 00:47:55 +02:00
13cec9a46a feat(mail) : MailCreateTaskModal — picker projet/groupe/priorité, appel createTaskFromMail 2026-05-20 00:47:08 +02:00
d676fdcb0c feat(mail) : clés i18n Phase 6 — createTaskModal, linkTaskModal, pickerModal, taskTab 2026-05-20 00:46:09 +02:00
bfcf712123 docs(mail) : plan détaillé Phase 6 — modals create/link task + onglet Mails dans TaskModal (8 tasks)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:44:26 +02:00
622fcf72c1 feat(mail) : page /mail — layout 3 colonnes, deep-link messageId, refus ROLE_CLIENT 2026-05-20 00:37:03 +02:00
67e73a52d7 feat(mail) : MailMessageViewer — header, body sanitizé DOMPurify, PJ téléchargeables, 4 actions 2026-05-20 00:36:29 +02:00
aa175063dc feat(mail) : MailMessageList — liste paginée infinite scroll, indicateurs lu/étoilé/PJ/date relative 2026-05-20 00:35:47 +02:00
9aa14d38a9 feat(mail) : MailFolderTree — arbre récursif dossiers, badges unread, icônes système 2026-05-20 00:35:19 +02:00
95a98012ad feat(mail) : MailRefreshButton — bouton sync manuel, disabled pendant syncing 2026-05-20 00:34:59 +02:00
535753b189 feat(mail) : composable useSystemFolderLabel — mapping dossiers système IMAP vers i18n + icônes 2026-05-20 00:34:46 +02:00
e710f57c49 feat(mail) : clés i18n mail.* (titres, vides, dossiers système, actions, erreurs) 2026-05-20 00:34:24 +02:00
73f0adc761 docs(mail) : plan détaillé Phase 5 — page /mail 3 colonnes + 4 composants (9 tasks)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:32:34 +02:00
2e0f5b4e30 feat(mail) : store Pinia useMailStore — folders, messages, polling 30s, markRead/markFlagged 2026-05-20 00:26:19 +02:00
33e4e79f8e feat(mail) : service API mail — listFolders/messages/getMessage/markRead/markFlagged/createTask/linkTask/downloadAttachment/triggerSync 2026-05-20 00:25:21 +02:00
bfa155d060 feat(mail) : helper sanitizeMailHtml — DOMPurify + placeholder images distantes 2026-05-20 00:24:30 +02:00
e7224765b1 feat(mail) : types TS DTOs mail (config, folders, messages, attachments) 2026-05-20 00:23:26 +02:00
fe07398059 feat(mail) : install dompurify + types 2026-05-20 00:22:33 +02:00
a440ce267f docs(mail) : plan détaillé Phase 4 — services TS, store Pinia, DOMPurify (6 tasks)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:21:50 +02:00
8986f3cb0e feat(mail) : security.yaml - access_control ^/api/mail (IS_AUTHENTICATED_FULLY)
- 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>
2026-05-20 00:15:49 +02:00
6d420c86e8 feat(mail) : MailSyncTriggerController - POST /api/mail/sync (202 + Messenger async)
- 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>
2026-05-20 00:15:25 +02:00
cc46dd915d feat(mail) : MailSyncRequested message + handler + messenger.yaml transport async Doctrine
- 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>
2026-05-20 00:14:47 +02:00