Files
platform/docs/email-migration-checklist.md
T
pastilhasandClaude Opus 5 7d1212765b docs: test checklist for the email sidecar migration
Written to be run later rather than now, so it says what changed underneath and where a
failure will land: the routes moved verbatim, but the transport (browser → proxy → sidecar
HTTP) and the source of user identity (X-Officer-User instead of userMiddleware) did not,
and that is where breakage will cluster.

Includes the attribution table — 503 vs 502 vs 401 each point at a different half — and
flags the two things that are expected rather than wrong: sync still runs platform-side on
purpose, and the channel handlers' "sync emails" was already broken before this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 12:13:58 +00:00

109 lines
5.1 KiB
Markdown

# Email sidecar migration — test checklist
For `7c173b4`, which moved the mail store and all 14 routes out of the platform and into
`officer-email`. Each line is a single yes/no. Report as "M3 ok, R2 needs fix".
**Pre-req:** `pm2 restart officer-email && pm2 restart officer`, then hard-refresh. Both are needed —
the sidecar gained an HTTP listener and the platform became a proxy; restarting only one leaves them
speaking different protocols.
**Why this needs testing at all:** the routes moved *verbatim*, so the logic should be identical. What
changed underneath is the transport (browser → platform proxy → sidecar HTTP) and where the user
identity comes from (`X-Officer-User` header instead of the platform's `userMiddleware`). Failures will
cluster in those two places, not in mail logic.
---
## M — Messages and folders
- [ ] **M1** `/email` loads and lists messages.
- [ ] **M2** Folder switching works, and per-folder counts look right (inbox / sent / all).
- [ ] **M3** Paging past the first page works.
- [ ] **M4** `/email/stats` renders — the totals panel is populated, not zeroed.
- [ ] **M5** Labels/folders list is populated.
## R — Reading a message
- [ ] **R1** Open a message → body, sender, date, recipients all render.
- [ ] **R2** Open a thread → the whole conversation, in order.
- [ ] **R3** Mark as read → state sticks after a refresh.
- [ ] **R4** Mark a whole thread read.
- [ ] **R5** Delete a message → it disappears and stays gone after a refresh.
- [ ] **R6** Deep-link `/email/:emailId` in a fresh tab opens that message.
## S — Search and contacts
- [ ] **S1** Search returns sensible results.
- [ ] **S2** Search with an apostrophe or quote in the term behaves (`it's`, `"x"`), i.e. no 500.
- [ ] **S3** Contacts list populates (used by the compose autocomplete).
## A — Attachments
- [ ] **A1** A message with attachments shows them.
- [ ] **A2** Extracting/downloading an attachment works and the file is intact.
*Attachments write under `DATA_PATH`; the sidecar does this now, so a permissions problem would
surface here first.*
## L — Live updates (the SSE path)
- [ ] **L1** Leave `/email` open, send yourself mail → it appears without a manual refresh.
- [ ] **L2** No repeated reconnect errors in the browser console while the page sits idle.
*This is the biggest structural change: `email:new` used to travel sidecar → platform → SSE. The
stream is inside the sidecar now and the IDLE watcher pushes to it in-process.*
## C — Accounts
- [ ] **C1** The accounts screen lists the account with its status.
- [ ] **C2** Sync status / last-synced is shown and looks current.
- [ ] **C3** Trigger a manual sync → it starts.
- [ ] **C4** Adding an account still validates the IMAP connection (test with a deliberately wrong
password and expect a clear failure, not a hang).
## X — Sync regression (still platform-side, deliberately)
The two sync handlers did **not** move; they still run in the platform queue and now import the store
from its new location. So this block is checking nothing *broke*, not that anything improved.
- [ ] **X1** New mail still arrives — the periodic sync is running.
- [ ] **X2** Email sync jobs still appear in the Jobs list (they will stop doing so in stage 2, by
design — option A).
## P — Proxy behaviour
Run from the host. Mint a token the same way the app does, or reuse a browser one.
- [ ] **P1** A long request survives: trigger a from-scratch resync and confirm it isn't cut off around
60s. The proxy sets `timeoutSeconds: 1800` for the whole `/api/email` prefix.
- [ ] **P2** `/api/email/messages` returns 503 (not a hang or a 500) while `officer-email` is stopped:
```bash
pm2 stop officer-email
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOK" \
-H 'Host: officer.pastilhas.dev' http://127.0.0.1:9010/api/email/messages # expect 503
pm2 start officer-email
```
- [ ] **P3** Nothing in `pm2 logs officer` mentions email internals any more — the platform should be
logging proxy failures at most, never mail.
---
## Attributing a failure
The split makes this quick:
| symptom | look at |
|---|---|
| `503 email sidecar not available` | the sidecar isn't running, or hasn't announced its port — `pm2 logs officer-email` |
| `502 email sidecar unreachable` | it announced a port but died; check for a crash on boot |
| `401 missing X-Officer-User` | the proxy didn't inject the header — a platform-side problem |
| anything about messages, folders, IMAP | the sidecar — `pm2 logs officer-email` |
`pm2 logs officer-email` should now carry everything mail-related. If mail errors are still appearing
in `pm2 logs officer`, something didn't move.
## Known-broken already, not caused by this
`gmail-sync` is hardcoded in all three channel handlers (telegram, discord, whatsapp), but the only
account is `provider=gmail, auth_type=password`, which routes to IMAP. So "sync emails" from a chat
channel was already failing before this change. It gets fixed in stage 2, when the channels stop
opening the mail store directly and ask the sidecar over HTTP.