Environments and deployment framework
Four environments serve distinct purposes. Every system domain maintains all four before any code ships to production. No environment is optional and none may be bypassed in the promotion path.
Environment topology
| Environment |
Purpose |
Deployment trigger |
Infrastructure |
| local |
Developer iteration and rapid feedback |
Manual — framework emulator (e.g. sam local, serverless offline, LocalStack) |
Cloud provider emulators; external services mocked or pointed at dev sandboxes |
| dev |
Continuous integration baseline |
Every merge to main |
Full IaC, scaled to minimum, shared team instance |
| uat |
Pre-release verification |
Release candidate tag on main |
Full IaC, prod-equivalent config, reduced capacity |
| prod |
Live service |
Release tag + named approval gate |
Full IaC, production capacity, multi-region |
Code is never rebuilt between environments. The function artefact that passes UAT is the artefact deployed to prod — same content hash, no recompilation.
commit
→ PR → merge to main
→ dev pipeline: lint → unit tests → build artefact (content hash) → integration tests → deploy to dev → smoke tests
→ release candidate tag (vX.Y.Z-rc.N)
→ UAT pipeline: pull artefact → deploy to UAT → UAT/BDD suite → performance tests → security scan → promote artefact
→ release tag (vX.Y.Z) + approval
→ prod pipeline: pull promoted artefact → deploy to prod → smoke tests → live
↑ auto-rollback if smoke tests fail within 5 min
Manual deployments to dev, UAT, or prod are prohibited. A failed gate blocks promotion — no bypass without a documented exception approved under DT-007.
Pipeline stages
dev pipeline (trigger: merge to main)
| Stage |
Requirement |
On failure |
| Lint & static analysis |
Zero errors |
Block |
| Unit tests |
≥ 80% line coverage |
Block |
| Build artefact |
Packaged with content hash; stored in artefact registry |
Block |
| Integration tests |
All API contracts + key error paths pass |
Block |
| Deploy to dev |
IaC apply — idempotent |
Block |
| Smoke tests |
Key function invocations respond correctly |
Rollback dev deploy |
UAT pipeline (trigger: release candidate tag vX.Y.Z-rc.N)
| Stage |
Requirement |
On failure |
| Pull artefact |
Same hash as passed dev |
Block |
| Deploy to UAT |
IaC apply |
Block |
| UAT / BDD test suite |
All acceptance criteria in docs/systems/ pass |
Block |
| Performance tests |
p99 latency within NFR thresholds |
Block |
| Security scan |
No critical dependency CVEs; SAST clean |
Block |
| Promote artefact |
Tag as release candidate in artefact registry |
— |
prod pipeline (trigger: release tag vX.Y.Z + approval gate)
| Stage |
Requirement |
On failure |
| Approval gate |
Named approver confirms deployment |
Block |
| Pull promoted artefact |
Same hash as passed UAT |
Block |
| Deploy to prod |
IaC apply |
Block |
| Smoke tests |
Pass within 5 minutes |
Auto-rollback to previous version |
Infrastructure as code
All cloud resources are defined in code. Nothing is created or modified through a cloud console or direct API call outside of IaC. IaC tooling is not mandated here — see ADR-022 for options and selection criteria.
| Concern |
Approach |
| Cloud infrastructure |
SST v3 (Ion) with Pulumi as the infrastructure engine — resolved by ADR-025. State in S3 backend with DynamoDB locking. |
| Serverless configuration |
Function definitions, event sources, IAM bindings, and concurrency limits defined in IaC — not set manually. |
| Environment differences |
Variable overrides or stack parameters per environment applied to a shared IaC definition. No separate IaC codebases per environment. |
| Secrets |
Injected at runtime from secrets manager. Never in source code, artefacts, or pipeline logs. |
| Pipeline-to-cloud auth |
Short-lived OIDC tokens. No static credentials. |
| DNS, TLS, networking |
IaC-managed. No manual console edits. |
Testing requirements by module
Each module must ship all of the following before build_status can progress to Built:
| Type |
Scope |
Blocks |
| Unit tests |
Business logic, calculations, state machines |
dev deploy |
| Integration tests |
API contracts, event publishing, data round-trips |
dev deploy |
| Contract tests |
Consumer-driven contracts for inter-service calls |
dev deploy |
| UAT / BDD tests |
Acceptance criteria from module's docs/systems/ page |
UAT promotion |
| Performance tests |
p99 latency for any path with an NFR threshold |
UAT promotion |
| Security scans |
SAST, dependency vulnerability scan |
UAT promotion |
| Smoke tests |
Liveness check, one key function invocation |
Post-deploy |
Test definitions live in the code repository for each system domain, not in this wiki. The wiki documents the acceptance criteria that tests must cover.
Branch and release strategy
| Pattern |
Convention |
| Development |
Trunk-based. Short-lived feature branches (≤ 2 days), merge to main frequently. |
| Feature isolation |
Feature flags for partial work committed to main. No long-lived feature branches. |
| Release candidate |
Tag vX.Y.Z-rc.N on main to trigger UAT pipeline. Multiple RCs expected per release. |
| Release |
Tag vX.Y.Z on main after UAT passes. Triggers prod pipeline. |
| Hotfix |
Branch from latest release tag. Fast-track through the same pipeline gates — no gates skipped. |
| Versioning |
Semantic versioning. MAJOR for breaking API changes, MINOR for new capabilities, PATCH for fixes. |
Environment isolation
- Dev, UAT, and prod run in separate cloud accounts (or equivalent hard-boundary isolation).
- No cross-environment network paths. UAT cannot call dev services; prod cannot call UAT.
- Prod data never flows to dev or UAT. Test data is synthetic.
- Prod access requires just-in-time elevation with full audit trail. No standing access.