Deploy & release
Default: you do not deploy manually. CI owns it.
Normal path (automatic)
.github/workflows/ci.yml runs on push to main: check → typecheck → test → playwright → build, and only if all pass, deploys:
- api →
wrangler deploy --config apps/api/wrangler.production.jsonc - web → built with
VITE_API_URL=https://api.skillist.io, then deployed - docs →
wrangler deploy
Then a smoke job runs pnpm smoke against production. So: land it on main via a merged PR and let CI deploy. Don't run production wrangler deploy by hand unless explicitly asked to hotfix.
Manual deploy (only if explicitly requested)
- Requires Cloudflare credentials/secrets already configured. Use the production config:
apps/api/wrangler.production.jsonc(custom domains, real resource IDs, larger containers). Never deploy the basewrangler.jsonc(that's local-dev bindings) to production. - Worker secrets are managed separately:
pnpm setup:secrets. Never inline secrets intovars. - Schema ships before the code that reads it.
deploy-apirunspnpm db:migrateagainst thePRODUCTION_DATABASE_URLsecret beforewrangler deploy. If you deploy the API by hand, apply pending migrations first — skipping that shipped a Worker querying a column production did not have, and 500'd the whole observability endpoint. - Locally,
.env'sDATABASE_URLis the dev branch. Production isDATABASE_URL_PROD, and it must be passed explicitly:DATABASE_URL="$(grep -m1 '^DATABASE_URL_PROD=' .env | cut -d= -f2-)" pnpm db:migrate
npm packages (@skillist/skill-format, @skillist/cli)
Published via the manual workflow_dispatch workflow .github/workflows/publish-packages.yml (builds skill-format then cli, skips versions already published, uses NPM_TOKEN). Locally: pnpm publish:packages. Bump the package version first; the workflow no-ops if the version already exists.
Before any deploy
Run /preflight (or pnpm check && pnpm typecheck && pnpm test). Deploys should only follow green gates.