KB-2FEC

P10D-2E One-Time VPS Activation Report (2026-04-30)

6 min read Revision 1
p10dvps-activationtac-publicationreport

P10D-2E — One-Time VPS Manual Activation Report

  • Date: 2026-04-30
  • Agent: Claude (control: Nguyens-MacBook-Air.local), executing via SSH contabo
  • Verdict: ACTIVATION_PASS

1. Gate 0

  • Control host: Nguyens-MacBook-Air.local (user nmhuyen)
  • VPS: vmi3080463.contaboserver.net
  • PG identity: directus/directus

2. Hard gate (Step 2)

  • Repo: /opt/incomex/docker/nuxt-repo
  • HEAD before fix: 5ce3437 P10D: add parallel TAC official laws screen
  • Status: 0 dirty files ✅
  • Bind mount: /opt/incomex/deploys/nuxt-output → /app/.output

3. Dockerfile output path

  • File: /opt/incomex/docker/nuxt-repo/web/Dockerfile
  • L42 WORKDIR /app
  • L49 COPY --from=builder --chown=nuxtjs:nodejs /app/.output /app/.output
  • L61 CMD ["node", ".output/server/index.mjs"]
  • Image output path = /app/.output (no placeholder)

4. Build

Attempt 1 — FAIL

pages/knowledge/laws/[pubId].vue:192:54
RollupError: [vite:vue] Error parsing JavaScript expression: Unexpected token (1:22)

Line 192 had:

<DocsTreeView :nodes="docsTree" :selected-path="selectedDoc?.path || " @select="selectNode" />

The || had no RHS — the binding closed with empty string.

Fix (authorized by user, scope-extension to runbook)

Changed to selectedDoc?.path || ''. Committed on VPS:

  • New HEAD: 5c9656e fix(p10d): empty-string fallback for selected-path binding
  • Parent: 5ce3437
  • 1 file changed, 1 insertion(+), 1 deletion(-)

Attempt 2 — PASS

  • Image: nuxt-ssr-local:p10d
  • Build time: 214.5s
  • Nitro preset: node-server
  • Total .output size: 35.9 MB (10.1 MB gzip)

5. Sanity check

  • /tmp/p10d-output/ exists ✅
  • /tmp/p10d-output/server/index.mjs exists ✅
  • Size: 43M
  • HEAD at sanity time: 5c9656e
  • Route artifact (find */knowledge/laws*): empty (inconclusive — Nuxt SSR routes typically have no static artifact). Not a fail per runbook; runtime tests below confirm route works.

6. Backup

  • Path: /opt/incomex/deploys/nuxt-output.bak.p10d-20260430124407
  • Path written to: /tmp/p10d-nuxt-output-backup-path.txt

7. Container health after restart

  • docker restart incomex-nuxt issued
  • After 30s: incomex-nuxt Up 30 seconds (healthy)
  • Internal listen: 0.0.0.0:3000 LISTEN 1/node
  • Network: docker_incomex IP 172.18.0.6

8. Verify (Step 10 + 11)

Note: runbook used http://localhost:3000 from VPS host, but incomex-nuxt does not publish port 3000 to host (verified docker port empty — traffic flows via reverse proxy on docker bridge). Used container IP 172.18.0.6:3000 for direct checks; also verified via public domain.

HTTP

Endpoint Result
http://172.18.0.6:3000/knowledge/laws 200
http://172.18.0.6:3000/knowledge/laws/27e48995-d6a1-4a44-8559-cab6a07fdbe0 (D35) 200
http://172.18.0.6:3000/knowledge (KB hub) 200
https://vps.incomexsaigoncorp.vn/knowledge/laws (public) 200
https://vps.incomexsaigoncorp.vn/knowledge (public) 200

Content (200 thật vs catch-all)

Page Pattern matches
/knowledge/laws 2 (DIEU/publication/official/chính thức/tac_publication)
D35 reader 3 (MỤC TIÊU/DOT/SCHEMA/tree)

Directus tac_publication (via PG, no API token in env)

DIEU-35 v5.2
DIEU-32 v1.1
DIEU-28 v2.0

3 publications

KB doc route

  • Slug sample (PG): knowledge-dev-blueprints-architecture-decisions
  • HTTP: 200

9. Verdict — ACTIVATION_PASS

# Check Expected Actual
Step 9 Container healthy Up (healthy) Up 30s (healthy) ✅
Step 10 /knowledge/laws 200 200 ✅
Step 10 D35 reader 200 200 ✅
Step 10 Content grep TAC ≥1 2 / 3 ✅
Step 10 D28/D32/D35 3 pubs 3 ✅
Step 11 /knowledge hub 200 200 ✅
Step 11 KB doc route 200 200 ✅

TV mới (TAC laws screen) đã sáng. TV cũ (KB) vẫn chạy.

10. Rollback (if needed later)

ssh contabo 'BACKUP=$(cat /tmp/p10d-nuxt-output-backup-path.txt); \
  rsync -a --delete "$BACKUP"/ /opt/incomex/deploys/nuxt-output/ && \
  docker restart incomex-nuxt && \
  echo "ROLLED BACK to $BACKUP"'

Backup path: /opt/incomex/deploys/nuxt-output.bak.p10d-20260430124407

11. Cleanup (after stable verification window)

After production stability is confirmed, the following can be removed:

  • /tmp/p10d-output — extracted build artifact
  • /tmp/p10d-nuxt-output-backup-path.txt — backup pointer
  • Image nuxt-ssr-local:p10d — local image (docker rmi nuxt-ssr-local:p10d)
  • /opt/incomex/deploys/nuxt-output.bak.p10d-20260430124407 — output backup

12. Deviations from runbook

  1. HEAD diverged: source had a vite-parser-breaking syntax error in pages/knowledge/laws/[pubId].vue:192. User explicitly authorized a 1-line fix on VPS. New HEAD 5c9656e (parent 5ce3437). Repo /opt/incomex/docker/nuxt-repo now 1 commit ahead of whatever upstream had; per project convention "edit host directly, never git pull" this is expected.
  2. Verification endpoint: incomex-nuxt does not publish port 3000 to host; runbook's http://localhost:3000 always returns 000. Used container IP and public domain instead — both 200.
  3. Step 11 token lookup: no DIRECTUS_TOKEN found in /opt/incomex/.env, /opt/incomex/docker/.env, or /opt/incomex/docker/nuxt-repo/.env. Used PG direct query for slug; result still 200.

13. Follow-up (out of scope)

Open separate task: "Deploy Governance Cleanup / Đ41 patch" to dispense with the manual VPS-build path. Recommendations:

  • Address the missing DIRECTUS_TOKEN env (or document the actual location) so Step 11 of future runbooks works without PG fallback.
  • Document the host-port vs docker-network access pattern in deploy runbooks.
  • Decide upstream fate of commit 5c9656e (cherry-pick into the canonical branch when CI path is restored).