metallkart-erp/docs/diagnostics/SPEC-FIX-EMAIL-EXPIRED-RAPPORT.md
louis bdd819efd0 docs(router): email channel diagnostic — no bug, quiet hours behavior
EMAIL channel works correctly. The 5 EXPIRED from supervisor test
were emails successfully sent but unacked (terminal channel).
URGENT bypasses quiet hours (22h-7h UTC) and EMAIL sends fine.
No code fix needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-29 02:37:34 +04:00

4.1 KiB

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