Deploy a fresh application
Execute the supported deployment path with readiness, smoke, rollback, and recovery evidence.
Deploy a fresh application
When to use
Use this path after a generated buyer application passes local verification and is ready for its first commercial deployment or a new isolated environment. It covers Railway, Dokploy, and the OpenTofu-managed AWS, GCP, and Azure backends with native, Vercel, or Cloudflare static frontends.
Read the deployment contract first. A host outside those targets is a new proof obligation, not a small variation of this runbook.
Files and boundaries
.node-version,.bun-version, rootpackage.json: pinned toolchain.apps/server/Dockerfile: standalone API artifact and runtime user.apps/server/railway.toml: Railway build, readiness, and restart policy.deploy/dokploy/compose.yml,deploy/dokploy/.env.example: reproducible self-hosted topology.scripts/verify-dokploy-compose.sh: disposable production-container proof.apps/server/.env.example,apps/server/src/config/env.ts: private runtime configuration.apps/web/vercel.json,apps/web/.env.example: public static build configuration.apps/web/wrangler.toml,apps/web/public/staticwebapp.config.json: static frontend adapters.infra/: OpenTofu bootstrap, provider modules, executable roots, locks, and mocked tests.deployment/config.json,deployment/README.md: locked non-secret selection and operator steps.scripts/deploy/: migration-gated cloud release and native frontend scripts.apps/server/src/main.ts: startup order.apps/server/src/app.ts: liveness and readiness endpoints.apps/server/migrations/: dbmate schema authority.apps/server/email-templates/: rendered runtime templates..github/workflows/ci.yml: fresh-install, migration, buyer, build, and compiled-server proof.
The selected backend owns server secrets, Postgres, proxy behavior, and the API artifact. The
selected frontend owns only the static browser build and its public VITE_* values. Provider
dashboards own credentials, callback URLs, products, webhooks, and sender/domain verification.
Procedure
-
Generate the buyer repository and install from its own frozen lockfile.
-
Honor
.node-versionand.bun-version; confirm the root pnpm version frompackageManager. -
Start disposable Postgres and run:
vp install --frozen-lockfile vp check pnpm test vp run -r build docker build --pull -f apps/server/Dockerfile -t app-server:release . bash scripts/verify-dokploy-compose.sh -
Prove migration reversibility on a disposable database with
up → down → up. Do not use an ambient or productionDATABASE_URL. -
Choose exactly one supported API target. Railway uses
apps/server/railway.toml; Dokploy usesdeploy/dokploy/compose.yml. For AWS, GCP, or Azure, runpnpm deploy:configureif deployment was deferred during application creation, review the generated checklist, bootstrap isolated state, select native S3/GCS or R2 storage, and dispatch the protected OIDC workflow. Azure uses R2 because Azure Blob storage is not included. -
Set
DATABASE_URL, a new 32+ characterBETTER_AUTH_SECRET,LOG_PRETTY=false, the exactTRUSTED_PROXY_PROFILE, exact HTTPSFRONTEND_URLandSERVER_URL, pool limits, deployment metadata, a verifiedEMAIL_FROM, andRESEND_API_KEYin the selected API platform. -
Leave
MIGRATIONS_DIRandEMAIL_TEMPLATES_DIRunset for the included image. Configure optional Google, the selected billing provider, and storage integrations atomically or leave each complete integration unset. -
Run
./server migrateas a one-shot release step using the exact image digest. Deploy the API only after it exits zero, then require/readyto return200. Confirm all9/9templates are preloaded and the structured release metadata matches the digest. -
Deploy the chosen static frontend with
VITE_APP_ENV=productionand exact HTTPSVITE_API_URL. For Vercel or Cloudflare, use the stable production origin supplied before the backend apply. -
Register the exact Google callback and selected-provider webhook routes when those integrations are enabled.
-
Deploy the web artifact and execute the new-browser production smoke checklist in
docs/deployment.md. -
Record artifact IDs, command results, URL, measured cost, interventions, architecture violations, and smoke evidence in the agent evaluation harness.
Verification
Before any external deploy:
vp check
pnpm test
vp run -r build
bun test --cwd packages/create-app src/deployment-contract.test.ts
docker build --pull -f apps/server/Dockerfile -t app-server:release .For the container proof, run the image as its non-root user against disposable Postgres and require:
GET /health -> 200 {"status":"ok",...}
GET /ready -> 200 {"status":"ready",...}Inspect the running container uid/gid, its Docker health state, the startup migration result, and
the 9/9 template preload. Then execute the auth and enabled-integration smoke checks; a green
health endpoint alone is not deployment proof.
Security constraints
- Generate new secrets per environment and enter them only in the owning provider.
- Treat every
VITE_*value as public. Never expose server keys, secrets, connection strings, or private URLs through the web build. - Use exact HTTPS origins and callback URLs. Do not use wildcard credentialed CORS.
- Select the exact supported proxy profile and keep the origin inaccessible around its ingress.
- Schedule and test an application-database backup. A Dokploy control-plane backup is separate.
- Use sandbox/test provider products for proof; do not create a real billable test purchase.
- Use a new browser profile and non-customer test identity for production smoke checks.
- Redact tokens, cookies, private connection details, and email links from evaluation and Linear evidence.
Failure modes
- Building the server with
apps/serveras Docker context, which omits the workspace lockfile. - Leaving
VITE_APP_ENVunset, causing production instrumentation and behavior to be classified as development. - Pointing
VITE_API_URL,FRONTEND_URL,SERVER_URL, CORS, OAuth, and webhook configuration at different origins. - Marking the service healthy from
/healthwhile Postgres, migrations, or templates are unusable. - Allocating replica pool limits that leave less than 20% of database connections for release and administrative work.
- Partially configuring the selected billing provider, Google, storage, or Resend.
- Rolling back application code after an incompatible or destructive schema change.
- Treating a local Docker proof as evidence that external email, auth cookies, callbacks, billing, storage, DNS, and TLS work.
Rollback and diagnosis
If the API does not become ready, preserve logs and identify whether environment validation,
database connectivity, migration execution, or resource preload failed. Keep the new artifact out of
service and redeploy the previous schema-compatible artifact. Use the failed-migration golden path
before any down, manual SQL, or version-table change.
If the web build fails, inspect the frozen install, exact Vite environment, and output directory. If the deployed SPA regresses, restore the previous static artifact together with the API version whose contract it expects.
Rotate credentials after any accidental bundle, log, transcript, or issue exposure. A corrected deploy does not make an exposed secret safe again.
Acceptance criteria
- A clean generated buyer repository passes frozen install, checks, tests, builds, migrations, and the exact Docker build.
- The API runs as non-root, preloads required resources before traffic, and reports database-backed readiness.
- Frontend and selected backend environment ownership is explicit and contains no misplaced secret.
- Password, verification, magic link, reset, session, email, CORS, and every enabled optional integration pass the deployed smoke checklist.
- Release and rollback order are compatible with the schema.
- Measured recurring cost and excluded overages are recorded.
- The evaluation record contains no credentials or customer data.
Agent prohibitions
- Do not create provider projects, domains, products, or permanent account names without the founder's approval.
- Do not claim a deployed integration from config, mocks, a local container, or a health response.
- Do not change the selected supported topology to avoid diagnosing its failure.
- Do not route Railway or Dokploy readiness to
/health. - Do not add replicas, a worker, a queue, or another cloud/provider during first-deploy proof.
- Do not put secrets in Git, Docker layers,
VITE_*, browser logs, evaluation evidence, or Linear. - Do not apply, reverse, or repair migrations against an unconfirmed database target.