Backend Deployment — barrins_api¶
Operational guide for ops/my-server/barrins_api.yml, the sole playbook
that deploys/restarts the shared barrins_api backend used by both
Tolaria News and Tamiyo Scroll. Structured per Constitution §37.1.
| Production | Staging | |
|---|---|---|
| Domain | api.barrins-codex.org |
api-staging.barrins-codex.org |
Local port (uvicorn) |
8011 |
8511 |
| systemd unit | api |
api-staging |
| Source | latest GitHub release tag (or -e fastapi_backend_release_tag=<tag> to pin) |
develop branch (or -e fastapi_backend_git_branch=<branch>) |
.env (local, git-ignored) |
secrets/barrins_api/production.env |
secrets/barrins_api/staging.env |
All commands below run from ops/my-server/.
Preparation¶
Server requirements — initial.yml and setup.yml must have run on
the host already (nginx, certbot, base user). One-time only.
Dependencies — none beyond what fastapi_backend/backend_website
install automatically (uv, a Python venv). The role detects
pyproject.toml vs requirements.txt and picks the right installer.
DNS — an A record for the target domain pointing at the server
(146.59.146.57). register_ssl (Let's Encrypt HTTP-01) fails silently
if this isn't propagated yet.
GitHub token — barrins_api.yml's github_token var (vaulted) needs
repo scope: read access to clone the repo and to query the Releases
API for production deploys. See ops/my-server/README.md's "GitHub
Token" section.
Release (production only) — barrins_api needs at least one GitHub
Release published before its first production deploy (ADR-2 in
../architecture/decisions.md). No
release exists yet → the playbook fails with a clear message rather than
silently falling back to a branch.
Environment variables — create the local .env for the target
environment from its template:
cp secrets/barrins_api/production.env.example secrets/barrins_api/production.env
# fill in real values — see the table below
| Variable | Notes |
|---|---|
DATABASE_URL |
Never the same database between production and staging — pointing staging at production's database means staging tests corrupt real data. |
ENVIRONMENT |
production on the prod instance, staging on staging. Gates whether SMTP_HOST/FRONTEND_BASE_URL are required (production only). |
ALLOWED_ORIGINS |
Must include the origin of every frontend calling this backend: ["https://tolaria.barrins-codex.org", "https://tamiyo.barrins-codex.org"] in production, the -staging equivalents in staging. JSON format. Missing an origin → the SPA loads but every API call fails CORS in the browser console. |
REQUIRE_EMAIL_VERIFICATION |
true by default. false skips SMTP/FRONTEND_BASE_URL requirements — a temporary workaround while SMTP isn't configured. |
FRONTEND_BASE_URL |
Single value used for the {FRONTEND_BASE_URL}/verify-email link. The backend serves multiple frontends but this can only point at one — decide which. Required (non-default) when ENVIRONMENT=production and REQUIRE_EMAIL_VERIFICATION=true. |
SMTP_HOST/SMTP_USERNAME/SMTP_PASSWORD |
Required under the same condition as FRONTEND_BASE_URL. Empty SMTP_HOST (with verification on) logs the code to the service's journal instead of sending email — useful on staging. |
SECRET_KEY |
openssl rand -hex 32. Refuses to start on a placeholder value. Use a different key per environment. |
Deployment¶
# Staging first
ansible-playbook barrins_api.yml -e deploy_env=staging
# Production, once staging is verified — deploys the latest release tag
ansible-playbook barrins_api.yml
Code-only redeploy (skip cert/nginx setup, already idempotent but
faster): add --tags deploy.
Apply pending database migrations (never automated — Constitution §31.3):
ssh spigushe.org
cd ~/projects/api.barrins-codex.org/apps/barrins_api # or api-staging.barrins-codex.org/apps/barrins_api
uv run alembic upgrade head
# or: source .venv/bin/activate && alembic upgrade head
Validation¶
curl -I https://api.barrins-codex.org/→301to/docs(no dedicated/healthroute inbarrins_apitoday — see the open item in../operations/index.md).journalctl -u api -f(orapi-staging) while a frontend exercises the API, to confirm requests are landing and check for startup errors (missing.envvalues, placeholderSECRET_KEY, etc.).- Exercise a real user flow through one of the frontends: signup (check
the verification code lands somewhere — email or, if
SMTP_HOSTis empty, the service log), deck creation, a match record.
Rollback¶
See rollback.md for the full procedure. Short version:
ansible-playbook barrins_api.yml -e fastapi_backend_release_tag=<previous-tag>
This rolls back the code. It does not roll back the database — read
rollback.md before rolling back a release that included a migration.
Troubleshooting¶
| Symptom | Likely cause |
|---|---|
| Playbook fails before touching the server, "repo has no GitHub release yet" | Cut a release on GitHub, or pin one with -e fastapi_backend_release_tag=<tag>. |
register_ssl fails on "certbot certonly" |
DNS not propagated to 146.59.146.57, or port 80 unreachable from the internet. |
Service won't start (systemctl status api/api-staging failing) |
Placeholder SECRET_KEY, or (production only) missing SMTP_HOST/FRONTEND_BASE_URL. Check journalctl -u <app_name> -n 50. |
| A frontend's SPA loads but every API call fails (CORS error in console) | That frontend's origin is missing from ALLOWED_ORIGINS. |
| Email verification links point at the wrong frontend | FRONTEND_BASE_URL is shared across every frontend this backend serves — only one can be correct until this becomes per-app aware. |
| A recent feature doesn't work even though the code is current | Migration not applied — alembic upgrade head is never automatic, see "Deployment" above. |
See also¶
frontend.md— the frontends that call this backend.rollback.md— full rollback procedure.ops/my-server/secrets/README.md— the.envworkflow in detail.../../../apps/barrins_api/README.md,../../../apps/barrins_api/.env.example— the full, authoritative list of backend variables, maintained in the application repo.