Skip to content

13.4 · Scorecard — API-design debt

รายการนี้เป็น debt ที่เกิดจากการสังเคราะห์ข้าม 18 repo ที่เปิด API (ไม่นับ debt ระดับ business-logic หรือ infra ที่อยู่ใน Volume 14/15) — ทุกรายการ tag API เพื่อให้ reconcile กับ debt-ID กลางของแพลตฟอร์มได้ใน Vol 17-20 ID ที่ปรากฏในนี้เป็น ID ใหม่ระดับ platform ไม่ทับกับ ID ระดับ repo เดี่ยวที่มีอยู่แล้วใน Vol 3-9 (เช่น SEC-BENEFIT-01)

Severity: Critical

SEC-API-01 · Auth pattern ไม่สม่ำเสมอ — มี 3 repo ที่ guard ประกาศไว้แต่ bypass ทั้งหมด

ที่ — centralize-api (@Public() 17/17 endpoint, centralize-api/index), vtrc-common (@Public() ทุก endpoint ที่ประกาศ, vtrc-common/02-core-pipeline), 2way-vtrc-api (master bypass token static string, 2way-vtrc-api/index)

ผลกระทบ — ทั้งสาม service เปิด production ให้เข้าถึงได้โดยไม่ต้อง login แม้จะมีโค้ด JwtAuthGuard ประกาศไว้เป็น global guard — จากมุมมองภายนอก (Swagger, network scan) จะดูเหมือน service มี auth เพราะมี guard class อยู่ในโค้ด แต่ในทางปฏิบัติทุก request ผ่านได้หมด ต่างจาก workflow-api ที่ไม่มี guard เลยแต่ก็ไม่แอบอ้างว่ามี — ความเสี่ยงของ centralize-api/vtrc-common/2way-vtrc-api สูงกว่าเพราะทำให้ผู้ตรวจสอบภายนอกเข้าใจผิดว่า service ถูกป้องกันอยู่

SEC-API-02 · Shared JWT secret ข้าม 4+ microservice ไม่มี key rotation

ที่ — benefit-api, recruitment-api, ai-recruitment-api, pms-api ใช้ SECRET_KEY ค่าเดียวกันทุกตัวอักษร (benefit-api/04-auth-integrations, recruitment-api/04-auth-integrations, ai-recruitment-api/04-auth-integrations, pms-api/04-auth-integrations) — recruitment-api ยืนยันเพิ่มว่า token จาก vtrc-api (issuer redcross.or.th:vtrc) ก็ verify ผ่านได้เช่นกัน

ผลกระทบ — เป็นรูปแบบ "shared-secret SSO" ที่ทำงานได้จริงแต่ไม่มี JWKS/central auth service, ไม่มี mechanism หมุน secret แบบไม่กระทบทุก service พร้อมกัน และ secret หลุดอยู่แล้วผ่าน .env ที่ commit เข้า git ทุก repo ที่กล่าวถึง (ดู SEC-BENEFIT-01, SEC-RECRUIT-01, SEC-AIRECRUIT-01, SEC-PMS-02 ในสกอร์การ์ดระดับ repo) — ถ้า secret รั่วออกไปนอกทีม จะกระทบทั้ง 4 service (และอาจรวม vtrc-api) พร้อมกันในทันที ไม่มีทางแยก blast radius

Severity: High

QUAL-API-01 · ไม่มี API versioning convention ที่สอดคล้องกันทั้งแพลตฟอร์ม

ที่ — ทุก NestJS service ใช้ global prefix รูปแบบ {BASE_PATH}api/v1 เหมือนกัน (ดู 13.2 REST APIs) แต่ ไม่มี repo ใดมี v2 หรือแผน migration version จริงv1 เป็นแค่ค่า convention ที่ copy จาก template ตั้งแต่ scaffold ไม่ใช่ versioning strategy ที่ตั้งใจ ในขณะที่ vtrc-api/cu-central-api (GraphQL) ไม่มี versioning ใดเลย (schema แก้ตรงได้ทุกเมื่อ ไม่มี deprecation flag)

ผลกระทบ — ถ้าต้อง breaking-change field ใดใน GraphQL schema ของ vtrc-api/cu-central-api ไม่มีกลไกที่ frontend เก่าจะ fallback ได้ ต้อง coordinate deploy frontend+backend พร้อมกันเสมอ — ความเสี่ยงสูงขึ้นเมื่อมี consumer ข้ามทีมมากขึ้น (เช่น 2way-api/2way-vtrc-api/meeting-vtrc-api ทั้งหมดเรียก cu-central-api schema เดียวกัน — ดู 13.3 Inter-service map)

QUAL-API-02 · Query/endpoint ชื่อเดียวกันแต่ URL/host ต่างกันโดยไม่มีหลักฐานว่าชี้ instance เดียวกัน

ที่ — fetchListEmployeeForTwoWay ถูกเรียกจาก 3 จุดด้วย URL คนละแบบ: 2way-api อ่านจาก env CENTRALIZE_API_URL, 2way-vtrc-api hardcode centralizeapi.redcross.or.th:25563, meeting-vtrc-api อ่านจาก env CDB_BASE_CONNECT — ดู 13.3.3

ผลกระทบ — ไม่มีหลักฐานยืนยันว่าทั้ง 3 จุดชี้ไป cu-central-api instance เดียวกันจริง 100% — ถ้ามีคนย้าย/scale cu-central-api แล้วอัปเดต URL แค่บางจุด จะเกิด data inconsistency แบบเงียบ (silent) ที่ยากจะ debug เพราะทุกจุดเรียก query ชื่อเดียวกัน

OBS-API-01 · Swagger เปิดใน production โดยไม่มี env flag ปิด — 14 repo

ที่ — benefit-api, recruitment-api (ดู 13.2.2) และ NestJS service ส่วนใหญ่อื่นในกลุ่ม ไม่มี guard/env check ที่ปิด Swagger UI เมื่อ NODE_ENV=prod — มีข้อยกเว้นเดียวคือ pms-api ที่ไม่มีหลักฐานปิด Swagger เช่นกันแต่ไม่ได้ตรวจยืนยันเจาะจงในรอบนี้

ผลกระทบ — ผู้โจมตีที่เข้าถึง network ภายในหรือแม้แต่ public internet (ถ้า nginx ไม่ block /docs path) เห็น full API surface รวม request/response schema ทุก field — ไม่ถึงระดับ Critical เพราะ Swagger ไม่ leak ข้อมูลจริงของผู้ใช้ (แค่ schema) แต่ช่วยผู้โจมตี reconnaissance ได้เร็วขึ้นมาก โดยเฉพาะ repo ที่ auth bypass อยู่แล้ว (centralize-api, vtrc-common) — Swagger กลายเป็นแผนที่ตรงเข้าเป้าทันที

Severity: Medium

QUAL-API-03 · REST endpoint ที่ไม่มีเอกสาร Swagger — 2 repo

ที่ — ai-recruitment-api (Express ล้วน ไม่มี swagger-jsdoc/@nestjs/swagger เลย), meeting-vtrc-api (Express + ts-node ไม่มี Swagger) — ดู 13.2.1

ผลกระทบ — วิศวกรที่เข้ามาใหม่ต้องอ่าน route file ตรงเพื่อรู้ endpoint ทั้งหมด ไม่มี single source of truth ที่ query ได้ — ทั้งสอง repo นี้ยังเป็น service ที่ active (ai-recruitment-api ใช้จริงจาก back-office, meeting-vtrc-api เป็น backend หลักของระบบประชุม) ไม่ใช่ dead code จึงมีผลกระทบจริงต่อการ maintain

QUAL-API-04 · CORS policy ไม่สอดคล้องกันแม้อยู่กลุ่มเดียวกัน

ที่ — recruitment-api เปิด origin: '*' เต็มที่ (recruitment-api/src/main.ts (branch: prod):41-45) ในขณะที่ ai-recruitment-api จำกัด origin เฉพาะ 3 โดเมนตรง ๆ (ai-recruitment-api/server.js (branch: prod):23-31) และ pms-api เขียนเป็น callback function ที่ block localhost เมื่อ NODE_ENV=prod เท่านั้น (pms-api/src/main.ts (branch: uat):45-66) — ดู 13.2.5

ผลกระทบ — ไม่มี CORS policy กลางที่บังคับใช้ทุก service ในกลุ่มเดียวกัน (Domain Microservices) ทำให้แต่ละทีมตัดสินใจเองว่าเปิดกว้างแค่ไหน — recruitment-api ที่เปิด * เต็มที่คือความเสี่ยงสูงสุดในกลุ่มนี้เพราะรับ credential-bearing request จากทุก origin ได้

QUAL-API-05 · Port allocation ไม่มี central registry

ที่ — 2way-api, 2way-line-service, chat-center-api ทั้งสามตั้ง PORT=8200 โดยไม่รู้ตัวว่าเลขซ้ำกัน (13.2.3) ในขณะที่ job-scheduler-api มี EXPOSE ใน Dockerfile ไม่ตรงกับ PORT จริงใน .env

ผลกระทบ — ยังไม่กระทบ production จริง (deploy คนละ container/host) แต่เพิ่มความเสี่ยงเวลา local dev หรือ docker-compose รวมหลาย service เข้า network เดียวกัน — สะท้อนว่าไม่มีทีม infra กลางที่ track port allocation ข้าม repo

Severity: Low

OBS-API-02 · Env var ค้าง (vestigial) ที่ประกาศไว้แต่ไม่มีจุดเรียกใช้จริง — พบซ้ำในหลาย repo

ที่ — job-scheduler-api (VTRC_SERVER, VTRC_COMMON_SERVER, job-scheduler-api/03-persistence-integrations), recruitment-api (VTRC_SERVER, commonServer, recruitment-api/04-auth-integrations), chat-center-api (CENTRALIZE_SERVER, chat-center-api/03-persistence-integrations), ai-recruitment-api (HCTI_USER_ID/HCTI_API_KEY, ai-recruitment-api/04-auth-integrations), 2way-line-service (CENTRALIZE_SERVER, 2way-line-service/index)

ผลกระทบ — ไม่กระทบ runtime โดยตรง แต่ทำให้เอกสาร/env file ทุกตัวมีสัญญาณรบกวน (noise) — วิศวกรใหม่อ่าน .env แล้วเข้าใจผิดว่า service เชื่อมต่อไปที่นั่นจริง ต้อง grep source เพื่อยืนยันทุกครั้ง เกิดจาก pattern การ copy .env ต้นแบบข้าม repo โดยไม่ตัดค่าที่ไม่ใช้ทิ้ง

สรุป — คะแนนรวม

Severityจำนวน
Critical2
High3
Medium2
Low1

Modernization — ลำดับ ROI

  1. ปิด auth bypass 3 จุด (SEC-API-01)centralize-api/vtrc-common/2way-vtrc-api ควรตัดสินใจร่วมกับทีม product ก่อนว่า endpoint กลุ่มไหนตั้งใจเปิด public จริง แล้วลบ @Public()/bypass token ที่เหลือ
  2. แทน shared JWT secret ด้วย JWKS/central auth service (SEC-API-02) — งานใหญ่ที่กระทบ 4+ repo พร้อมกัน ต้อง phased rollout (dual-verify ช่วง transition)
  3. ปิด Swagger ใน production ด้วย env flag (OBS-API-01) — เป็น quick win ที่ทำได้ใน 1 บรรทัดต่อ repo (if (process.env.NODE_ENV !== 'production') { SwaggerModule.setup(...) })
  4. ตั้ง CORS policy กลางเป็น allowlist (QUAL-API-04) — เริ่มจาก recruitment-api ที่เปิด * ก่อน เพราะความเสี่ยงสูงสุด
  5. เขียน Swagger ให้ ai-recruitment-api/meeting-vtrc-api (QUAL-API-03) — ลด onboarding cost
  6. ตั้ง central port registry + ลบ env var ค้าง (QUAL-API-05, OBS-API-02) — งาน hygiene ที่ทำได้แบบ incremental ไม่กระทบ production

ไป กลับสู่ Volume 13 index หรือ Volume 14 · Business Logic