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

97 lines
4.1 KiB
Markdown

# 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 |