Skip to content

3.2.1 · Repository map

บทนี้เจาะโครงสร้างของ cu-central-api/main-api/src/ เพื่อให้อ่านและค้นหาโค้ดได้ง่ายขึ้น พร้อมทั้งระบุ typos และไฟล์ที่ไม่ได้ใช้แล้ว (dead files) ที่ต้องระมัดระวังเมื่อแก้ไขโค้ด


โครงสร้าง repo ระดับบน

cu-central-api/                          (independent git repo บน Bitbucket)
├── .gitignore
├── Dockerfile-nginx                     nginx proxy image
├── Dockerfile-redis                     redis image
├── docker-compose-dev.yml               dev compose
├── docker-compose.yml                   3x cu-cen-api replicas + redis + nginx
├── ecosystem.config.js                  PM2 config (legacy, ไม่ได้ใช้ใน prod)
├── package-lock.json
├── pm2Cmd.txt
├── database/                            legacy DB scripts
├── ldap/                                LDAP-related resources
├── nginx/                               nginx conf.d
├── redis-db/                            redis.conf + data volume
├── web-site/                            static nginx html
└── main-api/                            ★ service หลัก (Volume นี้ focus ที่นี่)
    ├── .dockerignore
    ├── .env.develop-test                UAT secrets (committed — ดู Volume 12 Security)
    ├── .env.example                     sanitized template
    ├── Dockerfile                       FROM node:12.18.3
    ├── index.js                         1-line entrypoint: import './src'
    ├── package.json
    ├── test/validator.js                test file เดียว (mocha)
    └── src/                             ★ application code

repo อยู่บน Bitbucket (bitbucket.org/i3dev/cu-central-api) ภายใต้ user i3wp ตามที่ระบุใน cu-central-api/main-api/package.json:13 — ต่างจาก repo อื่นที่อยู่บน GitHub ส่วนใหญ่


main-api/src/ top-level files

FileLOCหน้าที่บทที่เจาะลึก
index.js118Apollo + Express bootstrap3.2.2
config.js110env var destructuring (50+ vars)3.2.2
connector.js1966 Sequelize instances3.2.2
cron.js32node-schedule jobs (3 jobs, gated ด้วย APP_NO)3.2.2
routes.js64REST routes (signin/signout/token/conicle)3.2.3
testScript.js167dev-only scratch runner (gated ด้วย !IS_PRODUCTION)
directives/auth.js79@auth schema directive3.2.4
directives/index.js6directive registry3.2.4

main-api/src/ subdirectories

Directoryไฟล์หมายเหตุ
typeDefs/32 .js (29 root + 3 ใน hr/) + index.jshand-authored GraphQL SDL — รายละเอียดใน 3.2.6
resolvers/28 .js (25 root + 3 hr/ + 1 bank/) + index.js1,826 LOC total
models/6 subdirs + index.jsrecursive loader — รายละเอียดใน 3.2.2
lib/28 root .js + 31 subdirsbulk ของ business logic
directives/2 filesมีแค่ @auth
email-templates/requestResetPassword/nodemailer pug templates

lib/ subdirectories (31 โฟลเดอร์ ตาม bounded context คร่าว ๆ)

lib/
├── auth/                    LDAP + AD + JWT + apiKey + session
├── bank/                    book bank lookup
├── cache/                   Redis cache helper
├── childTuition/            child tuition allowance
├── class/                   employee class
├── conicle/                 Conicle SFTP integration
├── dataConverter/           data shape converter
├── finance/                 employee finance (★ typo: finanace.js)
├── his/                     HIS heal-card API
├── hr/                      HR mutations (taxes/address/phone)
├── hrPerProbation/          probation check
├── hrmi/                    HRMI HTTP API + leave/medical
├── mailer/                  nodemailer wrapper
├── masterData/              master data CRUD
├── notification/            SMS gateway
├── organization/            org unit lookup
├── otp/                     OTP generation + verify
├── personalProfile/         employee personal profile
├── phoneNumber/             phone change log
├── referenceData/           reference data
├── salaryCert/              salary certificate
├── session/                 Redis session store
├── sso/                     SSO integration (★ committed certs)
├── statLog/                 stat logging
├── studyLeaveRequest/       study leave
├── transferFile/            file transfer helper
├── twoWay/                  2-way employee sync
├── userIdGenerator/         userId mapping generator
├── userIdsMapping/          userIdsMapping table ops
├── userVerification/        user verification flow
└── verifyCode/              verify code flow

Typos ใน production code

Codebase มี typos หลายจุดที่ "ship แล้วเปลี่ยนไม่ได้" เพราะอยู่ใน GraphQL schema สาธารณะ

finanace (finance สะกดผิด) — 3 จุดที่ consistent กัน

ไฟล์รายละเอียด
lib/finance/finanace.jsชื่อไฟล์เอง
resolvers/finanace.jsresolver file (26 LOC)
typeDefs/finance.js:5,11type EmployeeFinanace + query employeeFinanceType

อ่านเจอครั้งแรกจะนึกว่ามี 2 files (finance + finanace) แต่แท้จริงแล้ว typeDef ใช้ชื่อโฟลเดอร์ที่สะกดถูก (finance/) แต่ชื่อไฟล์ข้างในสะกดผิด

typos อื่น ๆ ใน GraphQL schema

Type / Queryควรเป็นไฟล์
EmployeeFinanaceEmployeeFinancetypeDefs/finance.js:5
OrgazationAddressOrganizationAddresstypeDefs/organization.js
SubscribtionSubscriptiontypeDefs/root.js:17

GraphQL schema เป็น contract สาธารณะ — เปลี่ยนชื่อไม่ได้ถ้าไม่ break client ทั้งหมด (web + mobile + backoffice ที่ query ผ่าน vtrc-api)


Dead files และ legacy artifacts

typeDefs/payrollSlip_removed.js (112 LOC)

// ไฟล์นี้ไม่ถูก import โดย typeDefs/index.js — dead SDL
  • เป็นเวอร์ชันเก่าของ payrollSlip.js ที่ใช้ empCode เป็น parameter แทน profileKey (ที่ใช้ในปัจจุบัน)
  • ไม่ถูก import โดย typeDefs/index.js จึงไม่ปรากฏใน live schema
  • แต่ยังอยู่ใน repo เพราะเป็น "schema archaeology" reference

src/testScript.js (167 LOC)

if (!IS_PRODUCTION) {
  testScript()
}

เป็น scratch IIFE ที่ใช้สำหรับรัน one-off data-fix scripts (เช่น สร้าง AD user จำนวนมาก, mask ID card) ที่ผ่านมาในแต่ละเดือน/ปี

  • gated โดย NODE_ENV !== 'production'
  • แต่ top-level IIFE ยัง fire ทุกครั้งที่ boot ใน UAT/dev
  • เรียก checkAdAuthenConnection() ซ้ำกับ boot-time check ใน index.js:93

connector.js debug comment

// const dbHRMI_test = new Sequelize("dbHRMI_test", "root", "1q2w3e4r00", {
//   host: "localhost",
//   port: 3303,
//   dialect: "mariadb",
// ...

Comment ทิ้ง local-dev config พร้อม plaintext password 1q2w3e4r00 — pattern เดียวกับ vtrc-api/api/.env.example ที่มี plaintext credential commit อยู่ใน codebase เป็น evidence ว่าทีมเคยใช้ local MariaDB port 3303 + password 1q2w3e4r00 ในการ dev

dbHRMI_test connection (dead weight)

const dbHRMI_test = new Sequelize("dbHRMI_test", DB_USERNAME, DB_PASSWORD, {
  host: DB_HOST,
  port: DB_PORT,
  dialect: DB_SCHEMA,
  // ...
})

export { db, dbHr, dbHrTemp, dbMasDb, dbHRMI_test, dbHRMI_Center_HIS }
// walk(path.join(__dirname, 'hrmi_test'))
//   .filter(...)
//   .forEach(file => {
//     const model = require(...).default(dbHRMI_test, ...)
//     Models[model.name] = model
//   })
  • database name "dbHRMI_test" เป็น hardcoded literal ไม่ได้มาจาก env (ต่างจาก connection อื่น ๆ ที่อ่านจาก process.env)
  • exported ที่ connector.js:195 แต่ model loader (models/index.js:95-105) commented out
  • ผล — connection pool ที่มี pool.max: 100 เปิดขึ้นทุก boot แต่ไม่มี model ผูก ทำให้เปลือง MSSQL connection 100 session ที่ไม่มีใครใช้

Fix: ลบทั้ง connection ใน connector.js และ loader comment ใน models/index.js ออกพร้อมกัน


SSO certificates committed

cu-central-api/main-api/src/lib/sso/
├── DigiCert_Global_Root_CA.cer       root CA
├── TPRDWSSOWEB01.crt                  prod SSO cert
└── TUATWSSOWEB01.crt                  UAT SSO cert

certificate ของ SSO service (ทั้ง prod และ UAT) commit อยู่ใน repo — เป็น public cert ไม่ใช่ private key จึงไม่ใช่ secret leak โดยตรง แต่เป็น anti-pattern ที่ควร fetch จาก secret manager หรือ truststore แทน รายละเอียดการใช้งานอยู่ใน 3.2.7


สรุปขนาด codebase

ส่วนขนาด
SDL (typeDefs)2,629 LOC (32 ไฟล์)
Resolvers1,826 LOC (28 ไฟล์)
index.js (bootstrap)118 LOC
connector.js (DB)196 LOC
lib/ (business logic)~10,000+ LOC (31 subdirs)
Models~50+ files (6 subdirs)
รวมประมาณ~15,000 LOC

เล็กกว่า vtrc-api (routes.js อย่างเดียว 77 KB) แต่มี complexity ของตัวเอง — โดยเฉพาะ multi-tenant sharding ใน 3.2.5


ทำไมถึงมี typos และ dead code มาก

อ่านจากประวัติ — codebase นี้ port มาจาก HRMI leave-management system เก่า (hrmi.js เป็น SDL ใหญ่สุดที่ 394 LOC ทุก type มีพารามิเตอร์ sourceDb ซึ่งบ่งบอกว่าออกแบบมาให้ใช้กับหลาย shard) เมื่อ migrate หลายรอบโดยไม่มี lint ที่เข้มงวด (มี dep standard ใน package.json:50 แต่ไม่มี lint script) — typo และ dead file จึงสะสม

ใน Wave 1 modernization (Volume 19 Roadmap) lint ที่ลบ no-dupe-keys, no-unused-vars จะ catch ปัญหาพวกนี้ตอน commit


เคล็ดลับตอนทำงานจริง

ก่อนแก้ resolver ที่ดูแปลก

เช็กว่าชื่อไฟล์สะกดถูกไหม — finanace.js ไม่ใช่ bug เป็นชื่อที่ intentional และ GraphQL schema contract อ้างถึง

ถ้าเห็นไฟล์ที่ไม่ถูก import จาก index.js

อย่าลบทันที — เช็ก *_bk*.js, *_copy*, *_removed* ก่อน อาจเป็น "schema archaeology" ที่ team เก็บไว้

ก่อนเพิ่มไฟล์ typeDefs/resolvers ใหม่

อย่าลืม import ใน typeDefs/index.js หรือ resolvers/index.jspayrollSlip_removed.js คือตัวอย่างที่ลืม import จนกลายเป็น dead file


อ่านต่อ → 3.2.2 Bootstrap + 6 DB connections