Skip to content

4.6 · TypeDefs + resolvers catalog

บทนี้ catalog GraphQL schema (31 SDL files, 2,629 LOC) และ resolvers (29 files, 1,826 LOC) เพื่อให้ navigate codebase ได้ พร้อมชี้ patterns และ inconsistencies ที่สำคัญ


ขนาดรวม

ส่วนLOCไฟล์
TypeDefs (SDL)2,62931
Resolvers1,82629
รวม schema layer~4,50060

เล็กกว่า vtrc-api (queries.js ไฟล์เดียว 4,500 LOC) — แต่กระจายไฟล์ ทำให้ navigate ง่ายกว่า


TypeDefs catalog (31 ไฟล์)

ไฟล์LOC@auth ใช้?หัวข้อหลัก
root.js35declare directiveQuery, Mutation, Subscribtion (typo), SortingBy, YesNo, JSON, Date
authentication.js56pwdVerification @authAuthResponse, AuthProfileResponse, AuthDomains, AppCredentials
personal.js116personalProfile @auth, employeeProfileHistory @authPersonalProfile, EmployeeDetail, ProfileHistory
employee.js2713 fields @authEmployeeProfile, WorkingProfile, EmployeeFinancial, AccordingProfile, EmployeeAddress, MeisDivision, EmplGroup, EmpLevel, PositionManage/Technical, ImageContent
family.js58employeeFamily @authEmployeeFamily, FamilyPersonInfo, FamilyRelationship enum
organization.js97noneOrganization, OrganizationUnit, OrgazationAddress (typo)
userVerification.js102nonerequestVerificationCode, profileVerificationChecker, profileVerification
registration.js126changePassword @authcreateAccountByVerifyCode, changePasswordByVerifyCode, requestOtp, createSSONotifyUser mutations
timeAttendance.js33timeAttendanceByDate @authTimeAttendance, TimeAttendanceResponse
payrollSlip.js862 fields @authpayrollSlipDetail, payrollSlipDetail6Month
payrollSlip_removed.js112DEAD FILE — ไม่ถูก import
finance.js26employeeFinanceType @authEmployeeFinanace (typo), EmployeeBookBank
bank.js40noneBank, BankBranch, BankBook
tax.js106noneEmployeeTax (90+ fields, full Thai tax form)
fund.js86commented #@authProvidentFund, FundPolicy
compensation.js52employeeCompensation @authEmployeeCompensation, EmployeeCompensationIncomeDeduct
referenceData.js36nonerefOrganizations, refOrganizationBelongs, refNewOrganizationUnits
masterData.js86nonemasterOrgSystem, masterPlace
searchProfile.js44searchUser @auth(accessLevel: 4, ignoreAuth: true)SearchUserResponse
hrEnum.js25nonehrEnum query
notification.js25nonesendSMSNotification mutation
hrmi.js394nonelargest SDL — leave/medical/approver domain
childTuition.js88nonefetchListChildTuitions, fetchChildTuitionDetail
salaryCert.js59nonesalaryCertDetail, salaryCert
hrPerProbation.js15nonecheckHrPerProbationNotApprove
twoWay.js65none6 queries for 2-way sync
sso.js22nonefetchNonEmpSSO, nonEmpSSO
studyLeaveRequest.js105nonegetEmpStudyLeaveRequestCD, getPersonalCD
statLog.js26nonestatLog, statLogList
hr/hrTaxes.js113hrTaxes @authHrTaxesAttr input (~80 fields)
hr/hrAddress.js39hrAddress @authHrAddressAttr input
hr/hrPhoneNumber.js23hrPhoneNumber @authHrPhoneNumberAttr input

hrmi.js — SDL ใหญ่สุด (394 LOC)

ไฟล์เดียวที่ cover leave + medical + approver domain — port มาจาก HRMI leave-management system เก่า

หัวข้อในไฟล์

hrmi.js (394 LOC)
├── Leave
│   ├── getLeaveType
│   ├── getLeaveDocumentList(sourceDb)
│   ├── getLeaveDocumentDetail(sourceDb)
│   ├── getLeaveDay / getLeaveDayAll
│   ├── getWorkingDay
│   ├── getLeaveShiftTime / getShiftTime
│   ├── createLeaveDocument
│   ├── editLeaveDocument
│   └── deleteLeaveDocument
├── Medical
│   └── getMedical(sourceDb)
├── Approver
│   ├── getApprover
│   └── getLeaveApprover
├── Attachment
│   ├── createAttachmentFile
│   ├── updateAttachmentFile
│   └── deleteAttachmentFile
├── Org queries
│   ├── fetchEmpWithOrgnize(sourceDb)
│   ├── fetchEmpwithCoA(sourceDb)
│   └── employeeDetailProfile(sourceDb)
└── enums
    ├── ApproveStatus
    ├── DurationType
    └── ApproverType

sourceDb parameter กระจายไปเกือบทุก query — เป็น evidence ของ multi-tenant pattern (บท 4.5)


Resolvers catalog (29 ไฟล์)

ไฟล์LOCResolvers หลัก
main.js14Query.__type / __schema → throw (introspection guard)
authentication.js72pwdVerification, signInDomains (hardcoded 26-row org list)
personal.js79personalProfile, employeeDetail, employeeProfileHistory
employee.js127employeeProfile, accordingProfile, employeeFinancial, employeeManagement
organization.js42refOrganizations, refOrganizationBelongs
userVerification.js74requestVerificationCode, profileVerificationChecker, profileVerification
registration.js386isAccountExists, createAccountByVerifyCode, changePassword, requestOtp, createSSONotifyUser
timeAttendance.js33timeAttendanceByDate
payrollSlip.js240payrollSlipDetail, payrollSlipDetail6Month
finanace.js26employeeFinanceType (typo)
compensation.js29employeeCompensation
fund.js23fetchEmployeeProvidentFund, createChangeBenefitPerson
masterData.js31masterOrgSystem, masterOrgSystemCreate, masterOrgSystemUpdate
searchProfile.js23searchUser (apiKey-only ผ่าน ignoreAuth)
hrEnum.js17hrEnum
notification.js9sendSMSNotification
hrmi.js24424 resolvers — leave/medical/approver/attachment
bank/book.js38bankBookEmployee, bankBookEmployeeArray
childTuition.js204 child tuition queries
salaryCert.js12salaryCertDetail
hrPerProbation.js12checkHrPerProbationNotApprove
twoWay.js376 queries for 2-way sync
sso.js12fetchNonEmpSSO
studyLeaveRequest.js18getEmpStudyLeaveRequestCD, getPersonalCD
statLog.js12statLog
hr/hrTaxes.js33hrTaxes mutation (wraps dbHrTemp.transaction())
hr/hrAddress.js54hrAddress mutation (OTP ถูกปิด)
hr/hrPhoneNumber.js52hrPhoneNumber mutation (OTP ยังทำงาน)

OTP inconsistency (Critical)

hr/hrAddress.js — OTP ปิดไปตั้งแต่ 8 Jul 2021

17:33:main-api/src/resolvers/hr/hrAddress.js
// ## REMOVE OTP 08Jul2021 ##
// if (!await verifyOtpCode(...)) {
//   throw new Error('OTP_INVALID')
// }

🔴 High — address mutation (ที่ include email + phone fields ตาม HrAddressAttr input) ไม่ต้องผ่าน OTP

hr/hrPhoneNumber.js — OTP ยังทำงาน

hr/hrPhoneNumber.js
// OTP verification ยัง active
if (!await verifyOtpCode(...)) {
  throw new Error('OTP_INVALID')
}

Inconsistency

sibling resolvers 2 ตัว (address + phone) ใช้ pattern ต่างกัน — address แก้ได้ไม่ต้อง OTP แต่ phone ต้อง ควรมี single source of truth สำหรับ "field ไหนบ้างที่ต้อง OTP"


signInDomains — hardcoded org list

authentication.js resolver signInDomains คืน list ของ org ที่ login ได้ โดย hardcoded 26 rows ใน code

authentication.js:35-72
const domains = [
  { id: 'CHULA', nameTH: 'จุฬา', ... },
  { id: 'SOMD', nameTH: 'สมเด็จ', ... },
  // ... 24 more
]

🔴 High — org list ไม่ได้มาจาก DB ทำให้เพิ่ม/แก้ org ต้อง deploy code ใหม่ ควรย้ายไป masterData table


registration.js — ไฟล์ใหญ่สุด (386 LOC)

cover account creation + password management flow

registration.js (386 LOC)
├── isAccountExists         (check ก่อน create)
├── createAccountByVerifyCode
├── changePasswordByVerifyCode
├── changePassword
├── requestOtp
├── getVerifyCodeByEmail
└── createSSONotifyUser

flow ทั้งหมดผูกกับ SSO + AD + SMS gateway — เป็นไฟล์ที่ซับซ้อนที่สุดใน resolver layer


payrollSlip.js — 240 LOC

resolver ที่คำนวณ payroll slip detail

payrollSlip.js (240 LOC)
├── PayrollSlip.bookNo       (resolve field — sensor book number)
├── payrollSlipDetail
└── payrollSlipDetail6Month

ดึงข้อมูลจาก DB view uvi3PaySlipHD + uvi3PaySlipDT (models/hrmi/salary/) — เป็น view ที่ MSSQL side define ไว้


Patterns ที่สังเกตได้

1. Resolver ไม่ได้แยกตาม bounded context

ไฟล์ resolver ผสมหลาย domain — hrmi.js เดียว cover leave + medical + approver + attachment + org queries (244 LOC) ไม่ได้แยกเป็น leave.js, medical.js, approver.js ตาม domain

ใน Go target จะแยกเป็น bounded context ชัดเจน

2. ไม่มี DataLoader pattern

ทุก query ที่ resolve nested field ทำ N+1 — เช่น Employee ที่มี workingProfile association ถ้า query 100 employee พร้อมกัน จะมี 100+1 query

ใน Go target ใช้ dataloader pattern หรือ join โดยตรง

3. sourceDb กระจายทั้ง schema

parameter sourceDb อยู่ในเกือบทุก query ของ hrmi.js — caller (vtrc-api) ต้องรู้ว่าต้อง pass อะไร

ถ้า vtrc-api pass ผิด = cross-tenant data leak (บท 4.5)


Dead SDL — payrollSlip_removed.js

112 LOC ที่ไม่ถูก import — เป็นเวอร์ชันเก่าที่ใช้ empCode แทน profileKey

payrollSlip_removed.js
payrollSlipInfo(empCode: String, year: Int, month: Int): Payroll  ← legacy signature

live version (payrollSlip.js) ใช้ profileKey แทน

payrollSlip.js
payrollSlipDetail(profileKey: String, ...): PayrollSlipDetail  ← current

migration จาก empCodeprofileKey เกิดขึ้นเพื่อ support multi-tenant (เพราะ empCode ไม่ unique ข้าม shard)


สรุป

Patternสถานะ
Schema size🟢 เล็กกว่า vtrc-api
File organization🟡 ผสม domain ในไฟล์เดียว (hrmi.js)
@auth coverage🟡 ไม่ครบทุก field — หลาย field public
OTP consistency🔴 hrAddress vs hrPhoneNumber ต่างกัน
Hardcoded data🟡 signInDomains 26 rows
Dead SDL🟡 payrollSlip_removed.js
N+1 patterns🔴 ไม่มี DataLoader
Typos in schema🟡 EmployeeFinanace, OrgazationAddress, Subscribtion

อ่านต่อ → 4.7 External integrations