Environments and deploy
Three environments — dev, staging, production — each fed by a git branch. A push deploys itself.
How this page was verified
Read on 2026-09-15 from each deployable repo's .github/workflows/deploy.yml and deploy/ scripts, and the server facts from the exsport-repos skill.
Branch → environment
| Env | Branch | Storefront | Admin | Backend API |
|---|---|---|---|---|
| dev | development | dev.exsport.bdt.dev | dev-admin.exsport.bdt.dev | via the app hosts |
| staging | staging | stg.exsportbags.com | admin-stg.exsportbags.com | api-stg.exsportbags.com |
| prod | main | www.exsportbags.com | admin.exsportbags.com | www.exsportbags.com/gapi/graphql |
The webhook repo is single-branch, so it has only production. The production backend path is /gapi (not /be-api); api.exsportbags.com does not resolve. Prod storefront pages are client-rendered, so fetching the HTML shows no prices — query /gapi/graphql (public queries need no auth) or drive a browser to audit live data.
Auto-deploy on push
Every deployable repo (backend, storefront, admin, webhook) has the same deploy.yml:
- Trigger: push to
development,stagingormain(webhook:mainonly). - Runner: the self-hosted
[self-hosted, rumah]runner — neverubuntu-latest. - Concurrency: group
deploy-<ref>,cancel-in-progress: false— deploys queue, they do not kill each other. - GitHub environment per ref (
main→production, else the branch name), which lights up the Jira Deployments tab for the DEF07 ticket. - Script per branch:
development→deploy/dev.sh,staging→deploy/staging.sh,main→deploy/prod.sh. Webhook always runsdeploy/prod.sh. - Slack notice at the end (
if: always()) viadeploy/lib/slack-notify.pyusing repo secretSLACK_WEBHOOK_URL; it no-ops if the secret is unset and never fails the job.
The old d.bdt.dev webhook deployer is disabled for all four repos. Watch a run in the repo's Actions tab, and still confirm the served bundle or API when it matters — a deploy can fail.
Where each environment runs
Observed 2026-08-27; SSH aliases are in ~/.ssh/config.
| Env | Host | Notes |
|---|---|---|
| dev | one box, rumah.bdt.dev (ubuntu@) | apps under /home/ubuntu/apps/, DB is local Postgres exsport_dev |
| staging | one box, alias ex-stg-cd | all four apps under /home/ex-stg/apps/ on PM2 (storefront :3011, admin :3012, backend :3013, webhook :3014), DB exsport_stg. Staging ports differ from the local-Mac ports. |
| prod | split hosts behind bastion exsport-prod-bastion | exsport-prod-be (backend at /opt/backend, a built artifact with no git checkout), -fe, -webhook, -db, -proxy. Live production — read-only unless Eris says otherwise. |
The Pulumi AWS setup
def-exsport-pulumi also defines a full AWS setup (ECS, ALB, RDS, ElastiCache, ECR, S3, SNS) across seven stacks. That is not the same as the serving hosts above — read def-exsport-pulumi/stacks/ before assuming it is the live path. See the Pulumi repo page.
A note on next start
On admin and storefront, typescript is a runtime dependency because next start loads next.config.ts at boot. Keep it in dependencies or prod crashes on start.