ADR 13: Twelve-Factor App Methodology
Status: Accepted Date: 2026-04-10
Context
Substratum's cloud infrastructure, specifically the apps/gateway API and P2P node, must be highly available, horizontally scalable, and easy to deploy across environments (e.g., local development, staging, DigitalOcean production). To ensure our architecture remains robust and cloud-native, we need a formalized set of rules governing configuration, logging, and process management.
Decision
We will strictly adhere to the Twelve-Factor App methodology for all deployable applications in the Substratum monorepo.
For our Rust backend (apps/gateway), this requires specific technical implementations:
- Config (III): We will store all configuration in the environment. The
gatewaywill use thedotenvycrate for local development but rely purely on environment variables (e.g.,DATABASE_URL,S3_ENDPOINT,OAUTH_PRIVATE_KEY) in production. No secrets or environment-specific configs will be hardcoded. - Disposability (IX): We will implement graceful shutdown using Tokio's signal handling. Upon receiving a
SIGTERM, the Axum web server will stop accepting new connections, finish processing active HTTP requests, cleanly close the SeaORM database pool, and gracefully disconnect thelibp2pswarm before exiting. - Dev/Prod Parity (X): We will use
docker-compose.ymlto spin up local instances of PostgreSQL and an S3-compatible object store (like MinIO). This ensures local development perfectly mirrors our DigitalOcean Managed Database and Spaces production environment. - Logs (XI): We will treat logs as event streams. The
gatewaywill not write to local log files. Instead, it will use thetracingandtracing-subscribercrates to output structured JSON logs directly tostdout, allowing the hosting provider to capture and route them. - Admin Processes (XII): Database migrations will not run automatically on application startup. We will use the SeaORM CLI (
sea-orm-cli migrate up) as a one-off administrative process executed during the deployment pipeline.
Consequences
- Positive:
- Scalability: The
gatewayremains entirely stateless, allowing us to scale horizontally behind a DigitalOcean Load Balancer without conflict. - Portability: By treating backing services (PostgreSQL, S3) as attached resources via environment variables, we can easily migrate between cloud providers if necessary.
- Reliability: Graceful shutdown prevents data corruption and dropped connections during deployments.
- Scalability: The
- Negative:
- Boilerplate: Requires additional setup in the Rust
mainfunction to wire uptracing, signal handlers, and environment variable parsing. - Operational Discipline: Developers must strictly avoid writing state to the local filesystem or relying on local configuration files in production.
- Boilerplate: Requires additional setup in the Rust