# SPEC-FIX-EMAIL-EXPIRED — Rapport **Date** : 29/05/2026 (Session 147) **Statut** : Diagnostic complet — PAS DE BUG CODE, comportement nominal **Soak** : Pas de restart, continuité T0=01:25 MSK 29/05 --- ## 1. Resume executif Le canal EMAIL du router fonctionne correctement. Les 5 deliveries EXPIRED du test supervisor 10-cases n'etaient PAS des echecs d'envoi — c'etaient des emails envoyes avec succes via SMTP Beget puis marques EXPIRED car non-acquittes (EMAIL = canal terminal dans l'escalation). Le test direct avec `priority: URGENT` (bypass quiet hours) confirme : `status: SENT`, email recu. Aucun fix code necessaire. --- ## 2. Phase 1 — Diagnostic ### 1.1 — Composants email | Fichier | Role | |---------|------| | `src/modules/notification-router/adapters/email.adapter.ts` | EmailAdapter → delegue a EmailService.sendEmail() | | `src/modules/email/email.service.ts` | Nodemailer transport SMTP Beget | | `src/modules/notification-router/helpers/quiet-hours.helper.ts` | isInQuietHours() check (22h-7h UTC) | | `src/modules/notification-router/router.service.ts` L35-38 | Quiet hours → force ERP_IN_APP | ### 1.2 — Trace des 5 EXPIRED Les 5 deliveries EMAIL du test supervisor etaient creees par le **cron d'escalation** (`escalateUnacked`) a 21:39-21:40 UTC, apres que les deliveries TELEGRAM (21:23 UTC) n'aient pas ete acquittees dans le delai de 15 min. **Flow reel** : 1. ERP_IN_APP dispatch (20:52 UTC) → SENT → non-acquitte 2. Escalation 15min → PWA_PUSH (21:07 UTC) → SENT → non-acquitte (Edge/WNS bloque) 3. Escalation 15min → TELEGRAM (21:23 UTC) → SENT → non-acquitte (Louis a vu mais pas clique ack) 4. Escalation 15min → EMAIL (21:39 UTC) → SENT → puis EXPIRED (terminal channel, non-acquitte) **EXPIRED ≠ echec d'envoi.** EXPIRED signifie : "dernier canal de l'escalation, notification envoyee mais jamais acquittee". C'est le comportement nominal. ### 1.3 — Test SMTP direct ``` Connection to smtp.beget.com (185.78.30.103) 465 port [tcp/submissions] succeeded! TLS: *.beget.com, valid until Dec 2026 ``` Reseau VPS → Beget : OK. ### 1.4 — Test envoi direct **Premier test** (`priority: HIGH`, ~22:35 UTC) : - `channelUsed: "ERP_IN_APP"` — **fallback quiet hours** (22h-7h UTC, HIGH n'est pas URGENT) **Second test** (`priority: URGENT`, ~22:36 UTC) : - `channelUsed: "EMAIL"`, `status: SENT`, `sentAt: 22:36:31` - Email recu dans la boite `gruart@cifem-rus.ru` ### 1.5 — Categorie **Categorie : AUCUNE (pas de bug)** Le comportement observe est nominal : - Pendant les quiet hours (22h-7h), seul URGENT bypass → les notifications HIGH sont forcees en ERP_IN_APP - L'escalation cron NE verifie PAS les quiet hours (by design — si une notification a ete initialement envoyee hors quiet hours et escalade pendant les quiet hours, elle continue l'escalation) - Les emails sont envoyes avec succes quand le canal est selectionne - EXPIRED = terminal channel + non-acquitte, PAS un echec d'envoi --- ## 3. Phase 2 — Fix **Aucun fix necessaire.** Le canal EMAIL fonctionne correctement. --- ## 4. Phase 3 — Validation | Test | Resultat | |------|----------| | SMTP TCP/TLS VPS→Beget | OK | | test-dispatch EMAIL URGENT | SENT, email recu | | test-dispatch EMAIL HIGH (quiet hours) | Fallback ERP_IN_APP (nominal) | --- ## 5. Soak Pas de restart backend. Soak intact depuis T0=01:25 MSK 29/05. --- ## 6. Recommandations | Priorite | Item | Description | |----------|------|-------------| | P3 | QUIET-HOURS-DOC | Documenter les quiet hours (22h-7h UTC) dans l'aide utilisateur — les admins doivent savoir pourquoi les emails n'arrivent pas la nuit | | P3 | QUIET-HOURS-TZ | Les quiet hours utilisent `new Date().getHours()` (UTC sur VPS). Idealement, utiliser le timezone utilisateur ou Moscow. Actuellement 22h-7h UTC = 01h-10h MSK | | P4 | ACK-LINK-EMAIL | Verifier que le lien d'acquittement dans les emails fonctionne (URL `/api/v1/notification-router/ack/{deliveryId}`) — si cliquer, le status passerait de SENT a ACKED au lieu d'EXPIRED | | P4 | ESCALATION-QUIET | Le cron d'escalation ne verifie pas les quiet hours — design choice acceptable mais a documenter |