16.3 Wave 1 — Stabilize
Wave 1 ยกระดับ runtime และ dependency ที่ EOL ให้ทันสมัย แต่ยังอยู่บน architecture เดิม
เป้าหมายของ Wave 1
- Node runtime ทุกตัวเป็น LTS ปัจจุบัน (20+)
- ทุก service มี health endpoint
- CI/CD ครอบคลุมทุก repo
- Centralized logging + monitoring + alerting
- ลด High debt ได้ 15+ รายการ
- Effort: 3 เดือน (12 sprint)
ทีมที่ต้องการ
| บทบาท | จำนวน | หน้าที่ |
|---|---|---|
| Backend engineer | 2 | migration esm, Node upgrade, Apollo upgrade, RBAC |
| Frontend engineer | 1 | Apollo cache policy, AntD upgrade, axios consolidate |
| DevOps engineer | 1 | CI/CD, monitoring, logging |
| Database engineer (part-time) | 0.5 | schema migration, slow query |
ลำดับ task (dependency สำคัญ)
Sprint 3-4: esm shim → native ESM
│
▼
Sprint 5-6: Node 12 → 20 LTS
│
▼
Sprint 7-8: Apollo Server v2 → v4
│
Sprint 7-8: ───► parallel: RBAC fix, session index, txn fix
│
Sprint 9-10: dependency upgrade (redis, ldap, firebase)
│
Sprint 9-10: ──► parallel: frontend (Apollo cache, AntD)
│
Sprint 11-12: CI/CD, monitoring, logging, health endpointSprint 3-4 · esm shim → native ESM
Task 1.1 · แปลง esm shim เป็น native ESM
Debt: LEG-2 Effort: 2-3 สัปดาห์ ไฟล์: package.json และ source ทุกไฟล์ใน vtrc-api, cu-central-api
งาน:
- เพิ่ม
"type": "module"ใน package.json - เปลี่ยน
require→importทุกที่ - เปลี่ยน
module.exports→export default/export - ใช้
__dirname/__filenameทดแทนด้วยimport.meta.url - เปลี่ยนไฟล์ config ที่ใช้
.esmrc/-r esm - ลบ dependency
esm
กับดักที่พบบ่อย:
- ไฟล์ config ของ Sequelize ที่ใช้
.sequelizerc— ต้องแปลง - dependency ที่เป็น CommonJS — ใช้
import pkg from 'pkg'แล้วpkg.default - การ test ที่ใช้
esmloader — เปลี่ยนเป็น native ESM ของ test runner
Definition of Done:
- [ ]
esmไม่อยู่ใน package.json - [ ]
node .รันได้โดยไม่ใช้-r esm - [ ] ทุก test ผ่าน
- [ ] deploy ไป UAT แล้วทำงานได้
Rollback: คืน git commit ก่อนการแปลง (เป็นไปได้เพราะเป็น code-level change)
Task 1.2 · เครื่องมือช่วย
ใช้เครื่องมือ:
@babel/plugin-transform-modules-commonjs(สำหรับ auto-convert บางส่วน)cjs-to-esm(อาจมี bug, ใช้อย่างระมัดระวัง)- code review ทุกไฟล์ที่ auto-convert
Sprint 5-6 · Node 12 → 20 LTS
Task 1.3 · ยกระดับ Node runtime
Debt: LEG-1 Effort: 1 สัปดาห์ (หลัง Task 1.1 เสร็จ) ไฟล์: Dockerfile ทุกตัว
งาน:
- เปลี่ยน
FROM node:12→FROM node:20-alpine - แก้ native module ที่ต้อง rebuild (เช่น
node-qpdfถ้ายังใช้) - ปรับ
.nvmrcในทุก repo เป็น20 - ปรับ
engines.nodeเป็น>=20.0.0
กับดัก:
html-pdfใช้ PhantomJS ที่ไม่รองรับ Node 20 — ต้องเปลี่ยน (Task 1.10)- บาง dependency legacy ไม่รองรับ Node 20 — ตรวจก่อน
Definition of Done:
- [ ] ทุก Dockerfile ใช้ Node 20
- [ ] production service รันได้บน Node 20
- [ ] ทุก test ผ่าน
Sprint 7-8 · Apollo + แก้ debt สำคัญ
Task 1.4 · Apollo Server v2 → v4
Debt: LEG-3 Effort: 1-2 สัปดาห์ ไฟล์: vtrc-api, cu-central-api
งาน:
Apollo v4 มี breaking changes สำคัญ:
- เปลี่ยน
apollo-server→@apollo/server ApolloServerconstructor รับ schema เป็น parameter- context function เปลี่ยนรูป
- integration กับ Express เปลี่ยน (ใช้
expressMiddleware)
// v2
const server = new ApolloServer({ typeDefs, resolvers, context });
server.applyMiddleware({ app, path: '/api/graphql' });
// v4
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
app.use('/api/graphql', expressMiddleware(server, { context }));Definition of Done:
- [ ] ใช้
@apollo/serverv4 - [ ] GraphQL endpoint ทำงานเหมือนเดิม
- [ ] test ผ่าน
Task 1.5 · แก้ RBAC inconsistency (CORR-4)
Debt: CORR-4 Effort: 1-2 สัปดาห์ ไฟล์: vtrc-api/api/src/lib/repositories/session/session.js
งาน:
- เขียน test matrix (role × menu × action) ทุกกรณี
- รัน test กับ code ปัจจุบัน — บันทึกผลเป็น baseline
- แก้ source ให้ใช้ lookup path เดียวกัน
- รัน test อีกครั้ง — ผลลัพธ์ควรดีขึ้นหรือเท่าเดิม
- เอกสาร source of truth ของ RBAC
Definition of Done:
- [ ] test matrix ครอบคลุมทุกกรณี
- [ ] ไม่มีการอ้างอิง property ที่ไม่มีอยู่ (
role.accessRole) - [ ] policy test ผ่าน CI
Task 1.6 · Session indexed lookup (PERF-3)
Debt: PERF-3 Effort: 1-2 วัน ไฟล์: vtrc-api/api/src/models/core/session/session.js, repository
งาน:
- เพิ่มคอลัมน์
jwtId(indexed) ในตาราง Session - migration script เพื่อเติม jwtId จาก JSON ที่มีอยู่
- เปลี่ยน lookup จาก
userSession LIKE→WHERE jwtId = ? - ทดสอบ performance ก่อน/หลัง
Definition of Done:
- [ ] ตาราง Session มีคอลัมน์ jwtId (indexed)
- [ ] lookup ใช้ jwtId
- [ ] performance ดีขึ้น (> 10x เร็วขึ้นสำหรับตารางใหญ่)
Task 1.7 · แก้ transaction swallow (CORR-2)
Debt: CORR-2 Effort: 1-2 วัน ไฟล์: vtrc-api/api/src/lib/repositories/session/session.js
งาน:
เปลี่ยนจาก .then chain เป็น async/await:
// เดิม (มี race)
Models.db.transaction().then(t => {
return Models.Session.create(...).then(() => {
return t.commit();
}).catch(err => {
t.rollback();
responError(err);
});
});
// ใหม่ (ชัดเจน)
const t = await Models.db.transaction();
try {
await Models.Session.create(..., { transaction: t });
await t.commit();
} catch (err) {
await t.rollback();
throw err;
}Definition of Done:
- [ ] ไม่มี
.thenchain ที่มี transaction - [ ] test กรณี create fail → rollback เกิดจริง
Sprint 9-10 · Dependency upgrade + Frontend
Task 1.8 · ยกระดับ redis, jsonwebtoken (LEG-12, LEG-9 — ทำต่อจาก Wave 0)
Effort: 2-3 วัน ไฟล์: vtrc-api, cu-central-api
งาน:
- redis v3 → v4 (API เปลี่ยนเป็น Promise)
- jsonwebtoken v9 (จาก Wave 0)
- firebase-admin, googleapis ยกระดับ
Task 1.9 · เปลี่ยน ldapjs → ldapts (LEG-8)
Effort: 2-3 วัน ไฟล์: cu-central-api
งาน:
- ลบ
ldapjs, เพิ่มldapts - API คล้ายกันแต่ต้องตรวจทุก call site
Task 1.10 · เปลี่ยน html-pdf → Playwright (LEG-10)
Effort: 1 สัปดาห์ ไฟล์: vtrc-api, cu-central-api
งาน:
- ลบ
html-pdf,node-qpdf - เพิ่ม
playwright+pdfcpu(สำหรับ encryption) - เขียน wrapper ใหม่ที่มี interface เดียวกับเดิม
กับดัก: Playwright ใช้ headless Chrome ซึ่งใช้ memory มาก — ต้องจำกัด concurrent generation
Task 1.11 · Frontend — Apollo cache policy (PERF-2)
Effort: 1-2 วัน ไฟล์: vtrc-web/src/config/apollo.js
งาน:
- เปลี่ยน default
fetchPolicyเป็นcache-and-network - เพิ่ม
cache-firstสำหรับ query ที่เปลี่ยนน้อย (organization list, profile) - ทดสอบ UX ใน UAT
Task 1.12 · Frontend — AntD v3 → v4 (LEG-5)
Effort: 1 สัปดาห์ ไฟล์: vtrc-web
งาน:
- อัปเดต antd v3 → v4
- ใช้ codemod ของ AntD เพื่อ migrate
- ทดสอบทุกหน้า
Sprint 11-12 · Infrastructure
Task 1.13 · สร้าง CI/CD สำหรับ 3 repos
Effort: 1 สัปดาห์ ไฟล์: cu-central-api, centralize-api, vtrc-rc-backoffice
งาน:
- เขียน
bitbucket-pipelines.ymlสำหรับแต่ละ repo - pipeline: lint → test → build → push image → (manual deploy)
- เพิ่ม deployment environment ใน Bitbucket
Task 1.14 · Centralized logging
Effort: 1 สัปดาห์
งาน:
- ติดตั้ง Loki + Grafana (บน host ใหม่หรือ GCP VM)
- ติดตั้ง Promtail บนทุก host เพื่อส่ง log
- สร้าง dashboard สำหรับ error rate, slow request
Task 1.15 · Health endpoint ทุก service
Effort: 1-2 วัน
งาน:
- เพิ่ม
/healthendpoint ที่ตรวจสอบ DB + Redis connection - ใช้ใน docker-compose
healthcheck - ตั้ง uptime monitor ใหม่ให้ใช้
/health
Task 1.16 · ลบ _bk files 131 ไฟล์ (LEG-14)
Effort: 1-2 วัน
งาน:
- ลบไฟล์ทั้งหมดที่ตรง pattern
_bk*,_copy*,_removed* - เพิ่ม
.gitignore+ pre-commit hook
เกณฑ์การตัดสินใจว่า Wave 1 เสร็จ
- [ ] Node runtime ทุกตัวเป็น LTS 20+
- [ ] ทุก service มี health endpoint
- [ ] CI/CD ครอบคลุม 5/5 repos
- [ ] centralized logging + monitoring ทำงาน
- [ ] High debt ลดลง ≥ 15 รายการ
- [ ] MTTR < 1 ชั่วโมง (วัดจาก monitoring)
- [ ] team retrospective — บันทึก lesson learned
ความเสี่ยงของ Wave 1
| ความเสี่ยง | ผลกระทบ | Mitigation |
|---|---|---|
| esm migration มี bug | service พัง | ทดสอบใน UAT นาน, ค่อย ๆ migrate ทีละ module |
| Apollo v4 breaking change | endpoint พัง | เขียน integration test ก่อน migrate |
| RBAC fix เปลี่ยน behavior | ผู้ใช้บางคนเสียสิทธิ์ | test matrix ครอบคลุม, ค่อย ๆ roll out |
| AntD v3 → v4 | UI พัง | codemod + ทดสอบทุกหน้าใน UAT |
สรุป Wave 1
Wave 1 ใช้เวลา 3 เดือน ลด High debt ได้ 15+ รายการ และวาง infrastructure สำหรับ Wave 2
เมื่อ Wave 1 เสร็จ ทีมพร้อมเริ่ม Wave 2 (extract bounded context ไป Go)
บทถัดไปจะลงรายละเอียด Wave 2