Skip to content

13.2 · REST APIs

16 repository เปิด REST เป็น API หลัก (ไม่รวม vtrc-api/cu-central-api ที่มี REST เสริมคู่กับ GraphQL — ดู 13.1) ส่วนใหญ่เป็น NestJS 9 ที่ใช้ template เดียวกัน (global prefix {BASE_PATH}api/v1, JwtAuthGuard global guard + @Public() override, Swagger ที่ {BASE_PATH}docs) — เป็น pattern ที่ copy ข้าม repo จน "เหมือนกันไบต์ต่อไบต์" ในหลายจุด (ดู Volume 6 index)

13.2.1 · ตารางสรุปทุก REST API

RepoFrameworkBase pathPortAuth patternSwagger
vtrc-apiExpress (REST เสริม GraphQL)/ (routes.js, ~68 KB)8081apiKey + JWT (บางส่วนไม่มี)ไม่มี
cu-central-apiExpress (REST เสริม GraphQL)/ (endpoint auth)8080 (default code)apiKey + LDAP/Basic authไม่มี
centralize-apiNestJS 9/api/*3000 defaultJWT guard ประกาศไว้แต่ @Public() ทุก endpoint (17/17)มี (/docs)
2way-apiNestJS 92way-api/api/v18200 (.env.example, ไม่ใช่ 3000 default ใน main.ts)JWT global guard + @Public()มี ({BASE_PATH}docs)
2way-batchNestJS 92way-batch/api/v1UNVERIFIED (ไม่มี .env.example, Dockerfile เขียน EXPOSE 3000)JWT global guardมี
2way-line-serviceNestJS 92way-line-service/api/v18200 (.env.example)JWT global guardมี
2way-vtrc-apiExpress + ts-node/2way/...8001 hardcode (ไม่อ่านจาก env)Passport JWT + master bypass token static string "testnaja" (SEC-2WAYVTRC-01)มี (swagger-jsdoc, title ยังเป็น "JSONPlaceholder" ตัวอย่าง)
benefit-apiNestJS 9benefit-api/api/v19320JWT global guard (Passport JWT)มี, เปิดใน production ไม่มี env flag ปิด
recruitment-apiNestJS 9recruitment-api/api/v19330JWT global guard + self-managed JWT (AuthDataService)มี, CORS origin: '*'
ai-recruitment-apiExpress (ไม่ใช่ NestJS)/ai-recruitment-api/api9430custom verifyJWT middleware (jsonwebtoken ตรง ไม่มี Passport)ไม่มี
pms-apiNestJS 9pms-api/api/v19331JWT global guard + @Public() (GET /budget/getEmployeeSalary เป็น public — SEC-PMS-01) + ThrottlerGuard (100 req/60s — เฉพาะ repo นี้)มี
chat-center-apiNestJS 9chat-center-api/api/v18200 (ชนกับ 2way-api/2way-line-service เลขพอร์ตเดียวกันทั้ง 3 repo — คนละ container/host จึงไม่ conflict จริง แต่บ่งชี้ว่าไม่มี port-allocation convention กลาง)JWT global guardมี
job-scheduler-apiNestJS 9ประกาศ benefit-api/ (ผิด — QUAL-JOBSCHED-02)9900 (.env, Dockerfile เขียน EXPOSE 3000 ไม่ตรง)JWT global guard (แต่ AppController ว่างเปล่า — ไม่มี business endpoint)มี
workflow-apiNestJS 10workflow-api/api/v18000 default (.env.example)ไม่มี global guard — อ่าน JWT payload ไม่ verify signatureมี (SWAGGER_PATH, comment ในโค้ดยอมรับตรงว่า "signature is not verified in this service")
sso-apiNestJS 10{BASE_PATH}{API_VERSION_PATH}UNVERIFIED (ไม่มี .env/.env.example/Dockerfile ใน repo เลย)JWT global guard (Passport JWT ฝั่งรับ request)มี
vtrc-commonNestJS 9vtrc-common/api/v19310JWT guard ประกาศไว้แต่ ทุก endpoint ที่มีเป็น @Public() (SEC-COMMON-01)มี
meeting-vtrc-apiExpress + ts-node/meeting/...8000 hardcode (app.ts)Passport JWT bridge ผ่าน vtrc-apiไม่มี
vtrc-ocr-apiExpress/api3000 default, UNVERIFIED ค่าจริง (ไม่มี .env.example)ไม่มี auth เลยมี (swagger-jsdoc, /docs + /docs.json)

13.2.2 · Swagger/OpenAPI — มีเยอะแต่ไม่มี consumer ที่ยืนยันได้

14 จาก 16 repo REST เปิด Swagger/OpenAPI UI จริง — ทุก NestJS service ที่ใช้ @nestjs/swagger default (10 ตัว: centralize-api, 2way-api, 2way-batch, 2way-line-service, benefit-api, recruitment-api, pms-api, chat-center-api, job-scheduler-api, workflow-api, sso-api, vtrc-common — จริงๆนับได้ 12) รวมกับ 2way-vtrc-api และ vtrc-ocr-api ที่ใช้ swagger-jsdoc/swagger-ui-express แทน มีเพียง ai-recruitment-api และ meeting-vtrc-api ที่ไม่มี Swagger เลยในกลุ่ม REST ทั้งหมด แต่ ไม่พบหลักฐานว่ามีทีมใดใช้ Swagger spec สำหรับ codegen client หรือ contract testing — เป็น documentation ที่มีอยู่เฉยๆ ไม่ผูกกับ pipeline อัตโนมัติใดในทุก repo ที่ตรวจสอบ

Swagger เปิดใน production โดยไม่มี env flag ปิดใน benefit-api/recruitment-api (ทั้งสองไม่มี guard ปิด Swagger ตอน NODE_ENV=prod) — ดู 13.4 Scorecard

13.2.3 · Base path collision และ port ที่ไม่ตรง env

พบ 2 pattern ที่ก่อความสับสนซ้ำในหลาย repo:

  1. EXPOSE ใน Dockerfile ไม่ตรงกับ PORT จริงใน .envjob-scheduler-api (EXPOSE 3000 ใน Dockerfile แต่ .env ตั้ง PORT=9900 จริง, docker-compose.yml map 9900:9900 ถูกต้อง — EXPOSE เป็น documentation เฉยๆ ไม่ผูกกับ listen port จริง) — benefit-api/recruitment-api/pms-api ใช้ ConfigService.get('port') fallback 3000 ใน main.ts แต่ค่าจริงมาจาก .env เสมอ (9320/9330/9331 ตามลำดับ ตรงกับ Dockerfile EXPOSE ของทั้งสามตัว) — ต้องเปิด .env/Dockerfile คู่กันเสมอ ห้ามเชื่อ default ใน main.ts อย่างเดียว
  2. BASE_PATH copy ผิดจาก repo อื่นjob-scheduler-api ประกาศ BASE_PATH=benefit-api/ (ค้างจากการ copy .env ต้นแบบของ benefit-api) ทำให้ URL ที่ nginx ต้อง route จริง ({SERVER_URL}{BASE_PATH}api/v1) ไม่ตรงกับชื่อ service — ดู QUAL-JOBSCHED-02 ใน job-scheduler-api/04-scorecard
  3. เลขพอร์ต 8200 ถูกใช้ซ้ำ 3 ครั้งในแพลตฟอร์ม2way-api, 2way-line-service, chat-center-api ทั้งสามตัวตั้ง PORT=8200 ใน .env/.env.example ของตัวเอง เป็นไปได้เพราะแต่ละตัว deploy เป็น container/host แยกกันจึงไม่ชนกันจริงในการรัน แต่สะท้อนว่าไม่มี central port-allocation registry ข้ามทีม — ความเสี่ยงคือถ้าวันหนึ่งมีคนพยายามรันสอง service นี้บน host เดียวกัน (เช่น ตอน local dev หรือ docker-compose รวม) จะชนกันทันที

13.2.4 · Auth pattern แบ่งเป็น 5 กลุ่ม

กลุ่มRepoลักษณะ
Legacy apiKey + JWTvtrc-api, cu-central-apiapiKey header ระบุ APP_TYPE, JWT decode (ไม่ verify ที่ layer แรก, verify ที่ @auth directive)
LDAP + JWTcu-central-apiผสมกับกลุ่มบน — LDAP/AD bind สำหรับ authentication จริง
JWT global guard + @Public() (NestJS มาตรฐาน)2way-api, 2way-batch, 2way-line-service, benefit-api, recruitment-api, pms-api, chat-center-api, job-scheduler-api, vtrc-common, sso-apipattern ที่ copy ข้าม repo มากที่สุดในแพลตฟอร์ม — @Public() decorator override guard ต่อ route
JWT ไม่ verify signatureworkflow-apiอ่าน payload เพื่อดึง role/username เท่านั้น ไม่มี guard บังคับระดับ global — ข้อยกเว้นเดียวในกลุ่ม NestJS ทั้งหมด
ไม่มี auth เลย / bypass ทั้งระบบvtrc-ocr-api (ไม่มี auth), centralize-api (guard ประกาศแต่ @Public() 17/17), vtrc-common (guard ประกาศแต่ @Public() ทุก endpoint), 2way-vtrc-api (มี master bypass token แบบ static string)ความเสี่ยงสูงสุดของกลุ่มนี้

ความไม่สม่ำเสมอนี้คือหัวใจของ QUAL-API-01 ใน 13.4 Scorecard

13.2.5 · Shared JWT secret ข้าม service (ยืนยันจาก 4+ repo)

SECRET_KEY ที่ benefit-api, recruitment-api, ai-recruitment-api, pms-api ใช้ verify JWT เป็นค่าเดียวกันทุกตัวอักษร — token ที่ service ใดออก (รวม vtrc-api ตาม issuer redcross.or.th:vtrc ที่ recruitment-api เช็ค) ใช้ยืนยันตัวตนข้าม service ในกลุ่มนี้ได้ทันทีโดยไม่ผ่าน central auth หรือ JWKS ใด ๆ — เป็นรูปแบบ "shared-secret SSO" ที่ทำงานได้จริงแต่ไม่มี key rotation mechanism และ secret หลุดอยู่แล้วผ่าน .env ที่ commit เข้า git ทุก repo ที่กล่าวถึง

ดูหลักฐานต่อ repo ที่ benefit-api/04-auth-integrations, recruitment-api/04-auth-integrations, ai-recruitment-api/04-auth-integrations, pms-api/04-auth-integrations