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(usernmhuyen) - 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
.outputsize: 35.9 MB (10.1 MB gzip)
5. Sanity check
/tmp/p10d-output/exists ✅/tmp/p10d-output/server/index.mjsexists ✅- 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-nuxtissued- After 30s:
incomex-nuxt Up 30 seconds (healthy) - Internal listen:
0.0.0.0:3000 LISTEN 1/node - Network:
docker_incomexIP172.18.0.6
8. Verify (Step 10 + 11)
Note: runbook used
http://localhost:3000from VPS host, butincomex-nuxtdoes not publish port 3000 to host (verifieddocker portempty — traffic flows via reverse proxy on docker bridge). Used container IP172.18.0.6:3000for 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
- 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 HEAD5c9656e(parent5ce3437). Repo/opt/incomex/docker/nuxt-reponow 1 commit ahead of whatever upstream had; per project convention "edit host directly, never git pull" this is expected. - Verification endpoint:
incomex-nuxtdoes not publish port 3000 to host; runbook'shttp://localhost:3000always returns 000. Used container IP and public domain instead — both 200. - Step 11 token lookup: no
DIRECTUS_TOKENfound 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_TOKENenv (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).