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:
@@ -155,7 +155,7 @@ Given the amount of near-duplicate/overlapping data across snapshot tables (mult
|
||||
- **Renewal notification emails — DONE** (2026-08-01, extended 08-02). A sweep that mails the customer 30 days before expiry, 15 days before, and 7 days after, mapping onto `RenewalNotice.generation` 1/2/3 with **no schema change**. Sending is **Amazon SES** (`@aws-sdk/client-sesv2`, mirroring `StorageService`'s optional-client/degrade-don't-crash pattern). The letter body is the *existing* `aviso-renovacion` report; `@@unique([policyId, generation])` is already-in-place idempotency, so a re-run cannot double-send. Volume ≈260 mails/month, and **815 of the 893 policyholders (91%) have an email**.
|
||||
**Three things came out differently from the spec.** (a) The manual mark-as-sent mutation was **dropped on purpose** — a button that marks a notice sent without sending anything lets the list claim a customer was told when they were not. `POST /renewals/send` replaced it: sending from the list *is* the marking, and the report's `enviadas` total becomes real the same way. (b) The send history is **not renewal-specific** — every attempt, including the failures and no-email skips a `RenewalNotice` row cannot represent, also writes `email_notification_log` as `RENEWAL_NOTICE`/`POLICIES`, shared with the four bulk jobs from [`docs/MASS_EMAIL_NOTIFICATIONS.md`](docs/MASS_EMAIL_NOTIFICATIONS.md). `RenewalNotice` stays *gating* state; the log is *history*. (c) The `@Cron("0 6 * * *")` literal the spec called for lasted one day: both this sweep and the servicios jobs now take their cadence from `NotificationScheduleService`, stored in `app_settings` and reinstalled on save — no redeploy. Defaults preserve the old behaviour (pólizas 06:00 daily, servicios off).
|
||||
**Both halves live on one screen.** `/notificaciones` has Servicios and Pólizas tabs over the one log; `/renovaciones` is an alias onto the Pólizas tab. The send flags (`debug` in particular) sit in the shell above the tabs and govern both — before that there was no way to test a renewal aviso without mailing a real customer. A debug send diverts the mail, skips the `RenewalNotice` upsert **and** does not advance the sweep's `lastSuccessfulAt`; all three are needed together, or a test run silently narrows tomorrow's window and drops the letters it only pretended to send.
|
||||
**Still blocked in production:** the `SES_*` variables are wired through the deploy workflow but unset in Gitea, so a production send fails loudly rather than going out.
|
||||
**Production status:** the `SES_*` Gitea secrets were created 2026-08-02, clearing the last blocker — but the feature has not shipped yet (master is well past the newest tag) and nothing has confirmed that `SES_FROM` is a verified SES identity or that the account is out of the sandbox. Run the first sweep with `debug` on. See [`docs/BACKLOG.md`](docs/BACKLOG.md) §0.
|
||||
- **Liquidación batch workflow** — ~70% already built (`liquidated`/`liquidationNumber`/`liquidationDate` are wired through DTOs, list filter, stats, form and detail page); only the *batch* print-and-mark step is missing, against a live pending set of 226 policies. Adds a ramo-parameterized pending report plus `POST /policies/liquidate-batch` under a new MANAGER `policy:liquidate` ability. Parameterized by ramo, not MULT-only — legacy `TABLA LIQUIDA MF` served `MULT`, `INCENDIO` and `M EMPR` alike.
|
||||
- **Certificate / "Solicitud Atlas"** — renders from the same `format: "letter"` machinery `aviso-renovacion` uses, then reaches customers as an extension of the step-8/9 replication (PDF generated here, pushed to MinIO, pointer replicated), **not** as a new public surface in this repo. Half-blocked: "Solicitud" has zero referent in the legacy system and normally means an *application form*, a different artifact from a certificate.
|
||||
- **Carrier API integration (ANA Seguros + GMX)** — shape only (`CarrierConnector` + an import-review queue rather than direct `Policy` writes, matching how step 11's OCR results are routed). Carrier research done 2026-07-27: **the two carriers are one company** — both belong to **Grupo Valore** (ANA writes autos, GMX writes daños, which is exactly this database's `AUTO`/`LICENCIAS` vs `MULT`/`INCENDIO`/`M_EMPR` split), so it is one commercial relationship, not two. **ANA has a real live SOAP service** (`server.anaseguros.com.mx/ananetws/service.asmx`, ASP.NET `.asmx`) with a published operation list — catalogs, `CalculaValor`/`CalculaMSI`, `ValidaSerie`, `RecuperaCotizacion`, `Transaccion`. **GMX publishes no machine interface at all**, only human agent portals. ⚠️ **Critical mismatch:** every ANA operation serves *new-business quoting/issuance*, not "list the policies where I am agent of record" — so if the ask is inbound portfolio sync, no evidence exists that either carrier sells it. Blocked on one phone call to Grupo Valore ((55) 5480-4000) for credentials + a direction answer, not on further research. ("GDMX" in the meeting notes was a typo for `GMX` — confirmed 2026-07-27.)
|
||||
|
||||
@@ -685,9 +685,13 @@ Implementation notes worth keeping:
|
||||
- Wire shapes of the four jobs are byte-for-byte the legacy PHP responses,
|
||||
quirks included (Job 1 reports `result`, not `request`).
|
||||
|
||||
**Open:** `SES_*` is wired through the deploy workflow but **unset in Gitea**,
|
||||
so production sends fail loudly rather than going out. The 78 policyholders
|
||||
with no email are logged as `SKIPPED_NO_EMAIL` but there is still no printable
|
||||
worklist for them, and the notice body is English-only (`Customer` carries no
|
||||
language preference) — the same three questions §1 of the insurance spec
|
||||
opened.
|
||||
**Open:** the `SES_*` Gitea secrets were created 2026-08-02, so the feature is
|
||||
no longer blocked — but it has not shipped (master is well past the newest tag)
|
||||
and two things nobody has checked decide whether mail leaves the building:
|
||||
`SES_FROM` must be a verified identity in `SES_REGION`, and the AWS account
|
||||
must be out of the SES sandbox, which otherwise restricts delivery to verified
|
||||
recipients and would fail a real sweep while looking correctly configured. Run
|
||||
the first sweep with `debug` on. Still open beyond that: the 78 policyholders
|
||||
with no email are logged as `SKIPPED_NO_EMAIL` but have no printable worklist,
|
||||
and the notice body is English-only (`Customer` carries no language
|
||||
preference).
|
||||
|
||||
+24
-12
@@ -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`.
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user