Bitwarden naming convention — Last1 products¶
Date: 2026-08-10 (R940 authority update 2026-08-18)
Status: Approved standard. R940 is live; AWS ECS keys are historical only.
Purpose¶
One greppable pattern across Bitwarden Secrets Manager projects so operators can:
- Distinguish staging vs prod vs shared values on R940
- Separate product-owned secrets from cross-product platform secrets
- Map BWS storage names to runtime env vars via deploy scripts (no application renames required for LastVet API)
Pattern¶
| Segment | Allowed values | Meaning |
|---|---|---|
| PRODUCT | LASTVET, ANGEL, SOVEREIGN, MERIDIAN, LAST1, plus Railway→R940 product codes below |
Owning product. Use LAST1 / LAST1_PLATFORM only for the last1-platform project (cross-product). Do not use a universal LAST1_R940_* dump for every app. |
| TARGET | R940, RAILWAY, CLOUDFLARE, EDGE, IOS, SHARED, TEST, AWS (retired) |
Where the value is consumed or which infra lane it belongs to. AWS is historical only (ECS retired August 2026). |
| ENV | STAGING, PROD |
Logical environment. Omit for global/shared secrets (e.g. Cloudflare account ID). |
| PURPOSE | SNAKE_CASE slug |
Role of the secret. For API runtime mirrors, suffix with the runtime var name when helpful. |
grep cheatsheet¶
bws secret list | jq -r '.[].key' | grep '_R940_' # all R940-scoped
bws secret list | jq -r '.[].key' | grep '^LASTVET_' # all LastVet
bws secret list | jq -r '.[].key' | grep '^LAST1_' # platform project
bws secret list | jq -r '.[].key' | grep '_RAILWAY_' # rollback net only
Bitwarden projects¶
| Project | ID | Holds |
|---|---|---|
lastvet |
93af53ce-9afe-45e9-948d-b47a014a75d9 |
LastVet API, edge, R940 DB/MinIO, iOS-shared API secrets |
angel |
57bde08e-39ff-4989-9b0e-b48800118fa6 |
Angel API/web Workers, Neon, R2, Ollama lane |
sovereign |
6f7c74e0-47c7-421a-8f64-b4a00120dc74 |
Sovereign client + Odysseus/MemPalace runtime (currently empty) |
last1-platform |
(create) | Cross-product: token encryption, Onset assertion, shared Cloudflare IDs |
meridian |
(create) | Eval harness Ollama, VA sandbox fixture tokens, telemetry |
last1-test |
(create, optional) | E2E harness, non-prod automation mailboxes |
proxmox |
73c620d6-e7fc-425d-9742-b49e00fcb553 |
Out of product scope; do not merge into product projects |
Runtime mapping rule¶
Application code keeps canonical env var names. BWS keys are operator storage names only.
Deploy scripts (systemd, restore-api-env-from-bws.sh, secrets-pull.sh, Wrangler push) map:
LASTVET_R940_STAGING_DATABASE_APP_URL → export DATABASE_APP_URL=...
LAST1_PLATFORM_STAGING_TOKEN_ENCRYPTION_KEY → export LAST1_TOKEN_ENCRYPTION_KEY=...
ANGEL_R940_SHARED_OLLAMA_BASE_URL → wrangler secret put OLLAMA_BASE_URL
SOVEREIGN_R940_SHARED_ENGINE_URL → VITE_ENGINE_URL=... at build time
LastVet API never reads LASTVET_R940_* directly in TypeScript.
Cross-product policy (Ryan decisions 2026-08-10)¶
| Secret | Home | Per-env copies |
|---|---|---|
LAST1_TOKEN_ENCRYPTION_KEY |
last1-platform |
Yes: LAST1_PLATFORM_STAGING_* and LAST1_PLATFORM_PROD_* (distinct per env; generate in BWS, never reuse across security domains) |
ONSET_IDENTITY_ASSERTION_SECRET |
last1-platform |
Single LAST1_PLATFORM_SHARED_ONSET_IDENTITY_ASSERTION_SECRET unless Onset requires split |
| Ollama base URL | Per product | ANGEL_R940_SHARED_OLLAMA_BASE_URL, LASTVET_R940_SHARED_OLLAMA_BASE_URL, SOVEREIGN_R940_SHARED_OLLAMA_BASE_URL → http://inference-01.tailc3bbdc.ts.net:11434 |
| Cloudflare account ID | last1-platform |
LAST1_PLATFORM_SHARED_CLOUDFLARE_ACCOUNT_ID |
| Cloudflare API token | last1-platform (optional consolidate) |
Single operator token or per-repo deploy tokens (Ryan to confirm) |
Examples by product¶
LastVet¶
| BWS key | Runtime / use |
|---|---|
LASTVET_AWS_STAGING_DATABASE_APP_URL |
Retired. ECS staging (AWS decommissioned August 2026). |
LASTVET_R940_STAGING_DATABASE_APP_URL |
DATABASE_APP_URL on lastvet-api VM (staging systemd) |
LASTVET_R940_PROD_DATABASE_APP_URL |
DATABASE_APP_URL on lastvet-api VM (prod systemd) |
LASTVET_R940_STAGING_MIGRATION_DATABASE_URL |
MIGRATION_DATABASE_URL (full URL, lastvet_master role, staging) |
LASTVET_R940_PROD_MIGRATION_DATABASE_URL |
MIGRATION_DATABASE_URL (prod) |
LASTVET_R940_STAGING_VETERAN_JWT_SECRET |
VETERAN_JWT_SECRET (staging). Distinct from OAUTH_JWT_SECRET, SECURE_LINK_HMAC_SECRET, LAST1_TOKEN_ENCRYPTION_KEY, and prod counterpart. Generate in BWS; do not copy from retired AWS keys. |
LASTVET_R940_PROD_VETERAN_JWT_SECRET |
VETERAN_JWT_SECRET (prod). Same distinct-secret rule as staging. |
LASTVET_R940_STAGING_SECURE_LINK_HMAC_SECRET |
SECURE_LINK_HMAC_SECRET (staging). Distinct from token encryption and JWT secrets. |
LASTVET_R940_PROD_SECURE_LINK_HMAC_SECRET |
SECURE_LINK_HMAC_SECRET (prod). |
LASTVET_R940_STAGING_VETERAN_SESSION_EXCHANGE_SECRET |
iOS Debug + lastvet-api-staging (retired name: LASTVET_AWS_STAGING_VETERAN_SESSION_EXCHANGE_SECRET) |
LASTVET_R940_PROD_VETERAN_SESSION_EXCHANGE_SECRET |
iOS Release + lastvet-api-prod (retired name: LASTVET_AWS_PROD_VETERAN_SESSION_EXCHANGE_SECRET) |
LASTVET_EDGE_CLOUDFLARED_TUNNEL_TOKEN |
cloudflared on lastvet-edge |
LASTVET_RAILWAY_STAGING_DATABASE_APP_URL |
Retired. Rollback net torn down before VA production PHI. |
Angel¶
| BWS key | Runtime / use |
|---|---|
ANGEL_CLOUDFLARE_PROD_DATABASE_URL |
Worker DATABASE_URL (Neon today) |
ANGEL_CLOUDFLARE_PROD_SESSION_SECRET |
Worker SESSION_SECRET |
ANGEL_R940_SHARED_OLLAMA_BASE_URL |
Worker OLLAMA_BASE_URL |
ANGEL_R940_SHARED_OLLAMA_MODEL |
Worker OLLAMA_MODEL |
ANGEL_CLOUDFLARE_PROD_R2_ACCESS_KEY_ID |
Worker R2_ACCESS_KEY_ID |
Local docker-compose keys (POSTGRES_*, MINIO_*, REDIS_URL) stay out of production BWS or under ANGEL_LOCAL_DEV_* if stored at all.
Sovereign¶
| BWS key | Build-time mapping |
|---|---|
SOVEREIGN_R940_SHARED_ENGINE_URL |
VITE_ENGINE_URL (Odysseus engine on R940; replaces unicorn.*:7000) |
SOVEREIGN_R940_SHARED_ENGINE_URL_LOCAL |
VITE_ENGINE_URL_LOCAL |
last1-platform¶
| BWS key | Consumers |
|---|---|
LAST1_PLATFORM_STAGING_TOKEN_ENCRYPTION_KEY |
LastVet API staging (+ any product using Last1 OAuth token storage) |
LAST1_PLATFORM_PROD_TOKEN_ENCRYPTION_KEY |
LastVet API prod |
LAST1_PLATFORM_SHARED_ONSET_IDENTITY_ASSERTION_SECRET |
LastVet API, Onset Supabase |
LAST1_PLATFORM_SHARED_CLOUDFLARE_ACCOUNT_ID |
wrangler, GitHub Actions |
Meridian¶
| BWS key | Runtime mapping |
|---|---|
MERIDIAN_R940_SHARED_OLLAMA_BASE_URL |
OLLAMA_BASE_URL |
MERIDIAN_R940_SHARED_OLLAMA_MODEL |
OLLAMA_MODEL |
MERIDIAN_TEST_VA_SANDBOX_ACCESS_TOKEN |
VA_SANDBOX_ACCESS_TOKEN |
Extension — Railway / Supabase → R940 product prefixes (2026-08-20)¶
Decision (proposed; Ryan to approve): Per-product prefixes, not a universal LAST1_R940_* namespace.
Why not universal: LAST1 already means cross-product platform (last1-platform). A catch-all LAST1_R940_* would collide with that meaning, weaken blast-radius grep, and fight the existing LASTVET_ / ANGEL_ / SOVEREIGN_ / MERIDIAN_ pattern.
Product codes for consolidating apps:
| Product | BWS PRODUCT segment | Example key | Suggested BWS project |
|---|---|---|---|
| last1.id | LAST1ID |
LAST1ID_R940_PROD_DATABASE_URL |
last1id (create) |
| Onset / clinic.theonset.app | ONSET |
ONSET_R940_PROD_DATABASE_URL |
onset (create) |
| last1.app | LAST1APP |
LAST1APP_R940_PROD_DATABASE_URL |
last1app (create) or shared with RadioCheck until DB split |
| RadioCheck | RADIOCHECK |
RADIOCHECK_R940_PROD_SERVICE_ROLE_KEY |
shared with last1.app while Supabase project tcthzakppndkykatoefx remains one DB |
| RealOutcomes | REALOUTCOMES |
REALOUTCOMES_R940_PROD_DATABASE_URL |
realoutcomes (create) |
| last1-admin | LAST1ADMIN |
LAST1ADMIN_R940_PROD_SESSION_SECRET |
stays in last1-admin project |
| n8n | N8N |
N8N_R940_PROD_ENCRYPTION_KEY |
last1-admin or last1-platform ops |
Shared-DB exception: last1.app + RadioCheck (+ last1-admin auth) currently share one Supabase project. Until that DB is split, store one Postgres URL under a single agreed owner key (prefer LAST1APP_R940_* as the DB owner; RadioCheck maps the same runtime DATABASE_URL). Do not duplicate divergent copies.
Still cross-product (last1-platform only): token encryption, Onset identity assertion, shared Cloudflare account ID, and any secret consumed by ≥2 product security domains.
Runtime mapping rule unchanged: apps keep canonical env names (DATABASE_URL, SUPABASE_SERVICE_ROLE_KEY, …). systemd / restore scripts map PRODUCT_R940_ENV_PURPOSE → runtime.
Planning context: LAST1_INFRASTRUCTURE_CONSOLIDATION_PLAN.md.
Anti-patterns (do not use)¶
| Bad | Why |
|---|---|
DATABASE_APP_URL_STAGING |
No product or target; caused Railway/AWS/R940 confusion |
LASTVET_APP_PASSWORD_PRODUCTION |
Implies prod generically; was Railway-only |
OLLAMA_BASE_URL in angel without prefix |
Not greppable; hid product scope |
| Storing runtime names without target/env | Ambiguous grep; use LASTVET_R940_{STAGING,PROD}_* |
| Duplicating cross-product keys in every product project | Rotation drift; use last1-platform |
| Copying retired AWS secret values into R940 keys | Preserves key reuse; generate distinct values per env |
LAST1_R940_* for every consolidating app |
Collides with platform namespace; prefer LAST1ID_ / ONSET_ / LAST1APP_ / … |
Related documents¶
../deployment/R940_ENVIRONMENT_TOPOLOGY.md— R940 lane hard walls (canonical)BITWARDEN_ENV_AUDIT_FULL.md— runtime env catalogsBITWARDEN_HYGIENE_PLAN_FULL.md— migration sequence and tableLAST1_INFRASTRUCTURE_CONSOLIDATION_PLAN.md— Railway/Supabase → R940 consolidation plan- PR #8 (LastVet-only predecessor):
docs/lastvet/BITWARDEN_*on branchbitwarden-hygiene-plan