Lumen Docs

Dokploy deploy

Lumen is deployed to VPS jaeger via Dokploy — a self-hosted PaaS that manages Docker Compose stacks and Traefik routing.

Prod setup snapshot

  • Dokploy instance: https://dokploy.zenlabsai.com (admin-only)
  • Project: "Lumen" (composeId -lHrFrWxG8415d10zZ3j0)
  • Repo: codename-zen/ai-knowledge-base (master branch watched)
  • GitHub App: dokploy-zenlabsai — fires redeploy on push
  • SSH host alias: jaeger89.21.85.125
  • DB container: lumen-postgres (Postgres 16 + pgvector)
  • Web URL: https://ai-kb.zenmail.my.id
  • API URL: https://lumen-api.zenmail.my.id
  • Docs URL: https://lumen-docs.zenmail.my.id

Auto-deploy flow

git push origin master
       ↓ webhook
Dokploy pulls latest + docker compose build
       ↓
docker compose up -d with new images
       ↓
Traefik reloads routes

Typical deploy takes 3–6 minutes. Web rebuild is the bottleneck (Next typecheck + build).

Manual redeploy

Sometimes webhook doesn't fire, or you changed env vars and need a fresh pull. Trigger redeploy via Dokploy tRPC API:

# 1. Log in to Dokploy (once — cookie cached)
ssh jaeger "curl -s -c /tmp/dk_cookie -X POST \
  http://localhost:3000/api/auth/sign-in/email \
  -H 'Content-Type: application/json' \
  -d '{\"email\":\"ganysigit1@gmail.com\",\"password\":\"<pw>\"}'"

# 2. Trigger compose redeploy
ssh jaeger "curl -s -b /tmp/dk_cookie -X POST \
  http://localhost:3000/api/trpc/compose.redeploy \
  -H 'Content-Type: application/json' \
  -d '{\"json\":{\"composeId\":\"-lHrFrWxG8415d10zZ3j0\"}}'"

Expected response: {"result":{"data":{"json":{"success":true,"message":"Redeployment queued"...}}}}.

Watching a deploy

# Live container status
watch -n 5 "ssh jaeger 'docker ps --filter name=lumen --format \"{{.Names}}\\t{{.Status}}\"'"

# Build logs (last one)
ssh jaeger "ls -t /etc/dokploy/logs/compose-input-wireless-firewall-mjami6/ | head -1"
ssh jaeger "tail -f /etc/dokploy/logs/compose-input-wireless-firewall-mjami6/<filename>"

When lumen-web status flips from Up X minutes to Up X seconds, the new build is live.

Services in the compose stack

| Service | Role | Port | |---|---|---| | lumen-web | Next.js frontend | 3000 (internal) | | lumen-api | Hono API + chat stream | 4000 (internal) | | lumen-docs | Docs site (this one) | 3000 (internal) | | lumen-postgres | DB + pgvector | 5432 | | lumen-redis | BullMQ queue | 6379 | | lumen-embedder | Embedding + reranker | 8000 | | lumen-worker | Document processing queue consumer | — |

Traefik routes (auto-configured by Dokploy from labels):

ai-kb.zenmail.my.id      → lumen-web:3000
lumen-api.zenmail.my.id  → lumen-api:4000
lumen-docs.zenmail.my.id → lumen-docs:3000

Common gotchas

  • Migration failures on deploystart.sh in the API container runs prisma db push on boot. Schema changes that rename enum values or drop columns with data will fail. Apply manual migrations before merging to master (see Runbooks).
  • Enum + same-TX usage — Postgres rejects adding a new enum value and using it in the same transaction. Always split into two migrations: part1_enums.sql (add values) → part2_schema.sql (use them).
  • Embedder cold start — First deploy downloads model weights (~200MB). Container shows unhealthy for 2–3 minutes until first healthcheck passes. Patience.
  • Docker volume upload_data — Survives docker compose down but NOT docker volume rm. Doc files live here.

Rollback

# Find the bad commit
git log --oneline -10

# Revert it (keeps history, creates new commit)
git revert <sha> --no-edit

# Push → Dokploy auto-deploys the revert
git push origin master

If the DB schema is the problem, restore from the pre-change backup:

ssh jaeger "docker exec -i lumen-postgres \
  psql -U lumen -d lumen < /tmp/lumen-backup-<timestamp>.sql"

See Backup & restore.