Skip to content

ai-recruitment-api Deep Dive

ai-recruitment-api (branch: prod — default branch main เป็น branch เปล่า; tracked files บน prod ≈ 390) เป็น Express service แยกต่างหากจาก recruitment-api ทั้ง repo และทั้ง stack — ทำหน้าที่เป็น AI content / graphic generation helper สำหรับกระบวนการสรรหาบุคลากร ไม่ใช่ CRUD API ของข้อมูลผู้สมัคร

ชื่อใน package.json ตรงกับชื่อ repo (ai-recruitment-api/package.json (branch: prod):2) — entry script คือ server.js (package.json:5-8) ไม่ใช่ NestJS main.ts / app.module.ts (ไฟล์เหล่านั้นไม่มีใน repo นี้)

หน้าที่หลัก (จาก endpoint จริง)

  1. สร้างเนื้อหาประกาศงานด้วย AI — generate / สรุป job description, qualification และชุดคำถามสัมภาษณ์ ผ่าน OpenAI Chat Completions (gpt-4o หรือ gpt-3.5-turbo ตาม controller)
  2. สร้างภาพกราฟิกประกาศรับสมัคร — เลือกพื้นหลังสำเร็จรูป, สร้าง/เลือกภาพตัวละคร (DALL-E / gpt-image-1 หรือคลัง local), ลบพื้นหลัง (remove.bg), ผสม HTML + Puppeteer เป็นภาพประกาศสำหรับโซเชียล

หลักฐาน route ทั้งหมด: ai-recruitment-api/routes/index.js (branch: prod):53-144

Stack

ส่วนค่าหลักฐาน
FrameworkExpress 4 (express ^4.18.2) — ไม่ใช่ NestJSai-recruitment-api/package.json (branch: prod):15
LanguageJavaScript ล้วน (ไม่มี TypeScript / tsconfig.json)โครงสร้างไฟล์ .js ทั้งหมด
AI textopenai SDK ^4.104.0 + raw axioshttps://api.openai.com/v1/chat/completionspackage.json:20, config/openai.js:4-28, summarize/interview controllers
AI imageOpenAI Images API ผ่าน openai.images.generate() (gpt-image-1 / dall-e-3)config/dalle.js (branch: prod):41-52
Background removalremove.bg REST https://api.remove.bg/v1.0/removebgservices/removeBgService.js:66-78, controllers/removeBgUploadController.js:16,42
HTML → imagePuppeteer ^22.6.5 + system Chromium ใน Dockerpackage.json:23, combineJobPostingController.js:377-386, Dockerfile:14,20-21
Image libs (declared)sharp ^0.33.4, canvas ^3.1.2 — ไม่พบ require() ในโค้ด .js ของ repopackage.json:12,22 (ดู scorecard)
QR codeapi.qrserver.com (ไม่มี env)combineJobPostingController.js:65-75
DatabaseMSSQL ตรงผ่าน mssql ^9.0.1 — ไม่มี ORMpackage.json:18, config/db.js:1-19
AuthCustom verifyJWT ด้วย jsonwebtoken — ไม่มี Passport / ไม่มี role guardmiddleware/verifyJWT.js:7-40, server.js:37
Uploadmulter memory storageroutes/index.js:15, 99-117
Package managernpm (package-lock.json)root lockfile
Scriptsstartnode server.js, devnodemon server.jspackage.json:6-8

Entry point และพอร์ต

  • Entry: ai-recruitment-api/server.js (branch: prod):1-72
  • Mount path: /ai-recruitment-api/api (server.js:18-19,60)
  • พอร์ตจาก env key PORT — ค่าใน .env บรรทัด 6 คือ 9430; fallback ในโค้ดเป็น 3000 (server.js:67)
  • Dockerfile EXPOSE 9430 (Dockerfile:33) สอดคล้องกับค่า PORT ใน .env
  • ไม่มี Swagger / OpenAPI ใน repo

CORS whitelist (สำคัญ)

javascript
origin: [
  "https://uat-vtrcbackoffice.redcross.or.th",
  "https://vtrcbackoffice.redcross.or.th",
  "http://localhost:3000",
],
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "authorization", "apiKey"],

แหล่ง: server.js:23-31

นี่คือหลักฐานว่า consumer ที่ตั้งใจไว้คือ vtrc-backoffice (UAT/prod) และ local :3000 — ไม่ใช่ candidate-facing recruitment-web

หมายเหตุ: route upload ตั้ง Access-Control-Allow-Origin เป็น req.headers.origin || '*' ซ้ำอีกชั้น (routes/index.js:89-106) — กว้างกว่า CORS global ของ server.js

Auth แบบ one-liner

app.use(verifyJWT) ก่อน mount router (server.js:37,60) — ทุก HTTP request รวม static path ที่ผ่าน middleware stack นี้ต้องมี Bearer JWT (ไม่มี @Public() / allowlist ใน Express นี้) ดูรายละเอียดที่ 04 Auth + integrations

Deploy artifact

Dockerfile (branch: prod):

รายการค่าบรรทัด
Basenode:18-alpine1
Native build depspython3, make, g++, cairo/pango/giflib/jpeg/libpng4-12
Browserchromium + fonts + PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser14-21
Installnpm install --legacy-peer-deps28
StartCMD ["npm", "start"]node server.js35 + package.json:7

Node 18 ต่างจาก benefit-api / recruitment-api ที่ใช้ Node 20 — ดู LEG-AIRECRUIT-01 ใน 06 Scorecard

Database coupling

เชื่อม MSSQL database ชื่อจาก DB_DATABASE (.env:4) — ค่า hash ของชื่อ database ตรงกับ DB_AI_NAME ของ recruitment-api (ยืนยันด้วย SHA-256 prefix เดียวกันบนเครื่องเอกสารนี้; ค่า plaintext ไม่ใส่ในคู่มือ)

DB_SERVER ของ ai-recruitment-api ตรง hash กับ DB_AI_HOST ของ recruitment-api เช่นกัน

สรุป: shared-database coupling กับ recruitment-api connection ชื่อ ai — ดู 03 Persistence

JWT secret coupling

JWT_SECRET (.env:11) ที่ verifyJWT อ่าน (middleware/verifyJWT.js:4) มี SHA-256 hash เหมือน SECRET_KEY ของทั้ง benefit-api และ recruitment-api — shared signing key ข้ามอย่างน้อย 3 domain service (ดู 04)

สิ่งที่ควรรู้ก่อนอ่านบทถัดไป

  • .env อยู่ใน .gitignore:51 แต่ ยังถูก track ใน git (git ls-files .env คืน blob) — มี MSSQL password, OpenAI key, remove.bg key, HCTI keys, JWT secret เป็น plaintext ใน history/working tree ของ branch prod
  • storage-uploads/ มีภาพสำเร็จรูปหลายร้อยไฟล์ commit ใน repo (Background 29 ไฟล์ + คลังตัวละคร)
  • routes/index.js มี try/catch + diagnostic guard สำหรับ module2_2_controller เพราะเคยมี require-time crash (routes/index.js:23-78)
  • มี dead / orphan files: module2_1_get_background_v2.js, module_2_3_combine_image.js, routes/get-post-upload_image.js — ไม่ถูก require จาก server.js
  • Env HCTI_*, DALLE_ENDPOINT, GEN_BASE_URL ปรากฏใน .env แต่ ไม่พบจุดเรียกใช้ใน .js ระหว่างการสำรวจนี้

สารบัญ

บทหัวข้อ
01Repository map — โฟลเดอร์, boot, endpoint table, orphan files
02Core pipeline — text AI + image AI + combine end-to-end
03Persistence — MSSQL tables ที่ query จริง + file storage
04Auth (no-role) + OpenAI / remove.bg / QR / Puppeteer map
05Cron jobs — ไม่มี scheduler
06Scorecard + debt register

ขอบเขตการยืนยันของเล่มนี้

ยืนยันจากซอร์สบน branch prod แล้ว

  • Express boot, CORS whitelist, global JWT, 9 POST routes ใน routes/index.js
  • OpenAI call sites ทั้งหมดที่ grep พบ (wrapper + inline axios)
  • remove.bg call sites (service + upload controller)
  • ตาราง MSSQL ที่ interview / job-description controllers อ้าง
  • ไม่มี NestJS modules / @Public / role guard

ไม่ยืนยันในเอกสารนี้

  • ว่า front-end vtrc-backoffice เรียก path ใดเป็นลำดับตายตัว (อนุมานจากชื่อ endpoint + I/O)
  • sync mechanism ระหว่าง recruitment.dbo.jobReqPosition กับ recruitment_ai.dbo.jobReqPosition
  • ว่า HCTI เคยถูกใช้ใน commit เก่าหรือไม่ (ปัจจุบันไม่พบ caller)