Deploy Runbook — qgtmai.com / api.qgtmai.com
This runbook covers the repo's actual current production path. It does not describe greenfield bootstrap work or legacy Fly.io/Doppler infrastructure as if those were the active deployment model.
Preconditions
- [ ]
mainis green in GitHub Actions - [ ] You have access to the
QGTMAI/tradingrepository - [ ] GitHub secrets for Cloudflare and the DigitalOcean SSH key are current
- [ ] The DigitalOcean droplet at
142.93.1.195is reachable - [ ] Alpaca paper credentials are valid
- [ ] Any operator-impacting changes have updated their paired docs / Notion pages
Documentation Sync Gate
Before merging or deploying any operator-impacting change, confirm all three truth surfaces move together:
- repo docs updated where the behavior changed
- matching Notion source-of-truth pages updated
- docs deploy run completed if anything under
docs/**changed
Minimum repo doc set for trading/runtime changes:
README.mddocs/api-reference.mddocs/secrets-reference.md- this runbook or a more specific operator runbook when procedures changed
Production Surfaces
| Surface | Current deploy target |
|---|---|
| Terminal UI | Cloudflare Pages project qgtm-trading |
| API | DigitalOcean droplet 142.93.1.195 |
| Daemon | Same droplet, restarted via systemd during deploy |
| Redis | Same droplet, Docker/systemd |
| Docs | Cloudflare Pages project qgtm-docs |
Step 1: Trigger The Deploy Workflow
Production deploys are orchestrated by .github/workflows/deploy.yml.
- Push to
mainto trigger a change-scoped production deploy. - Use
workflow_dispatchif you need to deploy onlyweb, onlyapi, orall.
The workflow decides whether web and/or API surfaces changed before deploying.
Step 2: Web Deploy
For web changes, the workflow:
- checks out the repo
- installs Node and
pnpm - builds
qgtm_web - deploys
qgtm_web/outto Cloudflare Pages projectqgtm-trading
Operational expectation:
qgtmai.comshould reflect the new static export- this path does not deploy the docs site
Step 3: API + Daemon Deploy
For API-relevant changes, the workflow SSHes to the droplet and runs the
following flow inside /opt/trading:
- capture the previous git commit for rollback
git fetch origin maingit reset --hard origin/maingit clean -fd- update selected
.envvalues from GitHub secrets if new values are provided - activate
.venvand reinstall the package withpip install -e . - verify
from qgtm_api.main import appimports successfully - restart
qgtm-api - restart
qgtm-daemon - wait for
http://127.0.0.1:8000/health
If the import or health check fails, the workflow rolls the droplet back to the
previous git commit and restarts qgtm-api.
Step 4: Runtime Services
The active production services are managed by systemd wrappers around Docker Compose:
infra/systemd/qgtm-api.serviceinfra/systemd/qgtm-daemon.serviceinfra/systemd/qgtm-redis.service
These units reference the server-side compose file at:
The API and daemon are intentionally isolated into separate systemd units so an API restart does not imply the same failure domain as daemon execution.
Step 5: Post-Deploy Verification
Minimum verification after every production deploy:
curl -sS https://api.qgtmai.com/health
curl -sS https://api.qgtmai.com/api/v1/market-data/bars/GLD?limit=5
curl -sS https://api.qgtmai.com/api/v1/forecast/gold
curl -I https://qgtmai.com/
Check:
- terminal loads
- API health returns
status: ok - core bars endpoint works
- forecast endpoint works
- daemon restarted cleanly if API code changed
For operator-impacting API, daemon, or execution changes, also verify:
curl -H "X-QGTM-API-Key: $QGTM_API_KEY" \
https://api.qgtmai.com/api/v1/session/readiness
curl -H "X-QGTM-API-Key: $QGTM_API_KEY" \
"https://api.qgtmai.com/api/v1/orders/attribution?limit=50"
Check:
- readiness returns
ready=truewhen the stack is healthy checks.order_tag_coverage_okandchecks.legacy_tag_debt_presentreflect the expected attribution state- order attribution returns the expected realized-PnL and legacy/unknown unattributed split
Step 6: Docs Deploy
Docs deploy separately via .github/workflows/deploy-docs.yml.
That workflow:
- builds the MkDocs site into
site/ - deploys it to Cloudflare Pages project
qgtm-docs
Do not treat a successful terminal deploy as a docs deploy.
If docs/** changed, wait for the docs workflow and verify
https://qgtm-docs.pages.dev/.
Step 7: Rollback
Web
- Use Cloudflare Pages deployment rollback for project
qgtm-trading
API / daemon
- Re-run deploy after reverting the bad commit on
main, or - SSH to the droplet, reset
/opt/tradingto the known-good commit, then restart:
Emergency trading response
If the concern is trading safety rather than web/API correctness, use the kill-switch / flatten procedures from the operator runbooks before worrying about cosmetic rollback.
Legacy / Non-Canonical Paths
The repo still contains Fly.io, Neon, Upstash, Doppler, Terraform, and k8s references. Treat those as historical, experimental, or future-state assets unless they are reintroduced into the active GitHub Actions deploy path.