Documentation Integrity Report
| Field | Value |
|---|---|
| Protocol | /docs-verify |
| Date (local) | 2026-07-11 |
| Mode | CORPUS |
| Scope paths | docs/**/*.md (excluding node_modules, .vitepress build) |
| Repos consulted | vtrc-api, cu-central-api, centralize-api, vtrc-web, vtrc-rc-backoffice |
| Files in scope | 202 |
| Files fully claim-extracted | Trap-driven + high-risk volumes (see §7); not every pedagogical sentence in all 202 files |
| Overall verdict | FAIL |
| Evidence standard | Static code + config in workspace (no e2e / no production runtime) |
| Prior audits as leads only | Yes — docs/DOC-CODE-DISCREPANCY-AUDIT.md, docs/volume-17-appendices/08-changelog-errata.md |
1. Executive Verdict
English: The corpus FAILS national-grade integrity. Multiple P0 claims still instruct readers to use NestJS centralize-api as the live HR/auth path, store OTP in vtrc Redis, treat KBANK as Bangkok Bank, and follow an invented statusKcash map. Primary code shows END_POINT_CENTRALIZE → cu-central-api GraphQL/LDAP, OTP in MariaDB (Models.Otp), Kasikorn wording, and statusKcash ids 6–10 with SUCCESS = '9'.
ไทย: คู่มือทั้งชุด ไม่ผ่าน เกณฑ์ — ยังมีข้อผิด P0 ที่ชี้อ่านไป NestJS เป็นสะพาน HR/auth, OTP ใน Redis ของ vtrc, KBANK = กรุงเทพ, และตาราง statusKcash ที่ไม่ตรงโค้ด ทั้งที่หลักฐานยืนยันว่า live path คือ cu-central-api, OTP อยู่ใน MariaDB, ธนาคารคือกสิกรไทย, และ SUCCESS = รหัส '9'
2. Canonical Truths (verified this run)
| Fact | Value | Evidence |
|---|---|---|
| Live HR/GraphQL bridge from vtrc-api | GraphQLClient(END_POINT_CENTRALIZE) | vtrc-api/api/src/centralize/controllers/graphql.js:3,21,84 |
| Auth forward from vtrc-api | ${END_POINT_CENTRALIZE_AUTH}/signin (and related) | vtrc-api/api/src/centralize/controllers/auth.js:28,52,75,98 |
| Client target in vtrc-api example | http://localhost:8082/api/graphql and /auth | vtrc-api/api/.env.example:36-37 · class CLIENT_TARGET / ENV_EXAMPLE |
| cu-central listen default | APP_PORT = 8080 | cu-central-api/main-api/src/config.js:20; .env.example:4 · class CODE_DEFAULT |
| cu-central Dockerfile metadata | EXPOSE 9000 | cu-central-api/main-api/Dockerfile:18 · class DOCKER_EXPOSE only |
| cu-central compose host ports | 8000:8000, 8002:8000, 8003:8000 | cu-central-api/docker-compose.yml:53,72,89 · class COMPOSE_HOST |
| NestJS hrPaySlip method | @Post() under @Controller('hrPaySlip') | centralize-api/src/modules/hrPaySlip/hrpayslip.controller.ts:13,18 |
| NestJS employee GET count | 14 | employee.controller.ts @Get( count = 14 |
| NestJS HTTP route total | 17 (App 1 + Employee 14 + PaySlip 1 + TimeTemp 1) | Controllers under centralize-api/src |
| NBC MSSQL name in NestJS SQL | dbHRMI_Center_NBC (not dbHRMI_NBC) | Grep unique dbHRMI_* under centralize-api/src |
| vtrc-api Sequelize exports | db, db2 only | vtrc-api/api/src/connector.js:8,29,50 |
| KBANK institutional label in config copy | กสิกรไทย | vtrc-api/api/src/config.js:389 |
statusKcash SUCCESS | id '9', status: 'SUCCESS', label PAID / โอนสำเร็จ | vtrc-api/api/src/config.js:508-511 |
statusKcash FAILED ids | '6','7','8','10' (no id '0') | config.js:488-518 |
| Active vtrc-api crons | Fund rate if APP_NO===1; updateDelegatesExpire + statLog ungated | vtrc-api/api/src/crons.js:14-27 |
| OTP persistence | Models.Otp.create in cu-central; expire minutes default 3 | sendOtp.model.js:12-14; sendOtp.js:113; config.js:74 |
| vtrc-api Redis cache on common paths | Call sites largely commented | e.g. routes.js:411-442; resolvers/post.js:39-41 |
| OTP request from vtrc-api | Proxied via requestOtpCD → GraphQL mutation | verification.js repository + centralize/controllers/verification.js:42-47 |
| Device key field | value.key === apiKey | vtrc-api/api/src/index.js:34; config.js:45 (key:) |
| Session Redis key pattern (cu-central) | sess:{userUid}_{sessionId} | cu-central-api/main-api/src/lib/session/session.js:18-19 |
| syncModels active entries | 79 | Measured from vtrc-api/api/src/lib/model.js |
Gate #4 session errors | CANNOT_ACCESS / TOKEN_INVALID | session.js:24,39,44 |
| Backoffice Apollo transport | createUploadLink; apiKeyNews(); refresh via Queries.refreshTokenBO | vtrc-rc-backoffice/src/config/apollo.js:39,48-65,71-76 |
Backoffice isLoggedIn | Boolean (token ∧ refreshToken) | utils/auth.js |
| Backoffice Dockerfile runtime | Stage-2 nginx:1.24.0 | vtrc-rc-backoffice/Dockerfile:13 |
Web checkLinkURL origins | vtrc / uat-vtrc / localhost → endpoints as coded | vtrc-web/src/config/apollo.js (verified this run) |
Compose network_mode: host | On nginx service only (vtrc-api compose) | vtrc-api/docker-compose.yml:34 |
| NestJS caller from vtrc-api | Not found in workspace HTTP clients | Grep of bridge uses GraphQL/auth URLs only; E-08 stands |
3. Findings
| ID | Doc | Class | Claim (short) | Verdict | Sev | Code evidence | Correction |
|---|---|---|---|---|---|---|---|
| F-001 | volume-00/.../02-system-map.md | C1/C2 | Payslip steps 3–4 → NestJS REST + TypeORM | WRONG | P0 | slip.js → GraphqlCDWithToken; graphql.js:21 | Route to cu-central GraphQL |
| F-002 | volume-00/.../02-system-map.md | C2 | cu-central Port 9000 | WRONG | P0 | APP_PORT=8080; EXPOSE 9000 metadata only | Use port classification rubric |
| F-003 | volume-00/.../02-system-map.md | C2 | GET /api/hrPaySlip | WRONG | P0 | @Post() hrPaySlip | Document POST |
| F-004 | volume-00/.../02-system-map.md | C4 | DB name dbHRMI_NBC | WRONG | P0 | dbHRMI_Center_NBC in NestJS SQL | Rename |
| F-005 | volume-00/.../02-system-map.md | C6 | Redis cache payslip:{emp}:{date} on path | WRONG | P0 | No active write on slip path; cache helpers commented | Remove or mark vestigial |
| F-006 | volume-00/.../02-system-map.md | C8/C2 | URL table attributed solely to vtrc-web apollo includes backoffice origins | PARTIAL | P1 | Web apollo.js lacks backoffice hosts; BO has own file | Split tables per frontend |
| F-007 | volume-00/.../02-system-map.md | C1 | Absolute “never write MSSQL” | PARTIAL | P1 | Same doc admits cu-central two-way sync | Soften absolute rule |
| F-008 | volume-00/.../03-employee-day.md | C1 | Slip miss → NestJS | WRONG | P0 | Same as F-001 | Align with cu-central |
| F-009 | volume-00/.../04-admin-day.md | C10 | KBANK = ธนาคารกรุงเทพ | WRONG | P0 | config.js:389 กสิกรไทย | Replace bank name |
| F-010 | volume-00/.../04-admin-day.md | C6 | Check K-Cash cron | WRONG | P0 | crons.js has no K-Cash job | Manual import only |
| F-011 | volume-00/.../04-admin-day.md | C2 | POST /api/downloadExcel | WRONG | P1 | routes.js GET /download/excel/:table | Fix method/path |
| F-012 | volume-00/.../05-key-features.md | C1/C6 | Time attendance → NestJS + Redis; cron pulls K-Cash/กรุงเทพ | WRONG | P0 | timeAttendance.js GraphQL; no K-Cash cron | Rewrite |
| F-013 | volume-00/.../05-key-features.md | C8 | Paths like vtrc-api/typeDefs/... | WRONG | P1 | Real root vtrc-api/api/src/ | Fix prefixes |
| F-014 | volume-00/.../06-quick-glossary.md | C10/C4 | KBANK Bangkok; dbHr in vtrc connector.js; dbHRMI_NBC | WRONG | P0 | connector exports db/db2; bank text; NBC name | Fix glossary rows |
| F-015 | volume-01/.../04-payroll-slip.md | C1 | NestJS + Redis on slip | WRONG | P0 | GraphQL bridge | Fix flow |
| F-016 | volume-01/.../10-time-attendance.md | C1 | Diagram NestJS (conflicts later prose) | WRONG + CONFLICT | P0 | GraphQL; doc self-conflict | Unify on cu-central |
| F-017 | volume-01/.../11-payments-kbank.md | C10 | ธนาคารกรุงเทพ (KBANK) | WRONG | P0 | กสิกรไทย | Rename |
| F-018 | volume-01/.../07-welfare-hospital.md | C10 | กรุงเทพ / K-Cash | WRONG | P0 | Same | Rename |
| F-019 | volume-04/.../index.md | C1 | Topology edge vtrc-api → NestJS | WRONG | P0 | No NestJS client | Remove or mark unconfirmed |
| F-020 | volume-04/.../09-scorecard-comparison.md | C1 | Auth forward → centralize-api | WRONG | P0 | END_POINT_CENTRALIZE_AUTH | Say cu-central |
| F-021 | volume-03/.../index.md | C2 | “port 8082 … ตรงกับ cu-central-api” as absolute | PARTIAL | P0 | CODE_DEFAULT 8080; CLIENT_TARGET 8082 | Qualify by class |
| F-022 | volume-05/.../index.md + 01 + 03 + 09 | C7 | 12 / 14 / 16 endpoints (inconsistent) | WRONG | P1 | Measured 17 total; employee 14 GET | Harmonize to 14/17 |
| F-023 | volume-07/.../03-apollo-checklinkurl.md | C5/C8 | createHttpLink, getApikey, JWT-from-isLoggedIn | WRONG | P0 | createUploadLink, apiKeyNews, boolean isLoggedIn | Rewrite from apollo.js |
| F-024 | volume-07/.../02-bootstrap-build.md | C7 | Docker serve / alpine narrative | WRONG | P0 | nginx:1.24.0 stage-2 | Rewrite Dockerfile section |
| F-025 | volume-07/.../04-routing-auth-gate.md | C5 | PrivateRoute / getApikey menu | WRONG | P0 | No PrivateRoute; workforce axios | Align with App/Sider |
| F-026 | volume-08/.../01-persistence-topology.md + 09 + 11 | C4 | dbHRMI_NBC; NestJS as primary live reader framing | WRONG / PARTIAL | P0 | dbHRMI_Center_NBC; live reader via cu-central for vtrc-api | Fix names + ownership |
| F-027 | volume-09/.../02-authentication-flow.md | C1/C5 | Login → NestJS; MSSQL password check | WRONG | P0 | Auth REST to cu-central; LDAP at cu-central | Full rewrite of live path |
| F-028 | volume-09/.../05-credential-secrets.md + 10-supply-chain-runtime.md | C1 | Remaining gate = NestJS password | WRONG | P0 | cu-central auth | Fix naming |
| F-029 | volume-10/.../02-auth-headers.md | C5/C8 | Filter key.apiKey; Redis sess:<sid> | WRONG | P1 | value.key; sess:{uid}_{sid} | Fix snippets |
| F-030 | volume-10/.../01-api-topology.md | C2 | Implies cu-central default 8082 in places | PARTIAL | P1 | CODE_DEFAULT 8080 | Qualify |
| F-031 | volume-11/.../03-welfare-hospital.md | C6 | statusKcash id '0' SUCCESS; labels บัญชีปิด… | WRONG | P0 | Literal config.js:488-518 | Replace table with code dump |
| F-032 | volume-12/.../11-cron-scorecard.md + related | C6 | Every job gated APP_NO===1 | WRONG | P0 | Only fund-rate gated | Correct SPOF narrative |
| F-033 | volume-12/.../04-docker-compose.md | C2 | Stack-wide network_mode: host | WRONG | P1 | Only nginx | Fix table |
| F-034 | volume-12/.../01-hosting-topology.md | C1 | NestJS on same prod traffic path without caveat | PARTIAL | P0 | Caller unconfirmed (E-08) | Add unconfirmed label |
| F-035 | volume-12/.../07-database-redis.md | C5/C6 | vtrc Redis OTP TTL 5m / cron locks | WRONG | P0 | OTP in Models.Otp; crons no Redis | Rewrite vtrc Redis section |
| F-036 | volume-13/.../06-redis-operations.md | C6 | otp:* on vtrc-redis TTL 300s | WRONG | P0 | DB OTP; TTL 3 min | Replace runbook |
| F-037 | volume-13/.../08-debug-playbooks.md | C6 | Debug OTP via Redis KEYS | WRONG | P0 | Same | Point to cu-central DB |
| F-038 | volume-13/.../07-user-session-management.md | C6 | OTP stored in Redis | WRONG | P0 | Same | Fix step |
| F-039 | volume-14/.../02-high-security.md vs volume-16/.../04-debt-id-index.md | C9 | SEC-6/7/8 ID meanings | CONFLICT | P0 | Vol14: SEC-6 trustCert, SEC-7 axois, SEC-8 PII; A.4 swapped | Make A.4 match Vol 14 |
| F-040 | volume-16/.../06-environment-variables.md | C3 | DB_USER for vtrc-api; cu PORT=8082 patterns | WRONG | P1 | vtrc .env.example uses DB_USERNAME; cu APP_PORT=8080 | Regenerate from examples |
| F-041 | volume-16/.../05-volume-cross-ref.md | C2 | “cu-central … port 8082” unqualified | PARTIAL | P1 | Same as F-021 | Qualify |
| F-042 | volume-15/.../08-infrastructure-evolution.md | C1 | Current-state → NestJS centralize | WRONG | P0 | Live bridge cu-central | Fix current-state only |
| F-043 | docs/audit/* | C1/C2 | NestJS live path; cu-central port 9000 | WRONG | P1 | Same evidence | Mark audit superseded or fix |
| F-044 | Vol 3 persistence / map | C4/C7 | syncModels 88; core User model path | WRONG | P1 | 79 active; no models/core/user | Recount / retarget |
| F-045 | Vol 3 02-graphql-pipeline.md | C5 | Gate emits SESSION_INVALID/EXPIRED | WRONG | P1 | CANNOT_ACCESS / TOKEN_INVALID | Fix codes |
| F-046 | Vol 6 inventory (queries 95; user components 56) | C7 | Counts | WRONG | P1 | ~137 gql; 36 user folders (measure when fixing) | Recount before publish |
| F-047 | Vol 0 axios “16” instances | C7 | 16 axios | STALE | P2 | 15 axios*.js files | Update count |
| F-048 | Various file:line (execSync, nginx compose line) | C8 | Exact lines | STALE | P2 | Drift vs current files | Refresh on edit |
4. Cross-Document Conflicts
| ID | Doc A | Doc B | Topic | Resolution (code wins) |
|---|---|---|---|---|
| X-001 | Vol 2.1–2.5 (cu-central live) | Vol 0/1/9 NestJS live | Live HR/auth bridge | cu-central-api via END_POINT_CENTRALIZE(_AUTH) |
| X-002 | Vol 10 NestJS “17 endpoints” | Vol 5 “12/16 endpoints” | NestJS route inventory | 17 total; employee 14 GET |
| X-003 | Vol 14 SEC-6/7/8/10 titles | A.4 debt-id index | Debt ID mapping | Vol 14 chapters are authoritative for IDs |
| X-004 | Vol 2 Redis vestigial | Vol 12/13 OTP in Redis | OTP store | cu-central MariaDB otp |
| X-005 | Vol 0.3 summary (cu-central) vs steps (NestJS) | Same file | Internal contradiction | Prefer code path GraphQL |
| X-006 | A.1 glossary vs A.2 “Volunteer Thai Red Cross” | Acronym/glossary | VTRC expansion | Align to one definition (verify with org naming — UNVERIFIED if no charter in repo) |
5. UNVERIFIED Register
| ID | Claim | Blocker | How to unlock |
|---|---|---|---|
| U-001 | NestJS centralize-api has a production caller | No client in this workspace (E-08); team-mentioned NEW_CENTRAIL_API / benefit-api absent | Obtain caller repo/config |
| U-002 | Host nginx TLS cipher suite / prod cert chain | Host-mounted nginx not fully auditable as production (E-02) | Ops sslscan + host conf |
| U-003 | Exact production listen port of cu-central behind nginx | Compose shows 8000; client example 8082; code default 8080 | Confirm deployed env + nginx upstream |
| U-004 | Official English expansion of “VTRC” | Conflict between glossary and acronyms; no charter file in workspace | Org naming authority |
| U-005 | Every non-trap factual sentence in all 202 files | Time-boxed CORPUS; full line-by-line claim extraction incomplete for low-risk narrative chapters | FILE/VOLUME passes per volume |
| U-006 | npm/yarn audit CVE inventory as stated in Vol 14 | Network audit not re-run this session (E-01) | Run audits with network |
6. Correction Checklist
P0
- [ ] Theme A — Live bridge: Fix NestJS-as-live-path in Vol 0, 1, 4, 8, 9, 12, 15 (and diagrams). Match Vol 2/3 wording.
- [ ] Theme B — Ports: Rewrite all absolute “cu-central = 8082/9000” using CODE_DEFAULT / CLIENT_TARGET / COMPOSE / EXPOSE classes.
- [ ] Theme C — KBANK: Replace ธนาคารกรุงเทพ with กสิกรไทย in Vol 0/1.
- [ ] Theme D — OTP/Redis: Rewrite Vol 12.7 and Vol 13.6/7/8; remove
otp:*vtrc-redis runbooks for registration OTP. - [ ] Theme E — statusKcash + cron gating: Replace Vol 11.3 table from
config.js:488-518; fix Vol 12 cron APP_NO narrative; remove K-Cash cron claims. - [ ] Theme F — Volume 7 Apollo/Docker/auth: Rewrite 7.2–7.4 from current source files.
- [ ] Theme H1 — Debt IDs: Make A.4 match Vol 14 SEC/LEG IDs exactly.
P1
- [ ] NestJS endpoint counts → 14 employee GET / 17 total across Vol 5.
- [ ]
dbHRMI_Center_NBCrename across Vol 0/8/glossary. - [ ] Vol 10 auth header + session key snippets.
- [ ] Env appendix regenerate from
.env.examplefiles. - [ ] Vol 3 model counts, User path, session error codes.
- [ ] Vol 6/7 inventory recounts (queries, folders, axios).
- [ ] Mark or repair
docs/audit/*as superseded where wrong.
P2
- [ ] Refresh stale
file:linecitations when editing those chapters. - [ ] Axios instance count 15; minor LOC drifts.
7. Coverage & Limitations
- Full trap verification (T1–T14): completed this run against primary sources.
- Mandatory cross-doc sweeps: completed (bridge, ports, bank, OTP/Redis, debt IDs).
- Volumes with dense claim re-check: 0, 1 (payments/slip/attendance), 3 (index/bridge claims), 4 (topology/scorecard), 5 (counts), 7 (Apollo/Docker), 8 (DB names), 9 (auth flow), 10 (auth headers/topology), 11.3, 12 (cron/redis/compose), 13 (redis/OTP runbooks), 14↔16 debt/env, 15.8 current-state,
docs/auditspot. - Deferred (U-005): exhaustive sentence-level extraction for remaining business narrative chapters (parts of Vol 1, 6 page deep-dives, 8 ERD field-by-field, 11 non-hospital workflows, 15 aspirational roadmap text except current-state). Deferred reason: CORPUS trap completion first; residual risk is lower-severity inventory/pedagogy unless traps reappear.
- Runtime verification: none.
- Prior audits: used as lead lists only; every P0 above re-validated in this run.
8. Recommended Errata Entries
Add to docs/volume-17-appendices/08-changelog-errata.md if not already present:
- E-09 NestJS still described as live bridge in multiple volumes
- E-10 cu-central port confusion (8080 / 8082 / 9000)
- E-11 KBANK documented as Bangkok Bank
- E-12 OTP/Redis mis-attributed to vtrc-api
- E-13
statusKcashtable in Vol 11 diverges fromconfig.js - E-14 Volume 7 Apollo/Docker docs diverge from source
- E-15 A.4 debt-id index conflicts with Vol 14
9. Sign-off
| Check | Status |
|---|---|
| No CORRECT without evidence | ☑ (canonical truths all cited) |
| All P0 have dual evidence when trap-class | ☑ |
| Cross-doc sweeps done for scope | ☑ |
| UNVERIFIED not hidden | ☑ (U-001–U-006) |
| Overall verdict consistent with findings | ☑ FAIL (P0 open) |
| Full 202-file sentence extraction | ☐ deferred (U-005) — prevents PASS even after P0 fixes until VOLUME sweeps complete |
Related artifact
Action checklist (earlier lead document): docs/DOC-CODE-DISCREPANCY-AUDIT.md
This file is the /docs-verify CORPUS report of record for 2026-07-11.