19.2 · 6-month correctness & data integrity
ขอบฟ้า เดือน 3–6 (ทับซ้อนท้ายของ 90 วันสำหรับงานที่เริ่มแล้ว) — แก้ bug ที่ทำให้ข้อมูลผิด / ส่งแจ้งเตือนผิด / auth flow พัง โดยที่ security emergency ใน 19.1 ต้องปิดพื้นผิว Critical ไปก่อนแล้ว
/ Months 3–6 — fix correctness and integrity defects after the 90-day emergency surface is closed. Wrong data and broken auth flows are in scope; framework rewrites are not.
แหล่งหลัก: vtrc-api/10 (CORR-VTRC-API-*), pms-api/06 (cron / notification), benefit-api/06 (dual hospital schema), Vol 12.5 (CORR-SSO-01)
ทำไมต้องแยกจาก security emergency
| Security 90 วัน | Correctness 6 เดือน |
|---|---|
| ผู้โจมตีภายนอก / credential leak | ผู้ใช้ภายในเจอข้อมูลผิด / email ซ้ำ / leave ค้าง |
| ปิดได้ด้วยลบโค้ด / rotate | ต้อง regression test + เข้าใจ business rule |
| Coordination หลัก = secret ownership | Coordination หลัก = HR / finance / PMS ops |
การแก้ transaction pattern ผิดทั้ง vtrc-api โดยไม่มี test จะสร้าง regression ที่มองว่าเป็น "security incident" ทั้งที่รากเป็น correctness — แยกขอบฟ้าเพื่อบังคับให้มี test plan ก่อน sweep
Track A — vtrc-api transaction & session correctness
A1 · CORR-VTRC-API-01 — transaction: t อยู่ผิด argument position
ที่: กระจายใน vtrc-api/api/src/lib/controllers/ (~20+ จุด) — vtrc-api/10
Sequelize คาดหวัง:
await Model.create({ ...fields }, { transaction: t })
await Model.update({ ...fields }, { where: {...}, transaction: t })แต่โค้ดจำนวนมากส่งเป็น arg ที่ 3 ซึ่งถูก discard:
await Model.create({ ...fields }, { where: {...} }, { transaction: t }) // arg 3 discardedImpact: ไม่มี atomicity จริง — partial write เมื่อ error กลางทาง; race ไม่ manifest ชัดเพราะ rollback ไม่เคยทำงาน
แผน 6 เดือน:
| Phase | งาน | ประมาณ |
|---|---|---|
| A1.1 | rg "transaction:\s*t" + จัดตาราง call site ตาม domain (leave / claim / auth) | 2–3 วัน |
| A1.2 | แก้ทีละ domain พร้อม integration test ที่ force error กลาง transaction | 2–4 สัปดาห์ |
| A1.3 | ห้าม merge PR ใหม่ที่ยังใช้ arg-3 pattern — lint / codeowner rule | 1 วัน |
ตรง vtrc-api/10 ROI #7 และคำเตือน "หนึ่ง change ต่อ PR"
A2 · CORR-VTRC-API-02 — getCurrentRoleUser signature mismatch
แก้ signature ให้ตรง caller — effort S แต่กระทบ RBAC จริง (คู่กับ auth pipeline ที่แดงใน health scorecard)
A3 · CORR-VTRC-API-03 — clouse.js limit cap ไม่ทำงาน
ไฟล์ชื่อ typo clouse (จาก clause) เป็น public contract ของ import path — แก้ logic ของ limit โดย ห้าม rename ไฟล์ใน PR เดียวกัน (ดู 19.4)
A4 · CORR-VTRC-API-04 — getCurrentProfileSession fallback ข้าม user
Medium severity แต่กระทบ session ที่ผูก user ผิดคน — วางในเดือน 4–5 พร้อม test login/refresh
A5 · Migration runner แทน syncModelToTable
vtrc-api/10 ROI #6: เพิ่ม goose / atlas / Sequelize migration runner — ลด schema drift ตอน boot
อย่าเปิด sync ใน production ระหว่าง migration นี้
Track B — PMS cron / notification integrity
จาก pms-api/06 ROI #2, #4, #5 และ regression checklist
B1 · CORR-PMS-01 — notification date gate ถูกปิด
คืน isSameDate gate ใน notification cron + await ที่หาย — effort ชั่วโมง แต่ impact = อาจส่งอีเมลทุกประเภททุกวัน
Regression:
- วันที่ไม่ตรง
settingGoalStart→ ต้อง ไม่ ส่งnotiGoalStart - วันตรง → ส่งได้ครั้งเดียวต่อวันต่อประเภท
B2 · CORR-PMS-02 — cron 1 นาที overlap
เพิ่ม in-process + distributed lock — effort 0.5–2 วัน (ROI #4)
Regression: จำลอง getEmployeeTriggerQeue ช้า > 60s → job ที่สองต้อง skip
B3 · OBS-PMS-01 — silent cron errors
Alert เมื่อ cron fail + metric last-success — ROI #5 (~1 วัน)
อย่าพึ่ง console.error อย่างเดียว (prod มี no-op pattern ในหลาย frontend/API)
B4 · QUAL-PMS-01 — docs ไม่ตรงโค้ด
อัปเดตหรือลบ PMS-Period-Notification-System.md — กัน ops ทำตามเอกสารผิด
สิ่งที่ทำได้ดีแล้วใน pms-api (อย่าทำพัง)
จาก pms-api/06 § สิ่งที่ทำได้ดีแล้ว:
*Historyaudit trail สม่ำเสมอ- Parameterized stored procedures (
sp_get_employeeSalary_orgUnit, …) — ไม่ใช่ string SQLi ThrottlerGuardglobalNODE_ENVdouble-guard บน migrate / notification manualValidationPipeเข้ม (forbidNonWhitelisted: true)- Period cycle แยกสถานะด้วยวันที่
PR correctness ต้องไม่ทำลายข้อเหล่านี้เพื่อ "cleanup"
Track C — benefit dual-schema & batch correctness
C1 · CORR-BENEFIT-01 / ROI #8 — reconcile benefit.wdHospitals vs vtrc.WDHospitals
benefit-api/06 Public contract ระบุ casing คนละแบบเป็นสัญญา — ห้าม unify ชื่อโดยไม่ migrate
งาน 6 เดือน:
- ตัดสินใจ source of truth (benefit schema vs vtrc schema)
- เขียน sync job หรือ API facade ที่อ่านจากเจ้าของข้อมูล
- ตรวจ diff รายวันจนกว่า drift = 0
- ค่อย deprecate ตารางซ้ำ
C2 · Distributed lock ให้ cron (ROI #7)
ถ้า deploy >1 replica โดยไม่มี lock — batch ซ้ำ = เบิก/โอนซ้ำได้
C3 · หลังปิด @Public() แล้ว — ตรวจ batch ที่เคยพึ่ง public path
ยืนยันว่า scheduler เรียกด้วย service credential ไม่ใช่เปิดเปล่า — คู่กับ 19.1 SEC-BENEFIT-04/05
Track D — SSO / workflow / cross-service auth correctness
D1 · CORR-SSO-01 — JWT sign พัง
Vol 12.5: sign() commented + JwtService not injected
ทางเลือก (ตัดสินใจในเดือน 3):
| ทาง | เมื่อไหร่ใช้ |
|---|---|
ซ่อมให้ sso-api ออก JWT จริง | ยังต้องการ SSO เป็น issuer |
| ลบ/bypass guard ที่พึ่ง sso-api ผิดสัญญา | ถ้า sso-api เป็น dead path |
ห้ามปล่อย "guard ที่ verify ไม่ได้แต่ยัง mount" — ทำให้ 2FA / login ดูผ่านทั้งที่ token ไร้ความหมาย
D2 · SEC-WORKFLOW-01 spillover
ถ้าไม่จบใน 90 วัน — เดือน 4–6 ต้องมี JWT verify จริง และเลิก derive role จาก sourceDB อย่างเดียว
D3 · CORR-WORKFLOW-01 — direct cross-DB (distributed monolith)
TypeORM ตรงไปยัง schema ของ service อื่น — เริ่ม inventory + ห้ามเพิ่ม connection ใหม่; แทนที่ด้วย API ค่อยเป็นค่อยไป (งานใหญ่ต่อใน 19.3)
Track E — Frontend correctness ที่กระทบข้อมูล
| ID | Repo | ปัญหา | งาน |
|---|---|---|---|
CORR-BO-02 / CORR-BONEW-01 | backoffice / backoffice-new | isRemember hardcode = 1 | แก้ทั้งคู่พร้อมกัน — fork ซ้ำ |
CORR-MOBILE-01 | vtrc-mobile | data integrity ฝั่ง client | ตาม scorecard mobile |
GraphQL cache-first stale | vtrc-web | stale UI หลัง mutation | เปลี่ยน fetchPolicy เฉพาะ operation ที่เขียนข้อมูล — vtrc-web/07 |
อย่าใช้โอกาสนี้ rename from/ หรือ TheamCss — 19.4
Track F — Observability ที่จำเป็นต่อ correctness
Correctness ที่ไม่มีสัญญาณ = แก้แล้วไม่รู้ว่าพัง
| งาน | Repo | Source |
|---|---|---|
/healthz + readiness | vtrc-api | ROI #2 — vtrc-api/10 |
| Structured logging (pino) + trace id | vtrc-api + Nest services | ROI #9 |
เลิกพึ่ง sync wlog อย่างเดียว | vtrc-api | OBS-VTRC-API-* |
| Cron last-success metric | pms-api, 2way-api (07:00 jobs) | pms ROI #5; 2way-api cron table |
2way-api มี cron announce/survey/complaint ทุกวัน 07:00 ที่พึ่ง raw SQL + LINE — หลัง parameterized ใน 90 วัน ต้อง monitor ว่าแจ้งเตือนถูกกลุ่ม (2way-api/04)
ลำดับเดือนแบบแนะนำ
Month 3 (ทับ 90-day ท้าย)
├── ปิด spillover: SEC-WORKFLOW-01 spike, SSO decision
├── CORR-PMS-01 / -02 / OBS-PMS-01
└── เริ่ม A1.1 inventory transaction sites
Month 4
├── A1.2 leave/claim transaction fixes + tests
├── CORR-VTRC-API-02 / -03
├── benefit dual-schema decision doc
└── healthz บน vtrc-api
Month 5
├── A1.2 ต่อ (auth/session controllers)
├── C1 sync job เฟสแรก
├── CORR-BO-02 + CORR-BONEW-01 พร้อมกัน
└── structured logging pilot
Month 6
├── A1.3 lint gate + A5 migration runner spike
├── D3 inventory cross-DB (ห้ามเพิ่ม)
├── regression pack เต็มตาม checklist ด้านล่าง
└── handoff ไป 12-month platform trackRegression pack (ขั้นต่ำก่อนปิดขอบฟ้า 6 เดือน)
vtrc-api
- Force error กลาง leave/create transaction → ไม่มี orphan row
- Role resolution หลังแก้
getCurrentRoleUserตรงกับเมนูที่เห็น - Profile session ไม่สลับ user หลัง refresh
pms-api
ใช้ pms-api/06 Regression checklist ข้อ 2–6 ครบ (ข้อ 1 ควรผ่านตั้งแต่ 90 วัน)
benefit-api
- สร้าง/อัปเดต wdHospitals ต้องมี JWT
- Diff
wdHospitalsvsWDHospitalsลดลงตามเป้าที่ตั้งใน decision doc - Approver list ไม่คืนทั้งตารางเมื่อส่ง
approverEmpCodeแปลก ๆ (หลัง SQLi fix)
2way-api
- Login ปกติผ่าน SSO ยังได้
- Backdoor ยังปิด
- Cron 07:00 ไม่ยิงซ้ำผิดกลุ่มหลัง SQL parameterize
สิ่งที่ยัง UNVERIFIED (อย่า claim ในสถานะ Done)
จาก pms-api/06 และ 2way-api/04:
| หัวข้อ | ทำไมยังไม่ยืนยัน |
|---|---|
| จำนวน replica จริงตอน deploy | ไม่มี k8s/helm ในหลาย repo |
| timezone container = Asia/Bangkok | cron 07:00 พึ่งสมมติฐานนี้ |
| WAF/gateway บังคับ JWT ด้านหน้า | อาจลด severity ปฏิบัติ แต่โค้ดยังเป็น bypass |
mDropdown แชร์ DB กับ benefit หรือไม่ | ชื่อตารางเหมือน คนละ schema |
| ความสัมพันธ์ workflow-api ↔ pms-ai-api | มี docs ใน workflow ยังไม่ verify |
บันทึก UNVERIFIED ไว้ใน ticket — อย่าใส่ใน "ปิดแล้ว" ของ Vol 19 โดยไม่มีหลักฐานใหม่