docs(mail) : checklist prod + sécurité, guide intégration complet, mention README
This commit is contained in:
@@ -21,6 +21,7 @@ Application de gestion de projet avec suivi du temps et portail client.
|
|||||||
- Profil utilisateur avec avatar (crop circulaire)
|
- Profil utilisateur avec avatar (crop circulaire)
|
||||||
- Notifications temps réel
|
- Notifications temps réel
|
||||||
- Intégration Gitea (issues, repos)
|
- Intégration Gitea (issues, repos)
|
||||||
|
- Intégration Mail IMAP (boîte partagée OVH, voir `docs/mail-integration.md`)
|
||||||
- Serveur MCP pour assistants IA
|
- Serveur MCP pour assistants IA
|
||||||
- Multi-langue (i18n)
|
- Multi-langue (i18n)
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ make shell-root # Shell root dans le container PHP
|
|||||||
make dev-nuxt # Dev server Nuxt (hot reload, port 3002)
|
make dev-nuxt # Dev server Nuxt (hot reload, port 3002)
|
||||||
make cache-clear # Vider le cache Symfony
|
make cache-clear # Vider le cache Symfony
|
||||||
make logs-dev # Tail logs Symfony
|
make logs-dev # Tail logs Symfony
|
||||||
|
make mail-sync # Synchroniser la boîte mail IMAP (voir docs/mail-cron-setup.md)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Base de données
|
### Base de données
|
||||||
|
|||||||
@@ -51,6 +51,16 @@ sudo crontab -u deploy -e
|
|||||||
|
|
||||||
La clé doit être la même que celle utilisée pour chiffrer le password lors de la configuration.
|
La clé doit être la même que celle utilisée pour chiffrer le password lors de la configuration.
|
||||||
|
|
||||||
|
## Checklist setup production
|
||||||
|
|
||||||
|
1. [ ] Définir `ENCRYPTION_KEY` dans les variables d'environnement production
|
||||||
|
2. [ ] Créer le compte mail dédié (ex: `lesstime@votre-domaine.fr`) chez OVH
|
||||||
|
3. [ ] Accéder à `/admin` → onglet "Mail" → renseigner les credentials IMAP/SMTP
|
||||||
|
4. [ ] Cliquer "Tester la connexion" → vérifier le succès
|
||||||
|
5. [ ] Cocher "Activer la synchronisation" → Enregistrer
|
||||||
|
6. [ ] Installer le cron OS (voir section "Installation du cron")
|
||||||
|
7. [ ] Vérifier les logs après la première sync : `make logs-dev` (chercher `mail.sync`)
|
||||||
|
|
||||||
## Commandes utiles
|
## Commandes utiles
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -86,6 +96,15 @@ Les messages loggés par `MailSyncService` sont préfixés `mail.sync`.
|
|||||||
- Les corps de mails, passwords et pièces jointes ne sont **jamais loggés**
|
- Les corps de mails, passwords et pièces jointes ne sont **jamais loggés**
|
||||||
- Le lock `flock` évite les runs parallèles (fichier dans `/tmp/sf.mail.sync.<hash>.lock`)
|
- Le lock `flock` évite les runs parallèles (fichier dans `/tmp/sf.mail.sync.<hash>.lock`)
|
||||||
|
|
||||||
|
## Rappels sécurité
|
||||||
|
|
||||||
|
- La page `/mail` et tous les endpoints `/api/mail/*` sont refusés aux `ROLE_CLIENT` exclusifs
|
||||||
|
- Le sidebar "Messagerie" est masqué pour les utilisateurs ROLE_CLIENT sans ROLE_USER
|
||||||
|
- Le password IMAP est chiffré via libsodium secretbox avant stockage (jamais en clair en base)
|
||||||
|
- Les corps de mails sont sanitisés via DOMPurify avant affichage (voir `frontend/utils/sanitizeMailHtml.ts`)
|
||||||
|
- Les pixels tracking distants sont remplacés par un placeholder
|
||||||
|
- Aucun body mail, password ou contenu de pièce jointe n'est loggé
|
||||||
|
|
||||||
## Production
|
## Production
|
||||||
|
|
||||||
En production, préférer un cron système ou un job scheduler (Kubernetes CronJob, ECS Scheduled Task, etc.).
|
En production, préférer un cron système ou un job scheduler (Kubernetes CronJob, ECS Scheduled Task, etc.).
|
||||||
|
|||||||
108
docs/mail-integration.md
Normal file
108
docs/mail-integration.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Intégration Mail — Vue d'ensemble
|
||||||
|
|
||||||
|
## Fonctionnalités
|
||||||
|
|
||||||
|
- Lecture de la boîte mail partagée (IMAP) depuis Lesstime
|
||||||
|
- Navigation par dossiers (arbre récursif avec compteurs non-lus)
|
||||||
|
- Liste paginée des messages (infinite scroll, cursor-based)
|
||||||
|
- Lecture des corps de mail sanitisés (DOMPurify — protection XSS + pixels tracking)
|
||||||
|
- Création d'une tâche Lesstime depuis un mail (sujet → titre, texte → description)
|
||||||
|
- Lien mail ↔ tâche (bidirectionnel)
|
||||||
|
- Onglet "Mails" dans le TaskDrawer pour retrouver les mails liés à une tâche
|
||||||
|
- Synchronisation IMAP automatique via cron OS (toutes les 10 min)
|
||||||
|
- Déclenchement manuel de sync depuis l'UI (bouton Refresh)
|
||||||
|
- Badge non-lus en temps réel dans la sidebar (polling 30s)
|
||||||
|
|
||||||
|
## Endpoints API
|
||||||
|
|
||||||
|
| Méthode | URL | Rôle | Description |
|
||||||
|
|---------|-----|------|-------------|
|
||||||
|
| GET | `/api/mail/configuration` | ROLE_ADMIN | Lire la config singleton |
|
||||||
|
| PATCH | `/api/mail/configuration` | ROLE_ADMIN | Mettre à jour la config |
|
||||||
|
| POST | `/api/mail/configuration/test` | ROLE_ADMIN | Tester la connexion IMAP |
|
||||||
|
| GET | `/api/mail/folders` | ROLE_USER | Arbre des dossiers + unread |
|
||||||
|
| GET | `/api/mail/messages` | ROLE_USER | Liste paginée (param: folder, cursor, limit) |
|
||||||
|
| GET | `/api/mail/messages/{id}` | ROLE_USER | Détail + body (cached 5 min) |
|
||||||
|
| POST | `/api/mail/messages/{id}/read` | ROLE_USER | Marquer lu/non-lu |
|
||||||
|
| POST | `/api/mail/messages/{id}/flag` | ROLE_USER | Marquer étoilé/non-étoilé |
|
||||||
|
| POST | `/api/mail/messages/{id}/create-task` | ROLE_USER | Créer tâche depuis mail |
|
||||||
|
| POST | `/api/mail/messages/{id}/link-task` | ROLE_USER | Lier mail à tâche existante |
|
||||||
|
| DELETE | `/api/mail/messages/{id}/link-task/{taskId}` | ROLE_USER | Supprimer le lien |
|
||||||
|
| GET | `/api/tasks/{id}/mails` | ROLE_USER | Mails liés à une tâche |
|
||||||
|
| GET | `/api/mail/attachments/{id}` | ROLE_USER | Télécharger une pièce jointe |
|
||||||
|
| POST | `/api/mail/sync` | ROLE_USER | Déclencher sync async (Messenger) |
|
||||||
|
|
||||||
|
Tous les endpoints `/api/mail/*` refusent explicitement `ROLE_CLIENT`.
|
||||||
|
|
||||||
|
## Sécurité
|
||||||
|
|
||||||
|
- ROLE_CLIENT exclusif : accès refusé à tous les endpoints mail et à la page `/mail`
|
||||||
|
- Le sidebar "Messagerie" est masqué pour les ROLE_CLIENT
|
||||||
|
- Password IMAP chiffré via libsodium secretbox (env `ENCRYPTION_KEY`)
|
||||||
|
- Corps de mail sanitisés via DOMPurify (`sanitizeMailHtml.ts`) — script/iframe/object/embed/on*/javascript: bloqués
|
||||||
|
- Pixels tracking distants (img src http) remplacés par placeholder
|
||||||
|
- Aucun body, password ou contenu de pièce jointe dans les logs
|
||||||
|
|
||||||
|
## Dépendances
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
- `webklex/php-imap` : client IMAP PHP
|
||||||
|
- `symfony/lock` : Symfony Lock pour éviter les syncs parallèles
|
||||||
|
- `symfony/messenger` : dispatch asynchrone `MailSyncRequested`
|
||||||
|
- `libsodium` (ext PHP) : chiffrement du password IMAP
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- `dompurify` + `@types/dompurify` : sanitization HTML des corps de mail
|
||||||
|
|
||||||
|
## Fichiers clés
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
- `src/Entity/MailConfiguration.php` — entité singleton (credentials, enabled)
|
||||||
|
- `src/Entity/MailFolder.php` — dossier IMAP synced
|
||||||
|
- `src/Entity/MailMessage.php` — message IMAP synced (headers, flags)
|
||||||
|
- `src/Entity/TaskMailLink.php` — lien tâche ↔ mail
|
||||||
|
- `src/Mail/ImapMailProvider.php` — implémentation IMAP (webklex)
|
||||||
|
- `src/Service/MailSyncService.php` — algorithme de sync (UID FETCH, resync flags)
|
||||||
|
- `src/Controller/Mail/` — controllers custom (test, folders, messages, sync)
|
||||||
|
- `src/State/Mail/` — providers/processors API Platform (configuration)
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- `frontend/pages/mail.vue` — page principale 3 colonnes
|
||||||
|
- `frontend/components/mail/` — MailFolderTree, MailMessageList, MailMessageViewer, MailRefreshButton
|
||||||
|
- `frontend/components/admin/AdminMailTab.vue` — onglet config admin
|
||||||
|
- `frontend/stores/mail.ts` — store Pinia (folders, messages, polling)
|
||||||
|
- `frontend/services/mail.ts` — service API (toutes les méthodes)
|
||||||
|
- `frontend/services/dto/mail.ts` — types TypeScript
|
||||||
|
- `frontend/utils/sanitizeMailHtml.ts` — DOMPurify wrapper
|
||||||
|
|
||||||
|
## Synchronisation cron
|
||||||
|
|
||||||
|
Voir `docs/mail-cron-setup.md` pour la configuration détaillée.
|
||||||
|
|
||||||
|
Résumé :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cron OS (toutes les 10 min)
|
||||||
|
*/10 * * * * cd /path/to/Lesstime && make mail-sync >> /var/log/lesstime-mail-sync.log 2>&1
|
||||||
|
|
||||||
|
# Commandes Makefile
|
||||||
|
make mail-sync # Sync complète
|
||||||
|
make mail-sync FOLDER=INBOX # Sync d'un dossier
|
||||||
|
make mail-sync DRYRUN=1 # Simulation sans écriture
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration admin
|
||||||
|
|
||||||
|
1. Aller sur `/admin` → onglet "Mail"
|
||||||
|
2. Renseigner les credentials IMAP/SMTP (OVH : `ssl0.ovh.net`, port 993/465, SSL)
|
||||||
|
3. Cliquer "Tester la connexion"
|
||||||
|
4. Activer la synchronisation → Enregistrer
|
||||||
|
5. Configurer le cron OS
|
||||||
|
|
||||||
|
## Variables d'environnement
|
||||||
|
|
||||||
|
| Variable | Description | Obligatoire |
|
||||||
|
|----------|-------------|-------------|
|
||||||
|
| `ENCRYPTION_KEY` | Clé hex 32 bytes libsodium pour chiffrer le password IMAP | Oui |
|
||||||
|
| `LOCK_DSN` | DSN Symfony Lock (défaut: `flock`) | Non |
|
||||||
|
| `MESSENGER_TRANSPORT_DSN` | Transport Messenger pour sync async | Recommandé (prod) |
|
||||||
Reference in New Issue
Block a user