0.2 · ภาพรวมระบบใน 1 หน้า
บทนี้วาดภาพใหญ่ของระบบทั้งหมดในหน้าเดียว ถ้าจำได้แค่หน้านี้ ก็พอที่จะ debug ได้ว่าปัญหาอยู่ตรงไหน
กฎเหล็กของระบบนี้ (จำให้ได้)
frontend ทั้งสองตัวคุยกับ API ตัวเดียวเท่านั้น คือ vtrc-api — ไม่มีทางเรียก centralize-api หรือ cu-central-api โดยตรง
ถ้าเจอปัญหาใน flow ข้อมูลของ frontend ให้ debug ที่ vtrc-api ก่อนเสมอ ไม่ใช่เริ่มที่ frontend
5 Repos ทำหน้าที่อะไรบ้าง
vtrc/
├── vtrc-web/ frontend ฝั่งพนักงาน (React 16 + AntD v3)
├── vtrc-rc-backoffice/ frontend ฝั่ง HR (React 16 + AntD v4 + MUI v5)
├── vtrc-api/ API แกนกลาง — ทุก request ผ่านที่นี่
├── centralize-api/ NestJS modernization template (REST/MSSQL) — ไม่ใช่ live hop ของ frontend
└── cu-central-api/ live identity + HR GraphQL ที่ vtrc-api เรียกจริง (Node 12 + LDAP)| Repo | Stack | Port | บทบาทสั้น |
|---|---|---|---|
vtrc-api | Node 12 + Apollo 2 + Sequelize + MariaDB + Redis | 8081 | แกนกลาง ทั้ง frontend เรียกที่นี่ |
vtrc-web | React 16 + Webpack 4 + Apollo v2 + AntD v3 | 3000 | หน้าพนักงาน |
vtrc-rc-backoffice | React 16 + CRA + Apollo v2 + AntD v4 + MUI v5 + Recoil | 3000 | หน้า HR |
centralize-api | NestJS 9 + TypeScript + TypeORM + MSSQL + Swagger | 3000 (/api, /docs) | modernization template — caller จาก vtrc-api ไม่ยืนยันใน workspace |
cu-central-api | Node 12 + Apollo 2 + Sequelize + LDAP + Redis + MSSQL | APP_PORT default 8080 (ดูหมายเหตุพอร์ตด้านล่าง) | live identity + HR data ที่ END_POINT_CENTRALIZE ชี้ไป |
หมายเหตุพอร์ต cu-central-api — ในโค้ด cu-central-api/main-api/src/config.js ค่า default คือ APP_PORT = 8080 ส่วน vtrc-api/api/.env.example ตั้ง END_POINT_CENTRALIZE เป็น localhost:8082 (CLIENT_TARGET / mapping ของ env ตัวอย่าง) Dockerfile มี EXPOSE 9000 ซึ่งเป็น metadata ของ image ไม่ใช่ listen port จริง และ docker-compose.yml ของ cu-central มัก map พอร์ต 8000 — อย่าสรุปว่าแอปฟังที่ 9000
แต่ละ repo ทำอะไร แบบเจาะ
vtrc-api — ทุกอย่างผ่านที่นี่
เป็น API ที่ frontend ทั้งคู่เรียก ทำหลายอย่างมาก
- authentication และ RBAC (
@authdirective) - payslip, tax, salary certificate
- leave (12 ประเภท) + multi-level approval
- welfare withdrawal (WDHospital — 13-state machine)
- provident fund
- time attendance (read-only — ดึงจาก HRMI ผ่าน cu-central)
- notification, news, document, policy
- PDF generation (slip + tax + cert + ใบเสร็จ) ผ่าน
routes.js - bridge ไป
cu-central-apiผ่านโฟลเดอร์centralize/+END_POINT_CENTRALIZE(GraphQL) /END_POINT_CENTRALIZE_AUTH(REST auth) - cron jobs ใน
crons.js(in-process, ไม่มี HA)
โครงภายในเป็น 3 layer: typeDefs (43 ไฟล์) → resolvers (41 ไฟล์) → lib/{controllers, repositories} (31+31 โฟลเดอร์) — รายละเอียดใน Volume 3
vtrc-web — หน้าพนักงาน
React SPA ที่พนักงานเปิดใน browser เน้นฟีเจอร์ดูข้อมูล (สลิป, เวลาทำงาน, ข่าว) และยื่นคำขอ (ลา, เบิกสวัสดิการ)
มีไฟล์ GraphQL operations อันเดียวที่ยาว 4,493 บรรทัด (src/graphql/queries.js) — เป็นไฟล์ที่ทุก query ของทุกหน้าอยู่รวมกัน
vtrc-rc-backoffice — หน้า HR
React SPA ที่ HR ใช้ เน้นฟีเจอร์อนุมัติและจัดการ
ไฟล์ operations ยาว 4,108 บรรทัด (queries.js) และ mutations ยาว 2,208 บรรทัด
มี axios instances 15 ตัว ใน src/config/ (axios*.js — เช่น axios-pms.js, axios-recruitment.js, axios-workforce.js, ...) — แต่ละตัวต่อ subsystem ของระบบย่อย บ่งชี้ว่า backoffice เป็น federated portal ของหลายระบบที่ glue รวมกันใน bundle เดียว
centralize-api — modernization template (แยกจาก live path)
NestJS + TypeScript + TypeORM + MSSQL + Swagger
เป็น repo เดียวที่ใช้ stack สมัยใหม่และมี pattern ที่ถูกต้อง (DTO validation, JWT guard, global exception filter, Swagger) — ทีมใช้เป็น template สำหรับ modernization ในอนาคต
อ่าน HR data จาก MSSQL (dbHRMI_Center + dbHRMI_Center_NBC) ผ่าน REST เช่น GET /api/employee, POST /api/hrPaySlip, POST /api/hrTimeTemp/import, ฯลฯ
ไม่ใช่ hop ที่ vtrc-api เรียกใน live payslip / time-attendance / auth flow ของ workspace นี้ — อย่าสับสนกับโฟลเดอร์ vtrc-api/api/src/centralize/
cu-central-api — live identity + HR data
Node 12 + Apollo 2 + LDAP + MSSQL + Redis
เป็นปลายทางจริงของ END_POINT_CENTRALIZE / END_POINT_CENTRALIZE_AUTH ดูแล
- identity verification ผ่าน LDAP/AD ของจุฬา (พนักงานที่สังกัด CU) — REST
/signinฯลฯ ภายใต้END_POINT_CENTRALIZE_AUTH - อ่าน/จัดการ HR raw data (MSSQL) ผ่าน Sequelize ของตัวเอง (
db,dbHr, … ในcu-central-api/main-api/src/connector.js) - OTP/SMS + SFTP file transfer
- two-way sync กับ HRMI
4 Logical Databases
จุดที่ทำให้ระบบซับซ้อนที่สุด คือมี database แยกกัน 4 อัน บน engine 2 ตัว
MariaDB (engine เดียวกัน, host เดียวกัน)
├── schema: vtrc ← เขียนโดย vtrc-api (db connection)
│ users, sessions, leave, withdraw, fund, ...
└── schema: vtrc-centralize ← เขียนโดย vtrc-api (db2 connection)
cross-schema join tables
MSSQL (HRMI — ระบบ HR ภายนอก)
├── dbHRMI_Center ← อ่านโดย cu-central-api (live) + NestJS centralize-api (template)
└── dbHRMI_Center_NBC ← อ่านโดย NestJS centralize-api (conn "nbc") — ชื่อเต็มในโค้ด/SQL| # | Database | Engine | Owner | ทำอะไร |
|---|---|---|---|---|
| 1 | vtrc | MariaDB | vtrc-api (db conn) | application state — users, sessions, leave, withdraw, fund, ... |
| 2 | vtrc-centralize | MariaDB | vtrc-api (db2 conn) | cross-schema join tables |
| 3 | dbHRMI_Center | MSSQL | cu-central-api (live) + centralize-api (template) | HR Master Data (Employee, PaySlip VIEWs, ...) |
| 4 | dbHRMI_Center_NBC | MSSQL | centralize-api (และ SQL ที่อ้างชื่อนี้ใน NestJS) | NBC variant (กลุ่มพนักงานแยก) |
กฎสำคัญ — vtrc-api เป็น read-mostly consumer ของ HRMI ผ่าน GraphQL ของ cu-central-api และ ไม่ มี Sequelize MSSQL (dbHr) ใน vtrc-api/api/src/connector.js (export แค่ db กับ db2)
ฝั่ง cu-central-api มี two-way sync กับ HRMI — ดังนั้นกฎ "ไม่เคยเขียน MSSQL" ใช้กับ vtrc-api เป็นหลัก ไม่ใช่กับ cu-central ทั้งก้อน
ถ้าเจอโค้ดที่พยายาม UPDATE หรือ INSERT ลง MSSQL จาก path ของ vtrc-api โดยตรง ให้ระวัง — อาจเป็น bug หรือเป็น feature ที่ไม่ได้ activate
ข้อมูลวิ่งอย่างไรในการดูสลิปเงินเดือน (ตัวอย่าง)
ตัวอย่าง flow ที่ใช้กันบ่อยที่สุด — พนักงานกดดูสลิป
1. browser (vtrc-web)
POST https://vtrcapi.redcross.or.th/api/graphql
Headers: apiKey + Authorization: Bearer <jwt>
Body: query fetchSlip(month, year)
2. vtrc-api
- context(): เช็ค apiKey ว่าตรง API_DEVICE_KEY ไหม
- ถ้าผ่าน, verify JWT (TTL 15 นาที) → ดึง sessionId
- @auth(accessRole: ["USER"]) directive เช็ค session + role
- เรียก lib/repositories/slip → centralize/controllers/slip.js
3. centralize/controllers/slip.js (ใน vtrc-api)
- GraphqlCDWithToken → END_POINT_CENTRALIZE (GraphQL ของ cu-central-api)
- header: API_CENTRALIZE_KEY
4. cu-central-api
- GraphQL resolver คิวรี่ MSSQL VIEW (PaySlip)
- ส่ง JSON กลับ
5. vtrc-api
- ส่ง response กลับ frontend
- (ไม่มี Redis key payslip:{emp}:{date} บน path นี้ — ไม่เขียน cache สลิป)
6. browser (vtrc-web)
- render สลิปในหน้าจอถ้าพนักงานกดดาวน์โหลด PDF จะเป็น flow อื่นที่ใช้ REST endpoint (ไม่ใช่ GraphQL) — ดูรายละเอียดใน Volume 11 · API Reference และคำเตือนเรื่อง security ใน บท 0.1
URL ที่ผู้ใช้รู้จัก
frontend เลือก GraphQL endpoint ที่จะยิงแบบ runtime โดยดูจาก window.location.href — แต่ละ frontend มี checkLinkURL() ของตัวเอง อย่ารวมตารางเป็นไฟล์เดียว
vtrc-web — vtrc-web/src/config/apollo.js
| Origin ที่ user เปิด | GraphQL endpoint ที่ใช้ |
|---|---|
https://vtrc.redcross.or.th/ | https://vtrcapi.redcross.or.th/api/graphql |
https://uat-vtrc.redcross.or.th/ | https://uat-vtrcapi.redcross.or.th/api-uat/graphql |
http://localhost:3000/ (หรือ 192.168.0.105:3000) | ชี้ไป UAT โดย default |
vtrc-rc-backoffice — vtrc-rc-backoffice/src/config/apollo.js
| Origin ที่ user เปิด | GraphQL endpoint ที่ใช้ |
|---|---|
https://vtrcbackoffice.redcross.or.th/ หรือ https://rc-vtrcbackoffice.redcross.or.th/ | https://vtrcapi.redcross.or.th/api/graphql |
https://uat-vtrcbackoffice.redcross.or.th/ | https://uat-vtrcapi.redcross.or.th/api-uat/graphql |
https://uat-rc-vtrcbackoffice.redcross.or.th/ | https://uat-vtrcapi.redcross.or.th/api-uat/graphql |
http://localhost:3000/ หรือ http://localhost:3001/ | ชี้ไป UAT โดย default |
https://backoffice-vtrc.web.app | https://api.vtrcapp.com/api-dev/graphql |
สังเกตว่า prod ใช้ path /api/graphql แต่ UAT ใช้ /api-uat/graphql — เป็น pattern เดียวกันทั้ง frontend ทั้งคู่
ถ้าแก้ config ฝั่ง frontend อย่าทำผ่าน .env — ให้แก้ใน checkLinkURL() ของ frontend นั้น ตาม pattern เดิม ตามกฎใน .cursor/rules/workspace-structure.mdc