5.9 · Scorecard + ownership + comparison
บทสุดท้ายของ Volume 5 สรุป centralize-api ในรูปแบบ scorecard เทียบกับมาตรฐาน NestJS production, ทบทวน ownership และ caller ที่ยังไม่ยืนยัน, และเปรียบเทียบกับ vtrc-api และ cu-central-api เพื่อให้เห็นตำแหน่งของ service ตัวนี้ในระบบ VTRC
Scorecard — ภาพรวมตามตัวชี้วัด
| มิติ | คะแนน | หมายเหตุ |
|---|---|---|
| Type safety | 2/5 | strictNullChecks: false, noImplicitAny: false, any ใช้แพร่หลาย |
| Test coverage | 0/5 | ไม่มี unit test จริง — empty spec + broken e2e |
| Documentation | 2/5 | Swagger doc พอใช้ แต่ response type ไม่ annotated + README เป็น starter default |
| Error handling | 1/5 | BadRequestException สำหรับทุก error, filter จับแค่ HttpException |
| Security | 1/5 | 4 Critical + 7 High (บท 5.8) |
| Production hardening | 1/5 | ไม่มี helmet, compression, health check, graceful shutdown |
| Dependency hygiene | 2/5 | outdated 2-3 major, moment deprecated, passport-local unused |
| Code organization | 3/5 | NestJS module pattern ชัดเจน แต่มี dead code + copy-paste CTE 4 ครั้ง |
| SQL safety | 4/5 | parameterized queries ทุกที่ ไม่พบ injection (ดีที่สุดในระบบ) |
| Schema migration | 5/5 | synchronize: false — TypeORM ไม่ alter HRMI ไม่มีความเสี่ยง |
| รวม | 21/50 | ต่ำ — service ทำงานได้แต่มี debt สะสมสูง |
รายละเอียดตามมิติ
Type safety — 2/5
TypeScript ปิด strict checks ส่วนใหญ่ทำให้เสียประโยชน์หลักของภาษา ในระบบมี any กระจายอยู่ใน JwtStrategy, repositories ทั้ง 3, และ controller return types
→ NestJS + TypeScript โดยปกติให้ type safety สูง แต่ centralize-api ตั้งค่าทำให้กลายเป็น JavaScript ที่มี decorator
Test coverage — 0/5
ไม่มี unit test หรือ integration test จริง — ไฟล์ *.spec.ts และ *.e2e-spec.ts ที่มีเป็นโค้ดค้างจาก starter template ที่ไม่ได้เขียน logic อะไร
→ ทุก refactor เสี่ยงเพราะไม่มี safety net
Documentation — 2/5
Swagger UI (/docs) serve ได้แต่
- response type ไม่ annotated → client ไม่ทราบ shape
- description ของ service ว่าง (
setDescription('')) - IP internal รั่วใน
addServer - BearerAuth หลอก เพราะ guard bypass
README เป็น NestJS starter default — ไม่มีข้อมูล architecture, env vars, deploy
Security — 1/5
บท 5.8 ระบุช่องโหว่ 4 Critical + 7 High — ส่วนใหญ่ยังไม่ได้รับการแก้ไขใน production
ถ้า service ถูก expose ออก internet โดยตรง → data breach ทันที ปัจจุบันอาจรอดเพราะอยู่ใน private network แต่ก็เป็นอันตรายที่ซ่อนรอ
SQL safety — 4/5 (จุดเด่น)
parameterized queries ทุกที่ — ไม่มี string interpolation ของ user input ใน SQL ใด ๆ ทำให้ centralize-api เป็น service ที่ปลอดภัยจาก SQL injection ที่สุดในระบบ VTRC
ลด 1 คะแนนเพราะ WITH (NOLOCK) ทุกที่ทำให้ dirty read เป็นไปได้ (acceptable สำหรับ HR facade แต่ต้องเขียน doc)
Ownership + caller ที่ยังไม่ยืนยัน
ข้อเท็จจริงที่ตรวจสอบได้จาก code
- centralize-api รันบน port 3000 ด้วย REST API ที่ prefix
/api - vtrc-api มี config
END_POINT_CENTRALIZEใน.env.example:36ชี้ไปhttp://localhost:8082/api/graphql(CLIENT_TARGET ตัวอย่าง) - path
/api/graphqlตรงกับ cu-central-api (Node 12 Apollo GraphQL) — CODE_DEFAULTAPP_PORT=8080; ไม่ใช่ NestJS centralize-api (port 3000) - ไม่พบ code ใน vtrc-api ที่เรียก
/api/employee,/api/hrPaySlip,/api/hrTimeTempของ NestJS centralize-api โดยตรง
สาเหตุที่เป็นไปได้
| # | สมมุติฐาน | หลักฐานสนับสนุน | หลักฐานคัดค้าน |
|---|---|---|---|
| A | centralize-api ตัวนี้เป็น service ที่ยังไม่เสียบใช้จริง (orphan) | มี .env committed, มี Swagger doc → ดูเหมือนจะใช้ | แต่ไม่พบ caller — ทำไม commit แล้ว? |
| B | มี caller อื่นที่ไม่ใช่ vtrc-api (เช่น cu-central-api proxy ต่อ) | cu-central-api เป็น Node 12 ที่อาจเรียก REST ของ centralize-api ผ่าน axios หรือ node-fetch | ไม่ได้ตรวจสอบ cu-central-api ในระดับนี้ |
| C | env ใน .env.example ไม่ตรงกับสภาพแวดล้อมจริงใน production | .env.example เป็นตัวอย่าง dev — production อาจชี้ END_POINT_CENTRALIZE ไป port 3000 จริง | แต่ถ้าเช่นนั้นควรมี .env.production ที่บอก |
| D | centralize-api ตัวนี้เป็นเวอร์ชั่น rewrite ของ cu-central-api ที่จะมาแทนที่ | ทั้งสองอ่าน HRMI schema เดียวกัน, มี SourceDB pattern เดียวกัน | แต่ cu-central-api ใช้ GraphQL + LDAP auth ส่วน NestJS ใช้ REST + JWT — ไม่ใช่การแทนที่โดยตรง |
คำแนะนำในการ verify
ก่อน refactor centralize-api ตัวนี้ ควรตรวจสอบให้แน่ใจว่า caller คือใครก่อน
- Log access — เปิด access log ของ centralize-api แล้วดูว่าในช่วง 7 วันมี request เข้ามาจาก IP ใดบ้าง
- ค้นหาในทุก repo — grep
:3000/api/หรือcentralize-apiในทุก source code ขององค์กร (รวม backoffice, internal tools) - สอบถามทีม CU/RC — เพราะ HRMI schema เป็นของทีม CU/RC อาจทราบว่ามี caller ที่ไม่ได้เก็บใน VTRC repo
- ทดสอบด้วยการปิด service — ถ้าปิด centralize-api แล้ว feature ใดพัง → feature นั้นคือ caller
ถ้าไม่พบ caller ใด ๆ → อาจ safe to deprecate หรือ archive
ผลกระทบต่อการวางแผน refactor
| สถานการณ์ | คำแนะนำ |
|---|---|
| ไม่พบ caller จริง | อย่า refactor ทันที — อาจเป็นการเสียเวลา ให้ deprecate หรือ archive ก่อน |
| พบ caller 1-2 ตัวใน VTRC | วางแผน coordinated refactor พร้อม caller |
| พบ caller ภายนอก VTRC | ต้องประสานงานข้ามทีมก่อน refactor ใด ๆ |
เปรียบเทียบกับ vtrc-api และ cu-central-api
ตารางเปรียบเทียบโครงสร้าง
| มิติ | vtrc-api | cu-central-api | centralize-api |
|---|---|---|---|
| Stack | Node.js + Express + Apollo GraphQL | Node.js + Apollo GraphQL + Sequelize | NestJS + TypeORM + TypeScript |
| Database | MariaDB (Sequelize) | MSSQL HRMI (Sequelize) | MSSQL HRMI (TypeORM) |
| Port | 8081 /api/graphql | CODE_DEFAULT APP_PORT=8080 (CLIENT_TARGET ตัวอย่าง 8082; compose มัก 8000; EXPOSE 9000 ≠ listen) | 3000 /api/... |
| รูปแบบ API | GraphQL (hand-written schema) | GraphQL | REST + Swagger |
| Auth | JWT + apiKey (custom) | LDAP/AD + JWT | JWT (แต่ bypass) |
| SourceDB sharding | ไม่มี | มี | มี |
| Cron jobs | มี (node-schedule) | มี | ไม่มี |
| Health endpoint | มี (ผ่าน /api) | ไม่ชัดเจน | ไม่มี |
| Test coverage | ไม่มีจริง | ไม่มี | ไม่มี |
บทบาทในระบบ VTRC
┌─────────────────────────────┐
│ vtrc-web (front-end) │
└─────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ vtrc-api (core) │
│ - บริการหลักของทั้งสอง frontend │
│ - เก็บข้อมูล welfare/leave/slip ใน MariaDB │
└─────────────────────────────────────────┘
│ │
(graphql) │ │ (REST/Swagger?)
▼ ▼ (caller ไม่ยืนยัน)
┌────────────────────────┐ ┌──────────────────────────┐
│ cu-central-api │ │ centralize-api (NestJS) │
│ - ตัวกลาง auth LDAP │ │ - HR facade read-only │
│ - HR data integration │ │ - 17 endpoints │
│ - multi-tenant sharding│ │ - auth bypass │
└────────────────────────┘ └──────────────────────────┘
│ │
└───────────┬───────────┘
▼
┌────────────────────────┐
│ HRMI MSSQL │
│ - dbHRMI_Center │
│ - dbHRMI_Center_NBC │
└────────────────────────┘จุดสังเกต — vtrc-api เป็น caller ของ cu-central-api ที่ยืนยันแล้ว (ผ่าน END_POINT_CENTRALIZE) แต่ caller ของ centralize-api (NestJS) ยังไม่ยืนยัน
จุดเด่นที่ centralize-api มีเป็น unique
- TypeScript + NestJS — service ตัวเดียวในระบบที่ใช้ TypeScript จริงจัง (cu-central-api ก็เป็น Node 12 JavaScript)
- REST + Swagger — service ตัวเดียวที่มี interactive API documentation (vtrc-api และ cu-central-api ใช้ GraphQL ที่ต้องใช้ GraphQL Playground)
- DTO validation — class-validator + class-transformer ที่ตรวจ input ทุก request (vtrc-api ตรวจใน resolver เอง)
- SQL injection-safe — parameterized queries 100% (ดีที่สุดในระบบ)
จุดด้อยเมื่อเทียบกับ vtrc-api
| มิติ | vtrc-api | centralize-api |
|---|---|---|
| Auth | JWT + apiKey ทำงานจริง | JWT bypass |
| Mutation | มี mutation endpoint | ไม่มี (read-only) |
| Business logic | มี welfare/leave/slip logic มาก | มีเฉพาะ time attendance merge |
| Schema migration | มี syncModelToTable | synchronize: false |
| Cron | มี 5+ jobs | ไม่มี |
→ centralize-api มีขอบเขตแคบกว่า vtrc-api มาก ทำหน้าที่เป็น facade ฝั่งอ่านเท่านั้น
สรุป — บทบาทของ centralize-api ในระบบ VTRC
จากการวิเคราะห์ทั้ง Volume สรุปได้ว่า centralize-api มีลักษณะดังนี้
- เป็น HR master data facade — อ่าน HRMI MSSQL ผ่าน raw SQL parameterized queries อย่างปลอดภัย
- ขนาดเล็กและจำกัดขอบเขต — 17 endpoints ทั้งหมด read-only, ไม่มี cron, ไม่มี mutation
- ออกแบบด้วย NestJS + TypeScript — pattern ที่ทันสมัย แต่ configuration ปิด type safety ไว้มาก
- มี Swagger documentation — จุดเด่นที่ service อื่นไม่มี แต่ doc ไม่สมบูรณ์
- มี technical debt สูง — 4 Critical + 7 High severity security issues ที่ active
- Caller ยังไม่ยืนยัน — ใน source code ที่ตรวจสอบ vtrc-api ไม่ได้เรียกตรง ๆ อาจมี caller อื่นที่ไม่ได้เก็บใน repo
คำแนะนำสำหรับทีม
- เร็วที่สุด — verify caller ก่อน (§"Ownership") แล้วค่อยวางแผน Phase 1 security fix
- Phase 1 — แก้ 4 Critical (เปลี่ยน password, สุ่ม JWT secret, เปิด auth, ปิด query logging)
- Phase 2 — แก้ 7 High + error handling refactor
- Phase 3 — ปรับปรุงระบบสมัยใหม่ (upgrade dep, เปิด strict mode, เขียน test)
- Phase 4 — เลือกว่าจะ keep service นี้, deprecate, หรือ merge เข้า cu-central-api
จบ Volume 5
Volume นี้เจาะ centralize-api ตั้งแต่ระดับไฟล์ไปจนถึง business logic และ security posture โดยมี file:line reference ครอบคลุมทุกประเด็นที่สำคัญ หากต้องการเจาะลึกเพิ่มเติมแนะนำ
- Volume 3.4 — The centralize bridge ใน vtrc-api ที่เรียก cu-central-api (ชื่อโฟลเดอร์
centralize/แต่ปลายทางคือ cu-central) - Volume 4 — cu-central-api ที่เป็น downstream จริงของ
END_POINT_CENTRALIZE - Volume 8.1 + 8.9 — Persistence topology + Identity across databases ที่อธิบาย HRMI schema เต็มรูปแบบ