15.8 Build & reproducibility debt
บทนี้รวบรวม debt ที่กระทบความสามารถในการ build ซ้ำได้ผลลัพธ์เดิม (reproducibility) และความน่าเชื่อถือของ build process
รายการทั้งหมด
LEG-15 · centralize-api ไม่มี lockfile
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | centralize-api/ — ไม่มี yarn.lock commit, ทั้งที่ Dockerfile ใช้ yarn install |
| ปัญหา | build ไม่ reproducible — yarn install ในแต่ละครั้งอาจได้ dependency version ต่างกัน |
| Impact | build ใน dev อาจไม่เหมือน production การ debug ปัญหายาก |
| Mitigation ระยะสั้น | commit yarn.lock ที่ generate จาก yarn install ครั้งแรก |
| แนวทางระยะยาว | CI ตรวจ lockfile drift — ถ้า yarn install เปลี่ยน lockfile ให้ fail |
LEG-16 · vtrc-web มีทั้ง yarn.lock และ package-lock.json
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | vtrc-web/ — มีทั้ง yarn.lock และ package-lock.json |
| ปัญหา | dual-resolver state — นักพัฒนาคนหนึ่งใช้ yarn อีกคนใช้ npm แต่ละคน lock คนละ file ผลลัพธ์การ install อาจต่างกัน |
| Impact | build ไม่ consistent ระหว่างเครื่อง ความสับสนในการ add dependency |
| Mitigation ระยะสั้น | เลือกตัวจัดการ dependency ตัวเดียว (yarn classic ตามที่เคยใช้) ลบอีกอัน |
| แนวทางระยะยาว | policy: 1 package manager ต่อ repo |
LEG-17 · TypeScript safety ปิดอยู่
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | centralize-api/tsconfig.json:15-19 — strictNullChecks: false, noImplicitAny: false, forceConsistentCasingInFileNames: false |
| ปัญหา | safety net ของ TypeScript ถูกปิด — เขียน TS แต่ไม่ได้ประโยชน์จาก type safety |
| Impact | bug ที่ type ช่วยตรวจไม่ได้ เช่น null reference, implicit any |
| Mitigation ระยะสั้น | เปิด strictNullChecks ก่อน (ตามด้วยการแก้ type error ที่เกิด) |
| แนวทางระยะยาว | strict: true ในทุก tsconfig |
LEG-18 · ไม่มี engines field ทุก package.json
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | rg '"engines"' → 0 matches ในทุก package.json |
| ปัญหา | ไม่จำกัด version ของ Node ที่ใช้ install/run — Node version ใดก็ได้ |
| Impact | นักพัฒนาใช้ Node version ต่างกัน อาจเจอ bug ที่เกิดจากความแตกต่างของ version |
| Mitigation ระยะสั้น | เพิ่ม "engines": { "node": ">=20.0.0" } ในทุก package.json |
| แนวทางระยะยาว | CI ตรวจ engines field ใช้ .nvmrc หรือ volta |
LEG-19 · In-process node-schedule สำหรับ cron
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | vtrc-api/api/src/crons.js (72 LOC) + cu-central-api/main-api/src/cron.js |
| ปัญหา | node-schedule รัน in-process — ไม่มี high availability, ไม่มี retry, ไม่มี visibility ถ้า replica ที่ถือ job restart ระหว่างรัน job จะหาย กับ 4 replica แต่ละ replica อาจรันซ้อน |
| Impact | cron job ที่หายไปไม่มีใครรู้ cron ที่รันซ้อนอาจทำให้ข้อมูลซ้ำ |
| Mitigation ระยะสั้น | ใช้ APP_NO=1 gate (ทำอยู่แล้ว) + log ทุก job ที่รัน + การตรวจสอบ |
| แนวทางระยะยาว | distributed scheduler — BullMQ + Redis (Node) หรือ asynq/robfig/cron (Go) กับ distributed lock |
LEG-20 · axios instances 16+ ตัวใน backoffice
| ข้อมูล | รายละเอียด |
|---|---|
| Evidence | vtrc-rc-backoffice/src/config/axios-*.js — 16+ ไฟล์ (PMS, Recruitment, Meeting, WorkForce, Payments, Benefit, AI, ...) |
| ปัญหา | axios instance แยก 16+ ตัว — แต่ละตัวมี config + interceptor + token-refresh path ของตัวเอง |
| Impact | การ maintain ใช้เวลานาน, ความเสี่ยง token-refresh path ต่างกันในแต่ละ instance |
| Mitigation ระยะสั้น | รวม instance ที่ config เหมือนกัน |
| แนวทางระยะยาว | ใช้ typed API client หนึ่งตัวต่อ bounded context |
ปัญหาที่ไม่มี ID แต่สำคัญ
ไม่มี health check endpoint
ไม่มี service ใดที่มี /health หรือ /healthz — Dockerfile ไม่ได้กำหนด HEALTHCHECK การตรวจสอบสถานะ service ต้องทำผ่าน URL อื่น ๆ (เช่น GraphQL playground) ที่ไม่ได้ออกแบบมาสำหรับ monitoring
ไม่มี CI/CD สำหรับ 3 repos
มี pipeline เฉพาะ vtrc-api และ vtrc-web — cu-central-api, centralize-api, vtrc-rc-backoffice deploy ด้วยมือทั้งหมด
Docker image ไม่ pin version
หลาย Dockerfile ใช้ FROM node:12 ไม่ใช่ FROM node:12.18.3-alpine3.11 — image ที่ได้จาก build แต่ละครั้งอาจต่างกัน
ไม่มี SBOM (Software Bill of Materials)
ไม่มีการ generate SBOM ของ dependency ทำให้การตอบสนองต่อ CVE ใหม่ ๆ ช้า — ไม่รู้ว่าแพ็กเกจที่มี CVE อยู่ใน image ใดบ้าง
สรุป
| ID | รายการ | Severity | Effort ระยะสั้น |
|---|---|---|---|
| LEG-15 | centralize ไม่มี lockfile | High | 30 นาที |
| LEG-16 | vtrc-web สอง lockfile | Med | 30 นาที |
| LEG-17 | TS safety ปิด | High | 1-2 สัปดาห์ (incremental) |
| LEG-18 | ไม่มี engines | Med | 30 นาที |
| LEG-19 | in-process cron | High | (architectural — Wave 2) |
| LEG-20 | axios 16+ instances | Med | 1 สัปดาห์ |
ไม่มี ID
| รายการ | Effort |
|---|---|
เพิ่ม /health endpoint ทุก service | 1-2 วัน |
| สร้าง CI/CD สำหรับ 3 repos ที่เหลือ | 1 สัปดาห์ |
| Pin Docker image version | 30 นาทีต่อ Dockerfile |
| Generate SBOM | 1-2 วัน |
บทถัดไปจะรวบรวมทุกรายการเป็น heat-map เพื่อช่วยตัดสินใจจัดลำดับ