Deploy Checklist (definitive) โ
One flow, followed the same way by a human or an AI agent. The automated path is npm run deploy -- --env <dev|qa|prod> (see scripts/deploy-mta.cjs). This document is the human-followable mirror of that script โ the steps, guards, and their reasons are identical. If the two ever drift, the script wins; fix this doc.
Why this exists. On 2026-07-14 a local
.deploydeploy shipped a broken/explore/page ("Explore bundle missing"). Root cause:npm run build:allwas stale/skipped beforembt build, and โ unlike CI โ the local deploy path ran no post-deploy smoke test, so the regression shipped silently. The smoke test that catches it (test/smoke/explore-route.smoke.test.js) already existed; it just never ran locally. This checklist +npm run deployclose that gap for the whole class of "stale/incomplete build" bugs.
TL;DR โ the automated path โ
# From the PRIMARY checkout on main (never a worktree):
cf login -a https://api.cf.eu10-005.hana.ondemand.com # if not already
cf target -s dev # match the env
npm run deploy -- --env devnpm run deploy runs every step below in order and fails loudly if any guard trips. Flags:
| Flag | Effect |
|---|---|
--dry-run | Print the plan, run read-only guards (cf target, branch), touch nothing. |
--skip-build | Deploy an already-built mtar. Guards still run. Use only when you just built. |
--skip-smoke | Discouraged. Skips post-deploy verification โ this is exactly how /explore shipped broken. Prints the manual command to run instead. |
Exit codes: 0 success ยท 1 guard/build/deploy failure ยท 2 smoke gate failed (deploy landed but a check regressed โ treat env as broken).
The manual checklist (if not using npm run deploy) โ
Environment coordinates โ the single source of truth (mirrored in scripts/deploy-mta.cjs ENVS and in mta-deployment.md):
| Env | Region | Space | Approuter URL | Srv URL |
|---|---|---|---|---|
| dev | eu10-005 | dev | โฆ-dev-tutorials-approuter.cfapps.eu10-005.โฆ | โฆ-dev-tutorials-srv.cfapps.eu10-005.โฆ |
| qa | eu10-005 | dev | โฆ-qa-tutorials-approuter.cfapps.eu10-005.โฆ | โฆ-dev-tutorials-srv-qa.cfapps.eu10-005.โฆ |
| prod | eu10-005 | prod | โฆ-prod-tutorials-approuter.cfapps.eu10-005.โฆ | โฆ-prod-tutorials-srv.cfapps.eu10-005.โฆ |
โ Step 0 โ Preconditions โ
- [ ] You are in the primary checkout, not a
.claude/worktrees/tree. (mbt onlycpshugo/public/; a worktree base can bake stale/ahead content.) - [ ]
git branch --show-currentโmain. - [ ] Deploy scope confirmed with the maintainer (backend-only / +content / +QA).
โ Step 1 โ cf target guard โ
- [ ]
cf targetAPI endpoint host contains the env's region (eu10-005). (The 2026-07-14 trigger: cf was pointed atus10while the target iseu10-005.) - [ ]
cf targetspace equals the env's space. Fix:cf login -a https://api.cf.eu10-005.hana.ondemand.comthencf target -s <space>.
โ Step 2 โ Build โ
- [ ] Export the env's
CAP_BASE_URL(deployed srv, not localhost). - [ ]
npm run build:deploy(=check-deploy-cap-target && build:all). -build:allrunsbuild:explore(Vite + manifest emit) beforebuild:hugo, andbuild:hugorunscheck-explore-bundle-manifest.cjswhich hard-fails ifhugo/data/explore_bundle.jsonis absent. - A greenbuild:deploycannot reproduce the /explore incident. The incident happened only because this step was skipped.
export CAP_BASE_URL="https://tutorial-system-dev-tutorials-srv.cfapps.eu10-005.hana.ondemand.com"
npm run build:deployโ Step 3 โ Package (mbt build) โ
- [ ] Bump
version:in.deploy/mta.yamlif this deploy is a new release. This is the versioncf mtasreports and thetutorials-ims_<version>.mtarfilename. It is hand-maintained (not generated) โ semver, your call when to bump. - [ ]
cd .deploy && mbt build. - [ ] Verify a fresh mtar was produced โ check
mta_archives/*.mtarmtime advanced. (mbt can silently no-op with exit 0 if its Go binary was never unpacked. On Windows a SUCCESSFUL build can also end with a benign "could not remove Makefile" + EXIT=1 AFTER "the MTA archive generated at:". Trust the mtar mtime, not the exit code.) If stale:(cd node_modules/mbt && node install cloud-mta-build-tool)then retry.
โ Step 4 โ Deploy โ
- [ ]
cf deploy mta_archives/*.mtar -e ../deploy/<env>.mtaext -f(from.deploy/).
โ Step 5 โ Smoke gate (do NOT skip) โ
- [ ] Run the smoke suite against the just-deployed URLs:
SMOKE_BASE_URL="<approuter url>" SMOKE_SRV_URL="<srv url>" npm run test:smoke- [ ] All green. A failure here means the deploy landed but regressed โ treat the env as broken until triaged. This is the step that turns a silent-broken-prod into a loud failure.
Notes โ
- Content publish (tutorial HTML โ HANA BLOBs) is a separate flow โ see mta-deployment.md Step 3. This checklist covers the MTA (approuter + srv + db) deploy only.
- CI already does all of this.
.github/workflows/deploy.ymlbuilds explore โ Hugo โ mbt โ deploy โtest:smoke. This checklist brings the local.deploypath up to the same bar. Prefer CI when you can. - Why
.deploy/mta.yamldoesn't just render Hugo inline (which would make Step 2 unskippable): an inline Hugo render inside the MTA before-all hit the MTA build timeout (the approutercpof ~527MB already runs 6-9 min; hence the 30m timeout override). So the local path copies a pre-builthugo/public/and depends on Step 2 having run โ which is whatnpm run deployenforces.