Deployment
The reference deployment target for Share Your Thoughts With Me is Azure Container Apps with a
managed Postgres Flexible Server alongside. The ACA ingress is the only
reverse proxy in the stack: it terminates TLS, manages the custom-domain
certificates for shareyourthoughtswith.me and sytw.me, and forwards plain
HTTP to the app container on port 8000. No additional nginx/Caddy container
is required.
High-level topology
- Azure Container App running the Share Your Thoughts With Me image (built from
Dockerfile). - Azure Postgres Flexible Server for durable storage.
- Azure Key Vault as the only source of truth for app secrets.
- Custom domains
shareyourthoughtswith.meandsytw.mebound to the same Container App. The app'sHostRedirectMiddleware301-redirectssytw.merequests to the canonicalshareyourthoughtswith.me.
Provisioning
Infrastructure lives in infra/terraform/. Apply it once per environment:
cd infra/terraform
terraform init \
-backend-config="subscription_id=<state-storage-sub>" \
-backend-config="resource_group_name=<state-rg>" \
-backend-config="storage_account_name=<state-sa>"
terraform apply -var-file=env/prod.tfvars -var-file=env/prod.secrets.tfvars
Subsequent app deploys are CI-driven via the Jenkinsfile in the repo root
and do not run Terraform.
Operator handoff steps after first apply
- Bind
shareyourthoughtswith.meandsytw.meto the Container App's managed certificate (Terraform issues the binding; the cert is provisioned asynchronously by ACA — verify withaz containerapp hostname list). - Confirm the Container App's environment variables (
SYTWM_*) are wired to the corresponding Key Vault secrets. - Run the first deploy via Jenkins or manually:
az containerapp update --name sytwm-app --image <acr>.azurecr.io/sytwm:<tag> - Verify health at
https://shareyourthoughtswith.me/health.
Local development
docker compose up spins up a local Postgres and the app:
cp .env.example .env
docker compose up --build
# App at http://localhost:8000
Run tests outside Docker:
uv sync --all-extras
uv run pytest
CI/CD
The Jenkinsfile follows the gold-standard pattern: it infers DEPLOY_ENV
from the job name, reads Azure IDs from infra/terraform/env/<env>.json,
builds and pushes to ACR via scripts/build.sh, runs migrations via
scripts/run-migrations.sh, deploys via scripts/deploy.sh, and verifies via
the Health Check stage.