This guide describes a public-safe, cloud-neutral deployment path for carbon-platform-api. It uses generic platform terms and placeholder values only. Do not copy local demo credentials, real account details, private data, private hostnames, screenshots, or organization-specific architecture into this repository.
No infrastructure-as-code skeleton is included in this repository. A useful IaC template would need a target platform choice, and adding one without that context would either overbuild the portfolio project or risk embedding provider-specific assumptions. If IaC is added later, keep it minimal, secret-free, placeholder-only, and validate it with the platform's format and validation commands before committing it.
A production-style deployment can be assembled from these generic components:
API callers
-> HTTPS load balancer or ingress
-> carbon-platform-api container on port 8000
-> PostgreSQL database
-> Redis cache
-> optional carbon intensity provider endpoint
Metrics scraper
-> GET /metrics on the API container or service
Log collector
<- structured JSON logs from the API process
Recommended platform capabilities:
- A container runtime that can run the image built from this repository's
Dockerfile. - A managed or self-operated PostgreSQL database compatible with the async SQLAlchemy URL.
- A managed or self-operated Redis instance compatible with
redis://orrediss://URLs. - A secret store or environment injection mechanism for runtime settings.
- HTTPS termination before traffic reaches the API container.
- A metrics scraper that understands Prometheus text exposition.
Keep the API container stateless. PostgreSQL is the durable system of record; Redis stores cache entries and is not the source of truth.
Set runtime configuration with CARBON_API_* environment variables. Do not commit real values to source control, container images, screenshots, or tickets.
| Setting | Required for deployment | Guidance |
|---|---|---|
CARBON_API_APP_NAME |
Optional | Keep the default unless the platform needs a different display name. |
CARBON_API_APP_VERSION |
Recommended | Set to the deployed image or release version for log correlation. |
CARBON_API_ENVIRONMENT |
Recommended | Use a generic label such as staging or production. |
CARBON_API_LOG_LEVEL |
Recommended | Use INFO for normal operation; avoid verbose logs in shared environments. |
CARBON_API_DOCS_ENABLED |
Recommended | Keep false unless interactive docs are intentionally exposed in a controlled environment. |
CARBON_API_AUTH_ENABLED |
Recommended | Use true for any shared deployment because business endpoints are otherwise open. |
CARBON_API_AUTH_API_KEYS |
Required when auth is enabled | Supply opaque keys from a secret store. Rotate outside this repository. |
CARBON_API_DATABASE_URL |
Required | Supply a PostgreSQL URL for the target database. Treat it as a secret. |
CARBON_API_REDIS_URL |
Required for readiness/cache | Supply a Redis URL for the target cache. Treat credential-bearing URLs as secrets. |
CARBON_API_CARBON_INTENSITY_PROVIDER_BASE_URL |
Optional | Leave as a placeholder unless a public provider has been selected and tested. |
CARBON_API_CARBON_INTENSITY_PROVIDER_TIMEOUT_SECONDS |
Optional | Keep a small timeout so provider issues do not tie up workers. |
CARBON_API_CARBON_INTENSITY_CACHE_TTL_SECONDS |
Optional | Tune to match provider freshness needs if the intensity service is used. |
The local defaults in example.env are placeholders for Docker Compose demos only. Replace them for any shared environment.
Build a tagged container image from a clean, tested commit:
docker build -t registry.example.invalid/carbon-platform-api:0.1.0 .Push the image to the selected registry using the platform's normal authenticated workflow:
docker push registry.example.invalid/carbon-platform-api:0.1.0The registry hostname and tag above are placeholders. Use immutable release tags or digests for repeatable rollbacks. Do not bake runtime secrets into the image; inject them at runtime.
The API does not auto-run Alembic migrations at startup. Run migrations as an explicit release step after backing up the target database and before sending production traffic to a new application version.
Example migration command with placeholder values:
CARBON_API_DATABASE_URL='postgresql+asyncpg://<user>:<password>@<host>:5432/<database>' \
uv run alembic upgrade headRecommended migration practice:
- Confirm the target database is reachable from the migration runner.
- Confirm the migration runner has schema-change permissions.
- Run
uv run alembic upgrade headexactly once per release environment. - Save the command output with the release notes.
- Start or roll forward API containers only after migrations succeed.
Avoid destructive schema changes unless a tested rollback and data recovery plan exists.
Run the container command from the Dockerfile or an equivalent ASGI server command:
uvicorn carbon_platform_api.main:app --host 0.0.0.0 --port 8000
Expose container port 8000 behind the platform's HTTPS load balancer or ingress. Configure health probes with the existing operational endpoints:
| Probe | Endpoint | Expected use |
|---|---|---|
| Liveness | GET /healthz |
Confirms the API process can answer lightweight requests without dependency checks. |
| Readiness | GET /readyz |
Confirms PostgreSQL and Redis connectivity before the instance receives traffic. |
| Metrics | GET /metrics |
Provides Prometheus-compatible process and HTTP request metrics. |
Suggested starting probe values:
- Liveness initial delay: 10 seconds.
- Liveness period: 30 seconds.
- Readiness period: 10 seconds.
- Probe timeout: 5 seconds.
GET /healthz, GET /readyz, and GET /metrics intentionally remain unprotected by API key auth. Place them behind platform network controls if the deployment is reachable beyond a trusted operations boundary.
Use a boring release sequence:
- Run
scripts/quality-gate.shon the release commit. - Build and push an immutable image tag or digest.
- Provision PostgreSQL and Redis with backups enabled where the platform supports it.
- Configure runtime settings through the platform's environment and secret mechanisms.
- Run
uv run alembic upgrade headagainst the target database. - Deploy the API container image.
- Check
GET /healthz,GET /readyz, andGET /metrics. - Send a small authenticated smoke request to a business endpoint if auth is enabled.
- Watch structured JSON logs, request error rates, readiness status, and latency during the rollout window.
Prefer rollback steps that keep data safe:
- Stop sending new traffic to the failing release.
- Redeploy the previous known-good image tag or digest.
- Confirm
GET /healthzandGET /readyzare healthy on the rolled-back version. - Review logs for migration or compatibility errors before scaling traffic back up.
Database rollback needs extra care. Alembic downgrades can remove schema or data, so do not run them automatically. If a schema rollback is required, restore from backup or run a tested targeted downgrade after confirming the exact revision and data impact:
CARBON_API_DATABASE_URL='postgresql+asyncpg://<user>:<password>@<host>:5432/<database>' \
uv run alembic downgrade <target-revision>Design future migrations to be backward compatible when possible: deploy additive schema changes first, roll application code second, and remove old columns only after all old application versions are gone.
| Risk | Mitigation |
|---|---|
| Migrations are skipped | Keep migrations as a required release step and fail deployment if uv run alembic upgrade head fails. |
| Runtime secrets leak | Store API keys and connection URLs outside source control and avoid logging raw environment values. |
| Operational endpoints are exposed | Restrict access with platform networking controls while keeping probes and metrics functional. |
| Database and application versions drift | Tag images immutably and record the Alembic revision applied for each release. |
| Redis is unavailable | /readyz reports Redis as unhealthy; cached carbon intensity lookups should be treated as unavailable until Redis recovers. |
| Carbon intensity provider is unavailable | Keep provider timeouts small and rely on mockable service boundaries; current business endpoints do not call the provider. |
| Demo carbon factors are misunderstood | Document that estimates are deterministic demo values, not authoritative measurements. |
| Observability is incomplete | Add platform-native logs, metrics scraping, and alerts; this repository only includes local Prometheus/Grafana examples. |
- No real cloud accounts, hostnames, credentials, or organization-specific deployment details.
- No CI deployment jobs.
- No secret-management integration code.
- No Terraform, Kubernetes, or other IaC files.
- No production hardening for Grafana or hosted monitoring.
These omissions are intentional for a public portfolio project. Add platform-specific deployment automation only in a separate, bounded ticket with secret-free placeholders and validation checks.