feat(mail): mise en place de MailDev et envoi des accusés de réception (#3177)#3231
feat(mail): mise en place de MailDev et envoi des accusés de réception (#3177)#3231
Conversation
MailDev listens on SMTP port 1025 and exposes a web UI on 1080, using the MAILDEV_* env vars already declared in .env.
Deploys a MailDev Deployment + Service on dev namespaces so review apps can send SMTP mail to a catcher. On preprod and prod the mail configmap sets MAIL_ENABLED=false until a real SMTP provider is provisioned.
…t templates Introduces a `~/modules/mail` module built on nodemailer. `sendMail` is a no-op when MAIL_ENABLED is false so preprod and prod are safe until a real SMTP provider is wired. `sendReceipt` orchestrates the three receipt flavours (declaration, second declaration, CSE opinion), attaches the récapitulatif PDFs when relevant, and self-audits every send via the existing audit log. Adds MAIL_RECEIPT_SEND and MAIL_RECEIPT_RESEND audit actions.
Wires the existing 'accusé de réception' banners to the new mail module: - declaration.submit / submitSecondDeclaration / cseOpinion.saveOpinions send the matching receipt template (with récapitulatif PDFs attached for declarations). - New mail.resendReceipt tRPC mutation powers the Renvoyer buttons on all three banners via a shared ResendReceiptButton client component. - mail.resendReceipt is audited as MAIL_RECEIPT_RESEND; initial sends piggyback on the existing submit audit rows plus a dedicated MAIL_RECEIPT_SEND log line emitted from sendReceipt.
revu-bot
left a comment
There was a problem hiding this comment.
⚠️ PR Review Skipped
1 validation issue found. Review thresholds can be adjusted in
.revu.yml.
See why it was skipped and detailed metrics
Issues Found
1. This PR changes 38 files, which exceeds the limit of 25 files.
Suggestion: Consider breaking this PR into smaller, more focused changes. Large PRs are harder to review effectively and may contain unrelated changes.
PR Metrics
- Total files changed: 38
- Reviewable files: 38
- Diff size: 1276 lines
- Documentation files: 0
- Largest file change: 104 lines
- Addition/Deletion ratio: 66.83
This validation helps ensure the bot focuses on PRs where automated review provides the most value.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Client components imported the mail barrel, which re-exported the nodemailer transporter and pulled Node built-ins (stream, perf_hooks) into the client bundle. Split into: - ~/modules/mail (client-safe: button + schemas + types) - ~/modules/mail/server (sendMail + sendReceipt, server-only) Also dynamic-imports sendReceipt inside router handlers: the static import went through buildPdfData, which lives in ~/modules/declarationPdf and pulls ~/server/api/routers/declarationHelpers, creating a module graph cycle that turbopack tripped over with a TDZ error on createCaller.
Dev review apps route the ProConnect test account (test@fia1.fr) to a shared yopmail inbox (fia1@yopmail.com) so the team can inspect receipts without configuring individual SMTP destinations. The map is an optional JSON env var, applied transparently in sendMail and recorded in the audit log metadata.
…n-prod envs" This reverts commit 225e46b.
Review apps get https://maildev-<namespace>.ovh.fabrique.social.gouv.fr pointing at the maildev service port 1080 so the team can inspect receipts directly in a browser without port-forwarding.
readOnlyRootFilesystem=true prevented MailDev from creating its mail spool directory, causing CrashLoopBackOff.
…load
- Templates now return only { subject, html }. sendMail uses
html-to-text to produce the plain-text alternative at send time,
removing the duplication between the two representations.
- CSE opinion receipt is now triggered by a successful POST on
/api/upload (flowType=cse_opinion) instead of cseOpinion.saveOpinions,
so the acknowledgement matches the moment the document is actually
deposited.
revu-bot
left a comment
There was a problem hiding this comment.
⚠️ PR Review Skipped
1 validation issue found. Review thresholds can be adjusted in
.revu.yml.
See why it was skipped and detailed metrics
Issues Found
1. This PR changes 39 files, which exceeds the limit of 25 files.
Suggestion: Consider breaking this PR into smaller, more focused changes. Large PRs are harder to review effectively and may contain unrelated changes.
PR Metrics
- Total files changed: 39
- Reviewable files: 39
- Diff size: 1518 lines
- Documentation files: 0
- Largest file change: 311 lines
- Addition/Deletion ratio: 75.08
This validation helps ensure the bot focuses on PRs where automated review provides the most value.
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Two changes targeted at the SonarCloud duplication threshold: - `modules/admin/declarations/shared/DsfrTable.tsx` was a byte-identical copy of `modules/shared/DsfrTable.tsx`. Deleted the copy, pointed the three existing consumers (DetailSections, DeclarationTable, test file) at the shared module. - `DeclarationTable` and `ReferentTable` both carried the same ~20-line sort / page-URL helper block. Extracted it into a new `useSortableTable` hook in `modules/shared`, with a companion unit test, so both tables consume the same code path.
Both the admin and public referent search pages had near-identical forms (same schema, same region/county cascade, same URL-state handling). Consolidated them into `~/modules/referents/shared/ ReferentsSearchForm` parameterized by basePath, fieldPrefix, schema and a few cosmetic flags. The two existing forms become thin wrappers.
|
🎉 Deployment for commit 9d07cfd : IngressesDocker images
|
Summary
Deployment+Servicedans.kontinuous/env/dev/templates/maildev.yaml).~/modules/mailbasé sur nodemailer avec 3 templates d'accusé de réception (déclaration, seconde déclaration, avis CSE) en texte + HTML multipart et PDF récapitulatifs en pièces jointes.declaration.submit,declaration.submitSecondDeclaration,cseOpinion.saveOpinions) et les 3 boutons « Renvoyer l'accusé de réception » via une nouvelle mutationmail.resendReceipt.MAIL_ENABLED=falsepar défaut sur preprod et prod (no-op silencieux) tant qu'un vrai fournisseur SMTP n'est pas choisi — MailDev reste cantonné àdev.MAIL_RECEIPT_SEND/MAIL_RECEIPT_RESEND(catégoriemutation, 365 jours).Closes #3177
Test plan
docker compose up maildev→ UI accessible sur http://localhost:1080audit.action_log:MAIL_RECEIPT_SEND(initial) +MAIL_RECEIPT_RESEND(resend)MAIL_ENABLED=false=> aucun SMTP ouvert,sendMailrenvoie{status: "disabled"}