Étape 10 : envoi d'emails par SMTP
- app/email/ : sender (smtplib, STARTTLS ou SSL, connexion réutilisée pour un
lot) + templates (rendu, textes dans locales/fr.json). EMAIL_ENABLED=false
(défaut) ⇒ journalisé seulement, sans destinataire ni corps (RGPD).
- Lien magique : POST .../auth/magic-link envoie désormais l'email
(PUBLIC_BASE_URL + magic_link_path + ?token=). Helper app/auth/magic_link.py
partagé. Sans SMTP, le jeton non nominatif reste journalisé pour le dev.
- Récapitulatif de planning : POST /editions/{id}/notifications/planning
(COORDINATION). subject/body sont des modèles ({prenom}, {nom}, {nb_creneaux},
{nb_heures}, {creneaux}, {lien_connexion} → lien magique personnel émis).
Cible tous les bénévoles avec email ou une liste. Envoi en BackgroundTasks.
- Config : PUBLIC_BASE_URL, EMAIL_ENABLED, SMTP_* ; .env.example,
docker-compose (dev + prod), deploy/README.
- 9 tests (sender activé/désactivé, rendu, notifications : contenu, gabarit par
défaut, lien magique embarqué, sous-ensemble, réservé COORDINATION).
137 tests au total ; ruff + alembic check verts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
977bd4dc34
commit
b268e308ab
@@ -142,6 +142,25 @@ La coordination crée les comptes via `POST /editions/{id}/accounts` : un
|
||||
`COORDINATOR` **exige** un `password` (≥ 10) ; un `LEAD` / `VOLUNTEER` le
|
||||
**refuse** (lien magique). Un bénévole sans email n'a pas de `Account`.
|
||||
|
||||
### Emails (`app/email/`)
|
||||
|
||||
Envoi par **SMTP** (auto-hébergé). `EMAIL_ENABLED=false` (défaut dev/tests) ⇒
|
||||
les emails sont seulement journalisés (`app.email`, INFO, **sans destinataire
|
||||
ni corps** — RGPD). Config : `SMTP_HOST/PORT/USER/PASSWORD/STARTTLS/SSL/FROM`,
|
||||
`PUBLIC_BASE_URL` (pour les liens).
|
||||
|
||||
- **Lien magique** : `POST .../auth/magic-link` envoie l'email contenant
|
||||
`PUBLIC_BASE_URL` + `magic_link_path` + `?token=`. Sans SMTP, le jeton (non
|
||||
nominatif) reste journalisé pour le dev.
|
||||
- **Récapitulatif de planning** : `POST /editions/{id}/notifications/planning`
|
||||
(COORDINATION), corps `{ subject?, body?, volunteer_ids? }`. `subject`/`body`
|
||||
sont des **modèles** avec `{prenom}`, `{nom}`, `{nb_creneaux}`, `{nb_heures}`,
|
||||
`{creneaux}`, `{lien_connexion}` (si présent ⇒ un lien magique personnel est
|
||||
émis pour le compte du bénévole). `volunteer_ids` absent ⇒ tous les bénévoles
|
||||
de l'édition qui ont un email. Envoi en tâche de fond (`BackgroundTasks`,
|
||||
une connexion SMTP réutilisée). Réponse : `{ queued, skipped_no_email,
|
||||
recipients }`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Moteur de validation des affectations — cœur du produit
|
||||
@@ -195,8 +214,8 @@ Sémantique figée :
|
||||
|
||||
### Hors périmètre (le modèle doit juste pouvoir les accueillir sans refonte)
|
||||
|
||||
Solveur OR-Tools · envoi d'emails / SMS · constructeur de formulaire ·
|
||||
pointage sur site · fonctions d'IA.
|
||||
Solveur OR-Tools · SMS · constructeur de formulaire · pointage sur site ·
|
||||
fonctions d'IA. *(L'envoi d'emails par SMTP est en place — voir § 2.)*
|
||||
|
||||
---
|
||||
|
||||
@@ -225,8 +244,9 @@ pointage sur site · fonctions d'IA.
|
||||
│ │ ├── api/ # routers + schemas Pydantic + deps
|
||||
│ │ │ # health, auth, accounts, imports,
|
||||
│ │ │ # volunteers, positions, shifts,
|
||||
│ │ │ # assignments, matrix
|
||||
│ │ ├── auth/ # lien magique + JWT + dépendances de rôle
|
||||
│ │ │ # assignments, matrix, notifications
|
||||
│ │ ├── auth/ # mot de passe + lien magique + JWT + rôles
|
||||
│ │ ├── email/ # SMTP (sender) + rendu des emails (templates)
|
||||
│ │ ├── importing/ # import CSV/Excel (parser, values, service)
|
||||
│ │ ├── models/ # tables SQLModel
|
||||
│ │ ├── validation/ # moteur pur (models, engine) + loader (base)
|
||||
@@ -292,7 +312,8 @@ Aucune dépendance locale requise hors Docker.
|
||||
- Secrets requis (voir `deploy/README.md`) : `SSH_HOST`, `SSH_USER`,
|
||||
`SSH_KEY`, `DEPLOY_PATH`, `GHCR_TOKEN`.
|
||||
- Le VPS porte un fichier `.env` (non versionné) avec `POSTGRES_USER`,
|
||||
`POSTGRES_PASSWORD`, `POSTGRES_DB`, `JWT_SECRET`.
|
||||
`POSTGRES_PASSWORD`, `POSTGRES_DB`, `JWT_SECRET`, `PUBLIC_BASE_URL` et les
|
||||
variables `EMAIL_ENABLED` / `SMTP_*` (voir `deploy/README.md`).
|
||||
|
||||
---
|
||||
|
||||
@@ -308,10 +329,9 @@ Aucune dépendance locale requise hors Docker.
|
||||
| 6 | Jeu de données de démonstration (`app/seed.py`) | validée |
|
||||
| 7 | Authentification : lien magique + JWT + application des rôles | validée |
|
||||
| 8 | Second système : connexion mot de passe (bcrypt) pour la coordination | validée |
|
||||
| 9 | Suppression du statut d'affectation (plus d'étape de confirmation) | à valider |
|
||||
| 9 | Suppression du statut d'affectation (plus d'étape de confirmation) | validée |
|
||||
| 10 | Envoi d'emails par SMTP : lien magique + récapitulatif de planning | à valider |
|
||||
|
||||
Premier incrément backend + authentification terminés. **Reste hors
|
||||
périmètre** (modèle prêt à les accueillir) : envoi réel d'emails/SMS (le lien
|
||||
magique est journalisé, pas envoyé), solveur OR-Tools, constructeur de
|
||||
formulaire, pointage sur site, IA. Le frontend (React/Vite/TS/Tailwind) reste
|
||||
à démarrer.
|
||||
**Reste hors périmètre** (modèle prêt à les accueillir) : solveur OR-Tools,
|
||||
SMS, constructeur de formulaire, pointage sur site, IA. Frontend :
|
||||
squelette + 6 écrans + connexion en place (voir `frontend/`).
|
||||
|
||||
Reference in New Issue
Block a user