R940 Product Isolation Principles v1¶
Status: Approved (Ryan, 2026-08-29 sprint kickoff)
Supersedes: conflicting guidance in PRODUCTS_ISOLATION_ARCHITECTURE_2026-08-29.md §1.3 (shared Caddy-only product ingress)
Scope: Last 1 portfolio R940 migrations (Tiers 3–8)
1. Ingress¶
| Edge | Host | cloudflared location | Role |
|---|---|---|---|
| lastvet-edge | lastvet-edge VM .89 |
lastvet-edge VM |
LastVet only — clinical API, provider surfaces. Do not add product or auth routes. |
| last1id-edge | auth-last1id VM .96 |
Same VM as origin (Option A) | Platform identity only — auth.last1.id → Kong :8000 |
| realoutcomes-edge | realoutcomes-app VM .99 |
Product app VM | realoutcomes.app → app :5000; optional Supabase Kong hostname if browser needs Storage/Functions |
| onset-edge | Onset app VM (TBD) | Product app VM | Onset apex + optional Supabase hostname |
| last1app-edge | last1.app app VM (TBD) | Product app VM | last1.app + RadioCheck bundle (shared Supabase) |
| admin-edge | admin-app VM .97 |
Product app VM | admin.last1.enterprises |
Rationale: Two Cox static IPs and no Netgate multi-IP NAT yet → per-product Cloudflare Tunnels instead of shared grey-cloud Caddy for all products. LastVet keeps dedicated edge unchanged.
LastVet API note: api.last.vet may use Cox + Caddy grey-cloud in parallel with lastvet-edge tunnel entries for rollback. Do not conflate with product tunnels.
2. Identity¶
| Rule | Detail |
|---|---|
| Single IdP | All products authenticate via https://auth.last1.id |
| Integration | @last1id/sdk (OIDC redirect + JWT validation). No product-local GoTrue at steady state. |
| Product Supabase | Postgres, PostgREST, Storage, Edge Runtime only — GoTrue retired after unification |
| Migration | Google/email users re-link to sovereign identities; remap public.users FKs |
3. Execution gates¶
| Sprint | Product / scope | Ryan gate before next |
|---|---|---|
| SPRINT-1 | last1id-edge + DNS cutover |
Required before SPRINT-2 |
| SPRINT-2 | RealOutcomes auth unification | Required before SPRINT-3 |
| SPRINT-3 | RealOutcomes realoutcomes-edge + DNS |
Required before SPRINT-4 |
| SPRINT-4 | RealOutcomes E2E (Ryan browser) | PASS required before SPRINT-5 |
| SPRINT-5 | RealOutcomes teardown | — |
| SPRINT-6 | Onset (real users — extra care) | — |
| SPRINT-7 | last1.app + RadioCheck bundle | — |
| SPRINT-8 | Admin reconnect + teardown | After all upstream sovereign |
No soak periods. End-to-end execution with explicit STOP between sprints.
4. Invariants (do not drift)¶
- Never add
auth.last1.idtolastvet-edgeagain. - Never add RealOutcomes/Onset/admin hostnames to
lastvet-edge. - Each product tunnel runs on that product's app VM (Option A).
- Document tunnel UUID + CNAME target in BWS (
*_EDGE_CLOUDFLARED_*keys). - Onset: verify with real family/friend users before Railway/Supabase teardown.
5. VM reference (current)¶
| VMID | Hostname | LAN IP | Tunnel |
|---|---|---|---|
| 110 | lastvet-edge | .89 |
lastvet-r940 (LastVet only) |
| 114 | auth-last1id | .96 |
last1id-edge |
| 116 | realoutcomes-app | .99 |
realoutcomes-edge (SPRINT-3) |
| 117 | realoutcomes-db | .98 |
LAN-only; optional Kong via realoutcomes-edge |
| 115 | admin-app | .97 |
admin-edge (SPRINT-8) |
6. References¶
- PRODUCTS_ISOLATION_ARCHITECTURE_2026-08-29.md — audit that led to this reconciliation
scripts/last1-id/install-last1id-edge-cloudflared.sh— SPRINT-1 installscripts/last1-id/verify-last1id-edge.sh— PF checksscripts/last1-id/remove-auth-route-from-lastvet-edge.sh— lastvet-edge cleanup