Docs / deployment/codex-deploy-prompt.md

PROMPT FOR CODEX — paste everything below this line

You are deploying Chimti's new merged web app + API updates on the Otlu server

(Coolify). This prompt is complete and self-contained — follow it top to

bottom, in order. This is an INFRA task: do not improvise product/code changes.

If a precondition fails, STOP and report back instead of patching code.

Context (30 seconds)

(`chimti-user-app`, `chimti-admin-app`). Same repo builds two variants via

Docker build arg `VITE_APP_VARIANT=user|admin`. It is feature-complete:

registers + deep detail chains (clients→brand→locations→pricing, orders→items,

role editor, plans depth, AI consoles, help center), mobile card-list layout,

Capacitor dirs (ignore android/ ios/ for this deploy).

**https://admin.chimti.ai** (admin app).

URL at build time. Do NOT move the API in this task.

1) read-only billing routes (`/v1/invoices`, `/v1/plans`, `/v1/subscriptions`)

2) a background worker layer (`src/worker.js` + `src/workers/`, 21 jobs,

separate process off the same image; `npm run test:workers` → 25 green).

deployed untouched as instant rollback. Do not delete them.

Step 0 — Preconditions (verify before touching Coolify)

Jagjeet has pushed the deploy branches. Confirm on a fresh checkout; if

anything is missing, STOP and tell him exactly what.

`chimti-api`:

`chimti-web-app`:

`src/lib/brandCatalog.js`, `src/lib/accessControl.js`,

`src/pages/PermissionDetailsPage.jsx`, `src/pages/UserDetailsPage.jsx`,

`src/pages/HelpCenterPage.jsx`, `src/pages/AiOpsModulesPage.jsx`,

`src/pages/ProfilePage.jsx`, `src/pages/ShipmentsPage.jsx`

"47 routes (user variant)" and "34 routes (admin variant)"

Step 1 — Deploy chimti-api update

1. Coolify → existing `chimti-api` app → Redeploy (same Dockerfile, no config

change for this step).

2. Verify:


curl -s https://chimti-api.otlu.io/v1/health          # JSON with "service":"chimti-api"

TOKEN="<accessToken from POST /v1/auth/login with a real internal account>"

curl -s -H "Authorization: Bearer $TOKEN" https://chimti-api.otlu.io/v1/plans | head -c 300

curl -s -H "Authorization: Bearer $TOKEN" https://chimti-api.otlu.io/v1/invoices | head -c 300

# expect {"items":[...]} from both (empty array is fine)

Step 2 — CORS for the new domains

In chimti-api's Coolify env, APPEND to `CORS_ORIGIN` (comma-separated, KEEP

every existing origin):


https://app.chimti.ai,https://admin.chimti.ai

Restart chimti-api, then verify preflight:


curl -s -o /dev/null -w '%{http_code}\n' -X OPTIONS https://chimti-api.otlu.io/v1/health \

  -H 'Origin: https://app.chimti.ai' -H 'Access-Control-Request-Method: GET'

# expect 200/204, not 4xx

Step 3 — Worker process (new Coolify service)

1. New Coolify app `chimti-worker` from the SAME `chimti-api` repo (same

Dockerfile). No domain, no public port.

2. Start command override: `npm run worker` (image default CMD starts the API;

the worker MUST run `node src/worker.js`).

3. Env = copy ALL of chimti-api's env (needs `DATABASE_URL` etc.), PLUS:


WORKERS_ENABLED=1

WORKER_ALERT_EMAIL=me@jagjeetsinghsethi.com

WORKER_DIGEST_HOUR=8

WORKER_SNAPSHOT_HOUR=2

WORKER_DEMO_RESET_HOUR=4

(Optional kill switches `WORKER_<KEY>=0`, cadence overrides

`WORKER_<KEY>_INTERVAL_SECONDS` — keys listed in

`chimti-docs/architecture/workers-automation-plan.md`.)

4. Deploy; logs must show `chimti worker starting` and 21 × `job scheduled`.

First boot creates `worker_heartbeats` / `worker_snapshots` tables itself —

no migration step.

5. DB check:


SELECT name, last_run_at, last_ok_at, last_error FROM worker_heartbeats ORDER BY name;

-- within ~2 minutes most short-interval jobs should have last_ok_at set

Step 4 — DNS for chimti.ai

At the chimti.ai DNS provider add two records pointing at the Otlu server

(same IP as the *.otlu.io apps), TTL 300 during cutover:


app.chimti.ai    A  <server-ip>   (or CNAME to the Coolify proxy hostname)

admin.chimti.ai  A  <server-ip>

Coolify/Traefik issues Let's Encrypt certs automatically once the apps exist.

Step 5 — Two web apps from chimti-web-app

Create TWO Coolify apps from `chimti-web-app`, Build Pack = Dockerfile (repo

root). nginx-static image; no runtime env needed.

`VITE_APP_VARIANT=user`

`VITE_APP_VARIANT=admin`

(`VITE_BACKEND_API_BASE_URL` defaults to `https://chimti-api.otlu.io` inside

the Dockerfile — do not set it.)

Deploy both; builds must end with vite `✓ built` and an nginx image.

Step 6 — Smoke checklist (tick every box)

User app — https://app.chimti.ai:

accepts a live article tag (OK) and rejects a fake one (Unknown)

Admin app — https://admin.chimti.ai:

Services catalog editor saves

re-open (persisted) → toggle back → Save

After 24h (bonus):

Step 7 — Old domains policy

Leave `chimti-user-app.otlu.io` / `chimti-admin-app.otlu.io` running untouched

(rollback). Only after Jagjeet confirms the new domains (a few days), add 301

redirects old → new and archive the old app repos.

Rollback

records.

additive — no schema rollback (worker tables are standalone).

Explicitly OUT of scope

web builds with new base URL).

leads write APIs, access-control approval-requests API. Do not stub them.

Reference docs in the repos

supersedes it where they differ)

(Drops A–D addenda = what's in this build)

Report back with: each step's status, the full smoke checklist ticked, the

worker_heartbeats query output, and anything you had to deviate on.