Skip to content

R940 Naming Convention v1 (NAMING-3)

Status: Canonical as of 2026-08-29 (NAMING-2 executed).
Supersedes: Ad-hoc *-r940 / *-supabase hostnames and {PRODUCT}_R940_PROD_* BWS prefixes.
Cross-reference: R940_PRODUCT_ISOLATION_PRINCIPLES_v1.md


1. Design intent

All product workloads on the R940 Proxmox cluster use role-based names (-app, -db) instead of location suffixes (-r940) or vendor labels (-supabase). The hypervisor is R940 by definition; self-hosted database stacks replace hosted Supabase per product.

Infrastructure VMs (identity, observability, edge connectors with dedicated tunnel names) keep their existing names unless Ryan directs otherwise.


2. VM naming

Role Pattern Examples
Product application {product}-app admin-app, realoutcomes-app, onset-app, n8n-app
Product database / stack {product}-db realoutcomes-db, onset-db
Single-VM product {product}-app n8n-app (was n8n-r940)
Identity auth-last1id unchanged
Identity DB sovereign-db-last1id unchanged
Observability observability unchanged
Dedicated edge tunnels lastvet-edge, last1id-edge tunnel names unchanged
Product edge tunnels {product}-edge tunnel name unchanged; runs on {product}-app

Proxmox: VM display name matches guest hostname. Cloud-init snippets: {product}-app-user.yaml, {product}-db-user.yaml.

LAN IPs: Stable; see R940_LAN_NETWORK_INVENTORY.md. Never assign 192.168.1.100 (iDRAC/BMC).


3. BWS secret prefixes

Scope Pattern Example
App-tier prod secrets {PRODUCT}_APP_PROD_{KEY} REALOUTCOMES_APP_PROD_SESSION_SECRET
DB-tier prod secrets {PRODUCT}_DB_PROD_{KEY} REALOUTCOMES_DB_PROD_DATABASE_URL
Edge (on app VM) {PRODUCT}_APP_EDGE_{KEY} REALOUTCOMES_APP_EDGE_TUNNEL_ID
Platform n8n N8N_APP_PROD_{KEY} in last1-platform project N8N_APP_PROD_ENCRYPTION_KEY

DB vs APP split (required for {product}-app + {product}-db products)

{PRODUCT}_DB_PROD_* (stack / Postgres / Kong):

  • DATABASE_URL, SUPABASE_URL, SUPABASE_POOLER_URL
  • POSTGRES_PASSWORD, JWT_SECRET
  • SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY

{PRODUCT}_APP_PROD_* (application runtime, build, integrations):

  • Stripe, SendGrid, OAuth, session secrets, PUBLIC_URL, cron secrets
  • VITE_SUPABASE_*, NEXT_PUBLIC_SUPABASE_* (build-time; values mirror DB stack)

App-only products (e.g. admin-app, n8n-app): all secrets under {PRODUCT}_APP_PROD_* only.

Out of scope (separate conventions)

  • LAST1ID_* / LAST1_ID_* — identity (auth-last1id)
  • LASTVET_* — LastVet platform
  • LAST1_PLATFORM_* — shared platform ops (except N8N_APP_*)

4. DNS and staging

Purpose Pattern
Staging app {product}-app.last1.enterprises
Staging DB / Kong (browser auth E2E) {product}-db.last1.enterprises
Production Product domain (realoutcomes.app, clinic.theonset.app, etc.)

Production DNS is not tied to VM hostname. Cloudflare tunnel ingress uses origin IPs or LAN URLs; tunnel names (realoutcomes-edge, onset-edge) stay stable.


5. Observability labels

Layer Pattern
Health probe metrics {product}_app_probe_*
Supabase reachability {product}_app_supabase_reachable
Loki host label {product}-app
Prometheus node scrape By IP (stable across renames)

Alert names keep product semantics (RealOutcomesHostDown, AdminHealthProbeFailed); annotations reference new hostnames.


6. Scripts and deploy artifacts

Artifact Pattern
Deploy script deploy-{product}-app.sh
Env render render-{product}-env-app.sh (reads APP + DB prefixes)
Stack → BWS push-db-stack-bws.py
Railway sync sync-app-bws-from-railway.py (skips DB keys)
Docker image tag {product}-app:prod

7. Future migrations

Applies to:

  • last1.app + RadioCheck bundle (admin reconnect)
  • MATR and any new R940 product
  • Remaining Tier work after Onset T-3

Checklist for new product:

  1. Provision {product}-app (+ {product}-db if self-hosted stack)
  2. Create BWS project or prefix family: {PRODUCT}_APP_PROD_*, {PRODUCT}_DB_PROD_*
  3. Product edge tunnel {product}-edge on app VM
  4. Prometheus scrape by IP; probe metrics {product}_app_probe_*
  5. No -r940 or -supabase in any new name

8. Rename history

Full inventory and execution log: VM_NAMING_RENAME_AUDIT.md (NAMING-1 approved 2026-08-29; NAMING-2 executed same day).

VMID Old New
112 n8n-r940 n8n-app
115 admin-r940 admin-app
116 realoutcomes-r940 realoutcomes-app
117 realoutcomes-supabase realoutcomes-db
118 onset-r940 onset-app
119 onset-supabase onset-db

9. Operational lessons (post-NAMING-2)

Discovered during RealOutcomes directory 500 regression (REALOUTCOMES_DIRECTORY_500_DIAGNOSTIC.md). Apply to every product migration and BWS prefix rename.

9.1 BWS copy ≠ validated DB connection

When copying {PRODUCT}_R940_* → {PRODUCT}_APP_* / {PRODUCT}_DB_*, values carry stale references forward (e.g. deleted hosted Supabase pooler URLs). Never trust copied DATABASE_URL / SUPABASE_URL without re-validation.

Canonical source for DB connection strings: live {product}-db VM via push-db-stack-bws.py, not BWS from an earlier migration step or Railway sync.

Required after any BWS prefix rename or key copy:

  1. Run scripts/{product}/push-db-stack-bws.py against live {product}-db.
  2. Confirm {PRODUCT}_DB_PROD_DATABASE_URL host is {product}-db LAN IP (or pooler on :6543), not *.supabase.co or aws-*-pooler.supabase.com (unless product is intentionally hosted-only, e.g. admin until Tier 6).
  3. Re-render app .env from APP + DB prefixes.

9.2 Docker env reload

docker restart does not re-read --env-file. Env is fixed at docker run / container create time.

After any .env change: remove and recreate the container (or run deploy-{product}-app.sh). Never rely on restart alone for connection-string fixes.

9.3 Product classes

Class DB BWS target Example
Sovereign stack ({product}-app + {product}-db) {PRODUCT}_DB_PROD_* → LAN {product}-db RealOutcomes, Onset
Downstream BFF (no own DB VM) {PRODUCT}_APP_PROD_* → hosted Supabase until upstream migrates last1-admin (paused, Tier 6)
Gate B / migration-only Separate key (e.g. ONSET_HOSTED_DATABASE_URL) Hosted dump source; not app runtime

See R940_MIGRATION_PLAYBOOK.md for step-by-step checklist.


References