docs: SES secrets created, ship blocker cleared

Five documents asserted the SES_* secrets were unset in Gitea. They now
exist, so all five are corrected rather than leaving the claim to rot in
whichever one a reader opens first.

Replaces the blocker with the two things creating the secrets does NOT
establish, since both fail in ways that look identical to a missing
config: SES_FROM must be a verified identity in SES_REGION, and the
account must be out of the SES sandbox — in sandbox SES only delivers to
verified recipients, so a sweep across 815 policyholders would fail
almost every send while the configuration reads as correct.

Recommends running the first sweep with debug on, which diverts every
recipient and, on the pólizas side, leaves the avisos pending so a failed
test consumes nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 13:25:44 -07:00
co-authored by Claude Opus 5
parent 3e12597204
commit e77e5546d8
5 changed files with 49 additions and 25 deletions
+24 -12
View File
@@ -38,21 +38,33 @@ Plus three backup-pipeline fixes that have never reached prod (`860d483`,
`567b033`, `898cf48` — the last prod run went green through the whole chain and
died on the final step wanting `deploy/.env.prod`).
> ### ⚠️ `SES_*` is unset in Gitea, and the renewal sweep is on by default
> ### `SES_*` secrets created in Gitea 2026-08-02 — unblocked, unverified
>
> The variables are wired through both deploy workflows and the app stack, but
> the secrets were never set. The production image runs `NODE_ENV=production`,
> which disables the stdout dev fallback, so every send fails and logs
> `FAILED`.
> The variables were wired through both deploy workflows and the app stack but
> had never been set. **They now exist.** What that clears: the production
> image runs `NODE_ENV=production`, which disables the stdout dev fallback, so
> a blank config made every send fail and log `FAILED` — and the pólizas sweep
> defaults to **enabled, 06:00 America/Tijuana**, so the failure would have
> repeated nightly.
>
> The pólizas sweep defaults to **enabled, 06:00 America/Tijuana**. Deploying
> current master with SES still blank means a sweep that fails every single
> night, silently except for the log.
> **Not yet confirmed, and the first deploy is what confirms it:**
>
> **Before cutting `v1.0.7`:** either set the Gitea secrets, or disable the
> pólizas schedule at `/notificaciones` → "Programación de envíos" first.
> See [`MASS_EMAIL_NOTIFICATIONS.md`](MASS_EMAIL_NOTIFICATIONS.md) and
> [`DEPLOY_AND_MIGRATIONS.md`](DEPLOY_AND_MIGRATIONS.md).
> 1. **Names match.** The preflight checks `SES_REGION`, `SES_FROM`,
> `SES_ACCESS_KEY`, `SES_SECRET_KEY` and warns by name if any is blank —
> read that warning on the next run. No `_GALACTUS` suffix on any of them;
> one SES identity serves every deployment.
> 2. **`SES_FROM` is a verified identity in `SES_REGION`.** An unverified
> sender is rejected per-send, which looks identical to a missing config in
> the log.
> 3. **The AWS account is out of the SES sandbox.** This is the one that would
> hurt: in sandbox, SES only delivers to *verified* recipients, so a renewal
> sweep across 815 policyholders would fail almost every send while the
> config looks entirely correct. Check before letting a real sweep run.
>
> Until 2 and 3 are confirmed, run the first sweep with `debug` on — it diverts
> every recipient to the override inbox, and on the pólizas side it also leaves
> the avisos pending, so nothing is consumed by a failed test. See
> [`MASS_EMAIL_NOTIFICATIONS.md`](MASS_EMAIL_NOTIFICATIONS.md) "Send flags".
Also outstanding on the deploy path: every pre-existing database still needs
its one-time `prisma migrate resolve --applied 0000_init`.
+7 -2
View File
@@ -335,5 +335,10 @@ backup does them (see `deploy/scripts/pre-migrate-backup.mjs`):
which has no DB lock (the pólizas one does). Keep it single-replica.
- `SES_*` is optional to deploy — the preflight only warns — but the production
image sets `NODE_ENV=production`, which disables the stdout dev fallback. A
blank SES config therefore makes every send fail and log `FAILED`. As of
2026-08-02 these secrets are still unset in Gitea.
blank SES config therefore makes every send fail and log `FAILED`. The
secrets were created 2026-08-02; the preflight warning on the next run is
what confirms the names are right. Two things it cannot check: that
`SES_FROM` is a **verified identity** in `SES_REGION`, and that the account
is **out of the SES sandbox** (in sandbox, delivery is restricted to verified
recipients, which would fail a real sweep while looking correctly
configured).
+7 -4
View File
@@ -797,10 +797,13 @@ No collision with the abilities proposed in `RECEIPT_CAPTURE_SPEC.md`
## Open questions to take back to Jorge (collected)
**§1 — renewal emails** (feature built; these three are still open)
- Which SES region + verified identity/configuration set, and whether to reuse
existing IAM credentials or create a scoped `ses:SendEmail` user. **Still
unanswered in production**: the `SES_*` variables are wired through the
deploy workflow but unset in Gitea, so production sends fail loudly.
- ~~Which SES region + verified identity/configuration set, and whether to
reuse existing IAM credentials or create a scoped `ses:SendEmail` user.~~
**Answered in practice 2026-08-02** — the Gitea secrets were created. Two
things the deploy preflight cannot verify and that decide whether mail
actually goes out: `SES_FROM` must be a verified identity in `SES_REGION`,
and the account must be out of the SES sandbox (which restricts delivery to
verified recipients). See [`BACKLOG.md`](BACKLOG.md) §0.
- The 78 policyholders with no email: skip silently, or produce a print
worklist? Currently they are **logged as `SKIPPED_NO_EMAIL`** in
`email_notification_log` — visible in "Registro de envíos", but not yet a