docs(adr): ADR-0002 — per-application environments via an env coordinate #15

Open
arcodange wants to merge 2 commits from claude/adr-multi-env into main
Owner

Summary

Adds ADR-0002 · Per-application environments — the architecture decision behind the multi-environment work currently rolling out across tools, factory, and erp.

The decision: extend the <app> join key with a second coordinate <env>, governed by an elision rule:

  • env defaults to prod and elides — when env == prod, every derived name is character-for-character identical to today's single-env output, so every existing app's tofu plan is a no-op and adoption needs zero migration.
  • Non-prod envs take the <app>-<env> kebab suffix everywhere, except the Postgres owner role which stays snake-case <app>_<env>_role.
  • One repo + one chart + one CI JWT role serve every env of an app.

Why it merits its own ADR (and the ADR-0001 reconciliation)

This is a genuine convention-level architecture change (it reshapes the <app> naming model documented in conventions.md). It also sits in apparent tension with ADR-0001, which rejected "sandbox namespace on the real cluster" (its Alternative 3). The ADR addresses this head-on rather than glossing it:

  • ADR-0001's rejection is scoped to rehearsing infrastructure change-classes (Ansible, Vault policy, Postgres superuser, ArgoCD prune, Longhorn, DNS) — those share fleet-wide control planes, so only a separate cluster isolates them. Hence ADR-0001 is local-only (k3d / VMs).
  • ADR-0002 operates one layer up: the AI agent's only reach is the Dolibarr HTTP API with a write-scoped key against an isolated database. It never touches kubectl/Vault-root/PG-superuser/ArgoCD/Longhorn/DNS, so the fleet blast radius that doomed Alternative-3-for-infra is not in scope.
  • The two are complementary; ADR-0002 does not supersede ADR-0001.

Files

  • vibe/ADR/0002-per-application-environments.md — the ADR (Status: Accepted, 2026-06-25).
  • vibe/ADR/README.md — index row + Last Updated bumped to 2026-06-25.
  • vibe/PRD/safe-prod-like-environment/README.md — bidirectional back-link to ADR-0002 on the Adjacent line + Last Updated bumped.

Implementing PRs (cross-linked from the ADR's References)

  • Phase A — tools#2: env/envs parameter on the shared app_roles + app_policy Vault modules.
  • Phase C — erp#11: chart literals templated to .Values (merged).

Process

Authored via the ADR Scribe persona (clean context), then validated via the Continuity Warden checklist: no-tombstone scan, breadcrumb first line, MADR-lite sections complete, all 6 relative links resolve, bidirectional links in place, Last Updated stamps bumped.

The ADR's References carries a placeholder "PR that introduces this ADR: to be linked once opened". I'll replace it with this PR's URL in a follow-up commit so the ADR↔PR crosslink is bidirectional.

🤖 Generated with Claude Code

## Summary Adds **[ADR-0002 · Per-application environments](vibe/ADR/0002-per-application-environments.md)** — the architecture decision behind the multi-environment work currently rolling out across `tools`, `factory`, and `erp`. The decision: extend the `<app>` join key with a second coordinate `<env>`, governed by an **elision rule**: - `env` defaults to `prod` and **elides** — when `env == prod`, every derived name is character-for-character identical to today's single-env output, so every existing app's `tofu plan` is a no-op and adoption needs zero migration. - Non-prod envs take the `<app>-<env>` kebab suffix everywhere, except the Postgres owner role which stays snake-case `<app>_<env>_role`. - One repo + one chart + one CI JWT role serve every env of an app. ### Why it merits its own ADR (and the ADR-0001 reconciliation) This is a genuine convention-level architecture change (it reshapes the `<app>` naming model documented in `conventions.md`). It also sits in apparent tension with **[ADR-0001](vibe/ADR/0001-safe-prod-like-environment.md)**, which rejected "sandbox namespace on the real cluster" (its Alternative 3). The ADR addresses this head-on rather than glossing it: - ADR-0001's rejection is scoped to rehearsing **infrastructure** change-classes (Ansible, Vault policy, Postgres superuser, ArgoCD prune, Longhorn, DNS) — those share fleet-wide control planes, so only a separate cluster isolates them. Hence ADR-0001 is local-only (k3d / VMs). - ADR-0002 operates **one layer up**: the AI agent's only reach is the Dolibarr HTTP API with a write-scoped key against an isolated database. It never touches kubectl/Vault-root/PG-superuser/ArgoCD/Longhorn/DNS, so the fleet blast radius that doomed Alternative-3-for-infra is not in scope. - The two are **complementary**; ADR-0002 does **not** supersede ADR-0001. ### Files - `vibe/ADR/0002-per-application-environments.md` — the ADR (Status: Accepted, 2026-06-25). - `vibe/ADR/README.md` — index row + `Last Updated` bumped to 2026-06-25. - `vibe/PRD/safe-prod-like-environment/README.md` — bidirectional back-link to ADR-0002 on the Adjacent line + `Last Updated` bumped. ### Implementing PRs (cross-linked from the ADR's References) - Phase A — [tools#2](https://gitea.arcodange.lab/arcodange-org/tools/pulls/2): `env`/`envs` parameter on the shared `app_roles` + `app_policy` Vault modules. - Phase C — [erp#11](https://gitea.arcodange.lab/arcodange-org/erp/pulls/11): chart literals templated to `.Values` (merged). ### Process Authored via the **ADR Scribe** persona (clean context), then validated via the **Continuity Warden** checklist: no-tombstone scan, breadcrumb first line, MADR-lite sections complete, all 6 relative links resolve, bidirectional links in place, `Last Updated` stamps bumped. > The ADR's References carries a placeholder "PR that introduces this ADR: _to be linked once opened_". I'll replace it with this PR's URL in a follow-up commit so the ADR↔PR crosslink is bidirectional. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
arcodange added 1 commit 2026-06-25 14:55:50 +02:00
Records the decision to extend the <app> join key with a second
coordinate <env>, governed by an elision rule (env=prod elides → every
existing app's derived names are byte-identical and its tofu plan is a
no-op; non-prod envs take the <app>-<env> suffix, with the Postgres
owner role staying snake-case <app>_<env>_role).

Motivated by the ERP's incoming write-capable AI-agent skill: it needs
an in-cluster sandbox instance (erp-sandbox) with a prod-like Dolibarr
API + isolated database to rehearse writes before a human promotes them
to prod. The ADR reconciles this against ADR-0001 honestly — ADR-0001
rejected an in-cluster sandbox for INFRA-change rehearsal (shared
fleet-wide control planes); ADR-0002 operates one layer up where the
agent's only reach is the app's HTTP API against an isolated DB, so the
fleet blast radius is not in scope. The two are complementary; ADR-0002
does not supersede ADR-0001.

Also:
- vibe/ADR/README.md: index row for 0002 + Last Updated 2026-06-25
- PRD safe-prod-like-environment README: bidirectional back-link to
  ADR-0002 on the Adjacent line + Last Updated 2026-06-25

Authored via the ADR Scribe persona, validated via the Continuity Warden
checklist (no-tombstone, breadcrumb, MADR-lite sections, dead-link scan,
bidirectional links).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arcodange added 1 commit 2026-06-25 14:56:17 +02:00
Replaces the placeholder References line with the PR URL so the
ADR↔PR crosslink is bidirectional per the AGENTS.md rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin claude/adr-multi-env:claude/adr-multi-env
git checkout claude/adr-multi-env
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: arcodange-org/factory#15