Skip to content

15.3 Performance debt

บทนี้รวบรวม debt ด้าน performance — ปัญหาที่ทำให้ระบบช้าและขยายตัวได้ยาก

หมายเหตุ: PERF-7 (phpMyAdmin เปิดสาธารณะ) อยู่ในบท 14.1 เพราะเป็น security Critical

รายการทั้งหมด

PERF-1 · execSync ใน request handler

ข้อมูลรายละเอียด
Evidencevtrc-api/api/src/routes.js:73,75,115,117,210,260,312 — ใช้ execSync สำหรับ qpdf
ปัญหาexecSync บล็อก event loop ของ Node — การสร้าง PDF หนึ่งไฟล์ใช้เวลา 2-5 วินาที ในช่วงนั้น request อื่น ๆ บน replica เดียวกันต้องรอ กับ 4 replica ความสามารถสูงสุด = 4 PDF พร้อมกัน
Impactตอนออกเงินเดือน (มีคนดาวน์โหลด payslip พร้อมกัน) ระบบช้ามาก ผู้ใช้รายอื่น (ที่ไม่ได้ดาวน์โหลด PDF) ก็ช้าด้วย
Mitigation ระยะสั้นเปลี่ยนเป็น async worker queue — request สร้าง job แล้ว return ทันที ผู้ใช้รอ download link (เช่น 30 วินาที)
แนวทางระยะยาวย้าย PDF generation ไป service แยกที่ใช้ chromedp (Go) หรือ worker ที่ไม่ใช้ event loop

PERF-2 · Apollo fetchPolicy 'no-cache' ทุก query

ข้อมูลรายละเอียด
Evidencevtrc-web/src/config/apollo.js:173-181fetchPolicy: 'no-cache' กำหนดทั้ง watch + query
ปัญหาnormalized cache ของ Apollo ถูกปิด — ทุกการนำทางใหม่เรียก network ทั้งหมด เป็นแหล่งเดียวที่ทำให้ frontend ช้าที่สุด
ImpactUX ช้า โหลดซ้ำข้อมูลที่เปลี่ยนน้อย (เช่น profile, organization list) กระทบโดยเฉพาะผู้ใช้มือถือบนเครือข่ายช้า
Mitigation ระยะสั้นเปลี่ยน default เป็น cache-and-network หรือ stale-while-revalidate สำหรับ query ที่ไม่ sensitive
แนวทางระยะยาวใช้ @nuxtjs/apollo ที่มี cache strategy ที่ดีกว่า หรือ useFetch ของ Nuxt 3

PERF-3 · Session lookup ด้วย JSON LIKE

ข้อมูลรายละเอียด
Evidencevtrc-api/api/src/lib/repositories/session/session.js:31-33userSession: { [Op.like]: \%${jwtid}%` }`
ปัญหาทุก authenticated request ต้องค้นหา session โดยการ LIKE บน JSON blob ในคอลัมน์ userSession — เป็น full table scan ไม่มี index
Impactเมื่อตาราง Session ใหญ่ขึ้น (ผู้ใช้ login หลายครั้ง) การ authenticate ช้าขึ้นเรื่อย ๆ
Mitigation ระยะสั้นเพิ่มคอลัมน์ jwtId (indexed) แล้ว lookup ด้วยคอลัมน์นี้แทน
แนวทางระยะยาวเก็บ sessionId ใน JWT แล้ว lookup ด้วย primary key

PERF-4 · N+1 RBAC query ทุก field

ข้อมูลรายละเอียด
Evidencevtrc-api/api/src/directives/auth.js:43-44 + session.js:127-153, 50-69
ปัญหาdirective @auth ทำ 3+ database round-trips ต่อการเรียกแต่ละ field ที่ protected — getCurrentRoleUser query Role แล้ว User แล้ว filter ใน JS, checkMenuAuth query User แล้ว RoleAccess แยกกัน
ImpactGraphQL query ที่มี field ที่ protected หลาย field จะทำ database query จำนวนมากผิดปกติ
Mitigation ระยะสั้นcache permission set ของ user ใน Redis (TTL = session TTL)
แนวทางระยะยาวโหลด permission set ครั้งเดียวต่อ request ใส่ใน context

PERF-5 · Approval-chain fetch ข้าม service แบบ synchronous

ข้อมูลรายละเอียด
Evidencevtrc-api/api/src/lib/controllers/hrmi/hrmi.js:65,122 — เรียก hrmiGetApproverCD
ปัญหาทุกการสร้าง leave/withdraw ดึง approval chain จาก cu-central-api แบบ synchronous — ถ้า cu-central-api ช้า การสร้างทั้งหมด hang
Impactประสบการณ์ผู้ใช้แย่ตอน cu-central-api มีปัญหา — แม้จะไม่ได้ใช้ข้อมูล approval chain ในทันที
Mitigation ระยะสั้นเพิ่ม timeout + fallback (ใช้ cache หรือ default chain)
แนวทางระยะยาวpre-cache approval ladder ต่อ org, invalidate เมื่อ MasterApprover เปลี่ยน

PERF-6 · God controller 3,179 บรรทัด

ข้อมูลรายละเอียด
Evidencevtrc-api/api/src/lib/controllers/withdraw/hospital.js — 3,179 LOC
ปัญหาcontroller เดียวผสมทุกอย่าง — creation, approval, bank export, reporting, status transition, attachment การแก้ของเล็ก ๆ มีความเสี่ยงกระทบส่วนอื่น
Impactการ maintainability ต่ำ การเพิ่มเติม feature ใหม่ทำได้ยาก การ review ใช้เวลานาน
Mitigation ระยะสั้นแยก method ที่เกี่ยวข้องกันเป็น module ย่อย (ไม่เปลี่ยน behavior)
แนวทางระยะยาวแยกเป็น domain aggregate — Claim (lifecycle), ApproverChain, BankExportBatch, Report แต่ละตัว < 400 LOC

PERF-8 · network_mode: host ใน docker-compose

ข้อมูลรายละเอียด
Evidencevtrc-api/docker-compose.yml:14-34
ปัญหาnginx container ใช้ network_mode: host — ไม่มี port isolation, container เห็น network ของ host ทั้งหมด
Impactความเสี่ยงด้าน security (container ที่ถูก compromise สามารถเข้าถึง service อื่นบน host) และความยากในการจำกัด network access
Mitigation ระยะสั้นเปลี่ยนเป็น bridge network + explicit port mapping
แนวทางระยะยาวทุก container ใช้ bridge network และกำหนด network policy

สรุป

IDรายการSeverityEffort ระยะสั้น
PERF-1execSync บล็อก event loopCritical3-5 วัน (worker queue)
PERF-2no-cache ทุก queryHigh1-2 วัน
PERF-3Session LIKE JSONHigh1-2 วัน (เพิ่มคอลัมน์)
PERF-4N+1 RBAC queryHigh2-3 วัน (Redis cache)
PERF-5sync approval fetchHigh2-3 วัน (timeout + cache)
PERF-6God controller 3,179 LOCHigh1-2 สัปดาห์ (split)
PERF-8network_mode: hostHigh1 วัน

บทถัดไปจะไปยัง debt ด้านความถูกต้องของข้อมูล ซึ่งเป็นหมวดที่กระทบความน่าเชื่อถือของระบบโดยตรง