Reference
Private operations
Prepare staging with readiness, migrations, smoke tests, and explicit rollback boundaries before connecting a real fleet.
Reviewed 2026-07-23
A successful build proves that the product compiles. It does not prove that Neon, secrets, the scheduler, and provider inventory are coordinated. This guide defines the boundary between “verified locally” and “ready to receive a fleet.”
Confidence levels
| Level | What it proves | What it does not prove |
|---|---|---|
| Local demo | UI, navigation, auth, and synthetic data. | Database, inventory, or real scheduler behavior. |
| Production build | Types, tests, lint, and rendering for every route. | Remote secrets or Neon connectivity. |
| Private staging | Real migrations, configuration, ingestion, and reconciliation. | Load, resilience, or billing accuracy at scale. |
| Production | Metrics and alerts under real traffic. | Accounting accuracy; costs remain estimates. |
Never present local verification as a production deployment.
Local preflight
Run every gate without contacting DigitalOcean:
bun run validate
cd cloud
bun run verify
The preview must contain only 127.0.0.1 published ports, prebuilt images, and
redacted secrets. bun run verify includes an offline Drizzle schema check
with a non-secret loopback placeholder URL; it does not connect to a database.
Repeat both gates after changing chalupa.yml or the inference engine.
Vercel project settings
Configure the Vercel project's Root Directory as cloud. The root package
is the Pulumi program and must never be selected as the web deployment.
Use the locked Bun workflow:
| Setting | Value |
|---|---|
| Root Directory | cloud |
| Install Command | bun install --frozen-lockfile |
| Build Command | bun run build |
| Output | Next.js default |
Scope secrets separately for Preview and Production. Run migrations as an explicit release step, not from the build command: builds may execute more than once and must remain free of database writes.
Staging configuration
Staging uses CHALUPA_DATA_MODE=database and requires:
DATABASE_URL;CLOUD_ADMIN_TOKEN;CHALUPA_INGEST_KEY;CRON_SECRET;DIGITALOCEAN_READ_TOKEN;NEXT_PUBLIC_CHALUPA_CLOUD_URL;DO_VOLUME_USD_PER_GIB_MONTH, reviewed against the current provider rate.
The staging origin must use HTTPS. The HTTP loopback value in .env.example
is accepted only for local development and is rejected by the staging check.
See Secrets with tvault for the injection workflow. Do not expose demo credentials in an internet-accessible deployment.
Migration and data
Review the committed SQL before running it:
cd cloud
bun run db:migrate
The first test must use a separate staging database. Verify tables, indexes, and constraints before sending heartbeats. Never edit the schema manually from a provider console.
Keep the previous deployment and a database restore point for rollback. A migration that deletes or reinterprets data needs a dedicated plan; reverting only application code may not be enough.
Health and readiness
Liveness answers whether the process can serve HTTP. Readiness answers whether required configuration is valid and critical dependencies respond. Neither response may include URLs, key names, SQL errors, or fleet data.
The exact probes are:
curl --fail --silent --show-error "$CLOUD_ORIGIN/api/health"
curl --fail --silent --show-error \
-H "Authorization: Bearer $CRON_SECRET" \
"$CLOUD_ORIGIN/api/ready"
Run the second command inside a tvault allowlisted subprocess and keep shell
tracing disabled. Liveness is public and returns only {"status":"ok"};
readiness is protected and returns only {"status":"ready"} or a redacted
503.
Use these signals for the platform smoke test, then verify the real journey:
- public landing page;
/appredirect to login;- administrator session;
- correctly labeled empty or synthetic fleet;
- HMAC ingestion with a fresh nonce;
- environment, run, and artifact visible to the administrator;
- logout and renewed route protection.
Scheduler and cost estimates
The DigitalOcean invoice is authoritative. Chalupa stores estimates by deployment and persistent storage:
- inventory reconciliation recovers still-observable resources that an agent did not report;
- launch-time rate capture preserves short-lived compute cycles;
- month-to-date totals retain already-sunk cycles;
- storage continues after compute reaches zero.
The production Vercel Pro configuration runs cost reconciliation every 15 minutes and retention once per day. Vercel Hobby cron supports at most one daily invocation; deployments on that plan must reduce the schedule or use an external authenticated scheduler.
Private smoke test
Before accepting a real fleet:
health → 200
readiness → ready
login → HttpOnly session
signed heartbeat → 2xx
replayed nonce → 409
fleet → updated environment
logout → /app redirects again
Use a synthetic or disposable environment. Creating or destroying a droplet requires explicit confirmation and is never part of a routine smoke test.
Rollback
Roll back when authentication, ingestion, or fleet reads stop working:
- stop the rollout and retain evidence without secrets;
- restore the previous deployment;
- revert the migration only if that path was designed and tested;
- verify health, login, and ingestion;
- disable cron temporarily if it writes incompatible data;
- document the affected estimate interval.
The agent uses a versioned contract. Keep the previous version compatible during rollout; do not replace the server and the entire fleet at the same instant.
Before any publication
The control plane remains private even when its landing page is public. Keep
/app and operational APIs out of search indexes, add platform-level
protection when available, and retain server-side auth.
The current tree excludes work material, but Git history may retain legacy names. Before making the repository public, create a clean history or perform a reviewed sanitization. Never publish local Pulumi state: it contains user-data and must be handled as a secret.