SendGrid → Resend migration inventory¶
Date: 2026-08-30
Purpose: Seed the parked SendGrid→Resend pass (POST_MIGRATION_ROADMAP.md §1) with a live key inventory.
Method: Read-only bws secret list on R940-accessible projects + architecture/docs cross-check. No secret values recorded here.
Summary¶
| Metric | Count |
|---|---|
| Distinct SendGrid API keys (Ryan inventory) | 13 |
| Keys found in BWS today | 8 API keys (+ 6 LastVet template/from companion keys) |
| Keys in Cloudflare Pages / not yet in BWS | ≥5 (marketing -web cluster) |
| Resend keys in BWS (any project) | 0 (2026-08-30) |
13-key product matrix (migration scope)¶
| # | Product / surface | SendGrid key location (expected) | BWS key name (if known) | BWS project | Notes |
|---|---|---|---|---|---|
| 1 | lastvet-proxmox | Infra / alerting | PROXMOX_SENDGRID_SECRET |
proxmox (73c620d6-…) |
Not app runtime; infra mail |
| 2 | angel | Cloudflare Workers API | ANGEL_CLOUDFLARE_PROD_SENDGRID_API_KEY |
angel (57bde08e-…) |
App transactional mail |
| 3 | lastvet | R940 ECS API (prod + staging) | LASTVET_R940_PROD_SENDGRID_API_KEY, LASTVET_R940_STAGING_SENDGRID_API_KEY |
lastvet (93af53ce-…) |
Prod + staging are two keys, one product; 3 SendGrid templates per env in BWS |
| 4 | last1org-web | Cloudflare Pages Functions | CF Pages env (not in BWS) | — | Marketing contact/newsletter; lower stakes |
| 5 | veteransco-web | Cloudflare Pages Functions | CF Pages env (not in BWS) | — | Same cluster as row 4 |
| 6 | last1capital-web | Cloudflare Pages Functions | CF Pages env (not in BWS) | — | Same cluster as row 4 |
| 7 | last1studios-web | Cloudflare Pages Functions | CF Pages env (not in BWS) | — | Same cluster as row 4 |
| 8 | last1ent-web | Cloudflare Pages Functions | CF Pages env (not in BWS) | — | Same cluster as row 4 |
| 9 | radiocheck | Shared last1.app Supabase / Edge | LAST1APP_APP_PROD_SENDGRID_API_KEY (shared hosted project) |
last1-radiocheck (8a22f77d-…) |
Same hosted Supabase ref tcthzakppndkykatoefx as last1.app; likely one physical key for both rows 9 and 13 |
| 10 | onset | Onset app + Edge functions | ONSET_APP_PROD_SENDGRID_API_KEY |
onset (1c643206-…) |
Also referenced in VM 119 functions .env |
| 11 | realoutcomes (key A) | R940 app | REALOUTCOMES_APP_PROD_SENDGRID_API_KEY |
realoutcomes (788ed6ec-…) |
GG 29169499; T2-3 rotate at migration |
| 12 | realoutcomes (key B) | Investigate at migration | Not in BWS under second name | — | Ryan inventory flags two RealOutcomes keys. BWS shows one API key today. Likely sources: (a) legacy Railway env duplicate, (b) second consumer (Edge/cron) using a different env name, or (c) stale key retired but still in SendGrid account. Audit SendGrid dashboard + Railway backup before cutover. |
| 13 | last1.app | Monolith + GoTrue (hosted) + Edge | LAST1APP_APP_PROD_SENDGRID_API_KEY |
last1-radiocheck |
GG 29615727; key dead (401) per T2-3; GoTrue hosted SMTP still SendGrid (smtp.sendgrid.net) until Resend wired |
Marketing -web cluster (lower stakes)¶
Five Cloudflare Pages marketing sites (last1org-web, veteransco-web, last1capital-web, last1studio-web, last1ent-web) typically send contact-form / newsletter mail via Pages Functions (/api/send-email pattern; see last1org-web precedent in LAST1_ID_MARKETING_EXTRACTION_AUDIT.md).
Migration note: These may consolidate to one Resend sending identity (e.g. noreply@last1.org or hello@last1.enterprises) with per-site from display names, after domain verification audit.
Adjacent SendGrid consumers (not in Ryan 13-key list)¶
| Consumer | BWS key | Notes |
|---|---|---|
| last1-admin | LAST1ADMIN_APP_PROD_SENDGRID_API_KEY |
Ops digest / admin mail |
| LastVet SendGrid templates | LASTVET_R940_*_SENDGRID_PROVIDER_*_TEMPLATE_ID (×3 per env) |
Template IDs retire with provider swap |
| GoTrue hosted (last1.app) | Platform-managed via Supabase dashboard | Hosted smtp_admin_email=noreply@last1.org; Management API returns digest only for smtp_pass (same redaction as Apple OAuth secret) |
RealOutcomes duplicate-key investigation checklist¶
- List active API keys in SendGrid account; map each to RealOutcomes Railway export vs R940 BWS.
- Grep RealOutcomes repo for
SENDGRIDenv names (app vs Edge vs cron). - Confirm whether GG 29169499 is one leaked key or two distinct keys in git history.
- After audit: one Resend API key per environment (prod/staging if both exist), retire duplicates.
Resend target state (T5-A GoTrue slice)¶
| Setting | Target value |
|---|---|
| SMTP host | smtp.resend.com |
| Port | 465 (SSL) or 587 (STARTTLS) |
| User | resend |
| Pass | Resend API key from BWS |
| Admin / sender | Verified domain only (confirm in Resend dashboard: last1.app, last1.org, or other) |
BWS keys to add (last1-radiocheck): LAST1APP_DB_PROD_RESEND_API_KEY or LAST1APP_DB_PROD_SMTP_PASS, plus LAST1APP_DB_PROD_SMTP_ADMIN_EMAIL, optional LAST1APP_DB_PROD_SMTP_SENDER_NAME.
Script: scripts/last1app/configure-last1app-gotrue-resend-smtp.sh
§5c test: scripts/last1app/test-last1app-gotrue-smtp.sh (single recover email to ryan@last1.enterprises only).
Related¶
- POST_MIGRATION_ROADMAP.md §1 — uniform SendGrid→Resend pass (post-sovereignty)
- SPRINT7_T2-3_REPORT.md — last1.app SendGrid key dead before rotation
- SPRINT7_T5-A_REPORT.md — GoTrue Resend wiring (in progress)