Operations

Deployment

Merging to master is deploying. The API ships to Heroku with migrations in the release phase. Both apps ship to Vercel.


master is production

A push to GitHub master in api-v2 or totlob-pos reaches real users within minutes, and API migrations run as part of it. master isn't branch-protected.

API: Heroku

ItemValue
Appcypher-prod (git remote heroku). GitHub repo totlob/cypher.
DatabasePostgreSQL on Stackhero (not a Heroku add-on)
CacheRedis Cloud
TriggerAuto-deploy from GitHub master, configured outside the repo

Procfile:

release: npm run db:migrate     # runs before new dynos take traffic
web:     npm start
worker:  npm run consumer       # keep at 0 until a broker exists
  • Consumers: use either a scaled worker dyno or WEB_CONSUMES_QUEUE=true on web, never both.
  • Scheduler: npm run sync-rates daily at 06:00 UTC, once the FX branch ships. Run it once by hand after the first deploy.
  • Planned move: PR #86 feat/aws-deploy (EC2 + Docker + Caddy, RDS, SQS replacing RabbitMQ).

Apps: Vercel

AppBuildOutputNotes
Dashboardtsc -b && vite builddist/SPA rewrite. Target domain app.totlob.com. Expects a same-origin API or a reverse proxy.
POStsc -b && vite builddist/SPA rewrite. VITE_API_BASE_URL is baked in at build time.

Pushing safely

push.default = upstream

A branch cut from origin/master tracks master, so a plain git push pushes to master, whatever the branch is called. Always push with an explicit destination:

git push origin HEAD:refs/heads/<branch>

or unset branch.<name>.merge first.

Before pushing to a Heroku app directly, check which branch it's running. A wrong branch once removed endpoints from the live dashboard (HANDOVER.md).

Release order for a new endpoint

  1. Publish the contract (push the contracts repo's master), then wait about a minute.
  2. Pin it exactly in api-v2, implement it, and merge. The API deploys.
  3. Pin it in the dashboard or POS, use it, and merge. The app deploys.

Clients must never ship ahead of the API.

Post-deploy steps

Search backfill

With SEARCH_BACKEND=postgres, an empty search_document shows an empty catalogue with no error. After deploying search changes:

  1. Run scripts/backfill-search.ts locally against the production DATABASE_URL. tsx is pruned on Heroku, and heroku pg:psql doesn't work with Stackhero.
  2. Then run VACUUM ANALYZE search_document.

FX rates

Run heroku run npm run sync-rates once after the FX job first ships. Until a rate exists, shops trading in anything but USD can't load their catalogue.

Client seeds

Client data scripts (e.g. seed-cafe-modifiers.mjs) run against production via .env.prod. Run them dry first, then with --apply.

Previous
Testing & CI