Skip to content

7.1.1 · Repository map (V1 depth)

branch: prod-meeting-vtrc-api (180 tracked files)

บทนี้เป็นแผนที่ไฟล์ของ meeting-vtrc-api — Express 4 + Sequelize 6 + MSSQL สำหรับจองและบริหารการประชุม พร้อม outbound ไป legacy vtrc-api และ employee directory แบบ "TwoWay"

ชื่อ package ใน package.json คือ "express" (package.json:2) — ไม่ตรงกับชื่อ repo; เป็นร่องรอย scaffold เก่า


แผนที่โฟลเดอร์ระดับ repo

meeting-vtrc-api/                    (branch: prod-meeting-vtrc-api)
├── app.ts                           # entry — Express + Sentry + route mount + listen(8000)
├── package.json                     # name=express, main=app.ts, start=ts-node
├── Dockerfile                       # node:16.19.0-alpine + Chromium + COPY .env${ENV}
├── docker-compose.yml               # meetingservice, 8000:8000, storage volume
├── .envdev / .envuat / .envprod     # plaintext secrets committed
├── tsconfig.json / jest.config.js / .eslintrc.json
├── README.md                        # สั้นมาก — ไม่ใช่ source of truth
├── model/
│   ├── meeting/meeting.ts           # 11 tables: Meeting, Guest, OtherGuest, Attached,
│   │                                # Summary, StatusResponse, Remark, Delegate,
│   │                                # Comment, Token, ScheduleJob
│   ├── approver/approver.ts         # Approver
│   ├── usergroup/usergroup.ts       # GroupMeeting + UserGroup
│   └── login.ts                     # user + user_group (domain ไม่เกี่ยวประชุม)
├── util/
│   ├── db.config.ts                 # Sequelize instance + import 4 model files
│   ├── env.ts                       # DATABASE/USERNAME/… จาก process.env
│   ├── jwt.config.ts                # SECRET hardcode "123"
│   ├── mongo.config.ts              # ทั้งไฟล์ comment — ไม่มี Mongo
│   ├── axiosinterceptors/
│   │   ├── vtrc.connector.ts        # → VTRC_BASE_CONNECT (vtrc-api GraphQL)
│   │   └── cdb.connector.ts         # → CDB_BASE_CONNECT (employee GraphQL)
│   ├── helper/                      # corn.email, sendNoti, emailsender, mapuser, …
│   ├── emailtemplate/emailtemplate.ts
│   └── pdftemplate/                 # sign_join_meeting.ejs, layout.html.ejs
├── middleware/
│   ├── checkbypass.ts               # Bearer + TokenMeeting (ใช้จริงน้อยมาก)
│   └── checkbypasswhenredirect.ts   # redirect flow: verify vtrc + stamp TokenMeeting
├── lib/
│   ├── pdfgenbyhtml.func.ts         # EJS → PDF (html-pdf-node / puppeteer)
│   ├── Emailsender.func.ts          # nodemailer + iCal
│   ├── Uploadimage.class.ts         # Tinify key hardcode (call commented)
│   ├── uploadfile.func.ts           # เขียนไฟล์แนบลง disk
│   ├── Usermanage.class.ts / Dateformat.class.ts / model.ts
├── corn-job/
│   ├── config.ts                    # JOB_SCHEDULE = "*/15 * * * *"
│   └── email.corn.ts                # scheduleEmail() — ดูหมายเหตุ boot ด้านล่าง
├── routes/
│   ├── auth/
│   │   ├── redirectbypass.ts        # mount ที่ /meeting/redirectbypass
│   │   └── refreshtoken.ts          # ไม่ถูก mount — dead code
│   ├── secure/meeting/              # ~30 route files
│   ├── secure/approver/approver.ts
│   ├── secure/usergroup/usergroup.ts
│   └── mockdelatlast/mockuser.ts    # PII mock — ไม่มี auth
├── fonts/                           # Kanit ฯลฯ สำหรับ PDF ใน Docker
├── storage/                         # static ผ่าน /meeting/file
├── interfacedef/                    # TypeScript interfaces (approver, user)
├── __test__/ / coverage/ / dist/    # test + build output — ห้ามแก้เป็น source
└── dataMeeting/                     # sample data folder

หลักการจัดกลุ่มไฟล์

  • model/ = ที่เดียวที่นิยาม schema — ไม่มี migration folder; boot เรียกแค่ authenticate() (util/db.config.ts:27-33) ไม่มี .sync()
  • routes/secure/* ไม่ได้แปลว่ามี auth — คำว่า secure เป็นชื่อโฟลเดอร์; global guard ถูก comment ที่ app.ts:104-120
  • util/axiosinterceptors/ คือขอบเขต outbound 2 ทาง — vtrc.connector.ts และ cdb.connector.ts
  • corn-job/ สะกดผิดจาก "cron" ทั้ง repo รวม public path /meeting/secure/corn-email — คงสะกดตามโค้ดจริง

Boot sequence

1. require("./corn-job/email.corn")     app.ts:4
       │  ← โหลด module แต่ไม่เรียก scheduleEmail() — cron auto-start ไม่เกิด

2. require("./util/mongo.config.ts")    app.ts:8
       │  ← side-effect เปล่า (ไฟล์ comment ทั้งก้อน)

3. dotenv.config({ path: "./.env" })    app.ts:21-23
       │  ← ชื่อไฟล์ต้องเป็น .env (Docker COPY .env${ENV} → .env)

4. swagger-jsdoc + swagger-ui @ /docs   app.ts:50-78

5. Sentry.init + request/tracing/error  app.ts:79-89

6. bodyParser json limit 500mb          app.ts:123-124

7. CORS Allow-Origin: * (มือเขียน)      app.ts:126-144

8. static /meeting/file → storage/      app.ts:147

9. mount ~30 route prefixes             app.ts:148-231

10. app.listen(8000)                    app.ts:232-234

Cron ไม่ถูก start ตอน boot — ข้อเท็จจริงสำคัญ

corn-job/email.corn.ts:6-18 export scheduleEmail แต่ app.ts แค่ require module เป็น myCorn โดยไม่เรียก myCorn.scheduleEmail()

ผลที่ตรวจได้จากซอร์ส:

ช่องทางสถานะหลักฐาน
Auto cron ทุก 15 นาทีไม่ถูกเรียกตอน bootapp.ts:4 require อย่างเดียว
Manual HTTP triggerทำงานGET /meeting/secure/corn-emailexecuteTask("email") (routes/secure/meeting/corn-email.ts:10-14)

ถ้า production พึ่ง cron ใน process นี้โดยไม่มี external scheduler ยิง /corn-email — อีเมลจะไม่ถูกส่งอัตโนมัติ (UNVERIFIED ว่ามี cron ภายนอกหรือไม่)

Cluster fork code ที่ app.ts:25-36 ถูก comment ทั้งก้อน — รัน single process


dotenv path mismatch

จุดโหลดPathหลักฐาน
app.ts / util/env.ts./.envapp.ts:21-23, util/env.ts:1-3
lib/Emailsender.func.ts./.env ถ้า NODE_ENV==production มิฉะนั้น ./.envdevlib/Emailsender.func.ts:6-8
middleware/checkbypasswhenredirect.tsเหมือน Emailsendermiddleware/checkbypasswhenredirect.ts:11-13
Docker buildCOPY ".env${ENV}" .envDockerfile:24

ไฟล์ที่ commit ชื่อ .envdev / .envuat / .envprod — ไม่มี .env ใน working tree จนกว่า Docker/CI จะ copy


Inventory — ทุก REST route ที่ mount ใน app.ts

Prefix มาจาก app.use(...) ใน app.ts:147-231 รวมกับ path ใน route.(get|post|delete) ของแต่ละไฟล์

Auth / redirect / mock

MethodFull pathFileAuth
GET/meeting/redirectbypass/routes/auth/redirectbypass.ts:22checkBypassWhenRedirect + x-api-key
GET/meeting/mockuser/oneroutes/mockdelatlast/mockuser.ts:29ไม่มี — คืน PII hardcode
(ไม่ mount) refreshtoken.tsroutes/auth/refreshtoken.tsdead code

Approver

MethodFull pathFile:line
POST/meeting/secure/approver/addNewApproverapprover.ts:22-24
GET/meeting/secure/approver/listApproverapprover.ts:50
DELETE/meeting/secure/approver/deleteApproverapprover.ts:82-84

Mount: app.ts:148-149

User group (/meeting/secure/group)

MethodFull pathFile:line
POST/meeting/secure/group/creategroupusergroup.ts:23-25
POST/meeting/secure/group/editgroupusergroup.ts:55-57
GET/meeting/secure/group/listgroupusergroup.ts:86
GET/meeting/secure/group/usergroup.ts:119
GET/meeting/secure/group/meetinggroupusergroup.ts:153
DELETE/meeting/secure/group/deletegroupusergroup.ts:185-187
GET/meeting/secure/group/listgroupmeetingallusergroup.ts:207
GET/meeting/secure/group/finduserlistbygroup/:idusergroup.ts:224-226

Mount: app.ts:218-219

Meeting CRUD + lists

MethodFull pathFileหมายเหตุ
POST/meeting/secure/meeting/addNewMeetingmeeting.ts:29-31Flow 1 — สร้างประชุม
DELETE/meeting/secure/meeting/deletemeetingmeeting.ts:51-53soft-delete isActive: 0
GET/meeting/secure/meeting/sendmeeting.ts:73test hooksendMail(4403) hardcode
POST/meeting/secure/updateMeeting/updatemeeting.ts:23-25
POST/meeting/secure/searchmeeting/searchMeetingsearchmeeting.ts:22-24
POST/meeting/secure/searchmeetingsummary/searchmeetingsummary.ts:22
POST/meeting/secure/listmeetingdraft/listmeetingdraft.ts:22
POST/meeting/secure/listmeetingevercreated/listmeetingevercreated.ts:22
POST/meeting/secure/listmeetingpendingapproval/listmeetingpendingapproval.ts:22
POST/meeting/secure/listmeetingrecordafter/listmeetingrecordafter.ts:22
POST/meeting/secure/listmeetingrequestapproval/listmeetingrequestapproval.ts:22
POST/meeting/secure/listmeetinginvited/listmeetinginvited.ts:29
POST/meeting/secure/listmeetingagree/listmeetingagree.ts:29-31
POST/meeting/secure/meetingdetail/meetingdetail.ts:35
POST/meeting/secure/approvemeeting/approvemeeting.ts:24-26Flow 3
POST/meeting/secure/acceptancemeeting/acceptancemeeting.ts:31-33Flow 4 — join/reject/delegate
POST/meeting/secure/guestlistmeeting/guestlistmeeting.ts:22
POST/meeting/secure/updateSummaryMeeting/updatesummarymeeting.ts:25-27
POST/meeting/secure/commentSummaryMeeting/commentsummarymeeting.ts:22-24
POST/meeting/secure/listCommentSummaryMeeting/listcommentsummarymeeting.ts:22-24
GET/meeting/secure/listCommentbyMultiMeeting/listcommentbymultimeeting.ts:22-24
POST/meeting/secure/listMeetinginMonth/listmeetinginmonth.ts:36-38
POST/meeting/secure/acceptsummarymeeting/acceptsummarymeeting.ts:22-24

Mount lines: app.ts:150-207, 222-223

Group meeting (legacy duplicate path)

MethodFull pathFile
GET/meeting/secure/groupmeeting/groupmeeting.ts:22
GET/meeting/secure/groupmeeting/meetinggroupgroupmeeting.ts:42
DELETE/meeting/secure/groupmeeting/deletegroupgroupmeeting.ts:74-76

Mount: app.ts:152-153 — ฟังก์ชันคล้าย /meeting/secure/group แต่คนละ router

Lookup / org / PDF / attachment / ops

MethodFull pathFileหมายเหตุ
GET/meeting/secure/finddropdownbyorg/:levelfinddropdownbyorg.ts:22
GET/meeting/secure/finduserlistbyorg/finduserlistbyorg.ts:23
POST/meeting/secure/finduserlist/finduserlist.ts:19-21
POST/meeting/secure/createpdfinvitemeeting/createpdfinvitemeeting.ts:44import auth แต่ไม่ apply
POST/meeting/secure/createpdfsignaturemeeting/createpdfsignaturemeeting.ts:15
GET/meeting/secure/attacment/:idattacment.ts:29typo "attacment"; import auth ไม่ apply
GET/meeting/secure/corn-email/corn-email.ts:10manual email task — ไม่มี auth
GET/meeting/secure/health-check/emailhealth-check.ts:9ส่งอีเมลจริงไป hardcode address

Static:

MethodFull pathหลักฐาน
GET/meeting/file/*app.ts:147./storage/meeting/

Auth surface — สิ่งที่โค้ด enforce จริง

app.ts:104-120   ← global /meeting/secure/* guard ถูก comment ทั้งก้อน

ผล:
  เกือบทุก mutation/list รับ request ได้โดยไม่ต้องมี Bearer หรือ x-api-key
  ยกเว้น redirectbypass ที่ใส่ middleware บน route เอง

middleware/checkbypass.ts — พฤติกรรมจริง

  1. ถ้ามี Authorization: Bearer … → เรียก requestCheckInVtrcApi(token) (checkbypass.ts:17-26)
  2. requestCheckInVtrcApi สร้าง GraphQL query string แต่ ไม่ยิง vtrcConnector — มีแค่ decodeJwt(token) แบบส่ง arg เดียว (checkbypass.ts:59-68) ในขณะที่ decodeJwt(token, secert) ต้องการ secret (util/helper/jwtdecode.ts:12-19) → jwt.verify ด้วย undefined มัก fail
  3. ถ้าไม่มี Bearer → next() ด้วย confirmBypass = false (checkbypass.ts:28-30) — ไม่บล็อก

checkApiKeyMiddleWare เทียบ x-api-key กับ process.env.API_KEY (checkbypass.ts:91-105)

middleware/checkbypasswhenredirect.ts — flow ที่ใช้จริง

  1. Decode JWT ด้วย SECRET_JWT_VTRC (checkbypasswhenredirect.ts:67)
  2. POST GraphQL fetchEmployeeProfileForOtherService ผ่าน vtrcConnector (:69-71)
  3. ออก JWT ใหม่ด้วย SECRET_JWT_MEETING หมดอายุ 48h (signNewJwt, :99-106)
  4. Stamp / update ตาราง Token (TokenMeeting) (stampDBToken, :109-127)
  5. checkApiKeyMiddleWare บังคับ x-api-key (:130-145)

นี่คือ auth bridge หลักระหว่าง meeting-backoffice กับ service นี้


Helper / lib map (ไฟล์ที่ flow หลักพึ่งพา)

ไฟล์บทบาท
util/helper/corn.email.helper.tscreateScheduleJob, executeTask, emailTask
util/helper/emailsender.tsorchestration ส่งเมล (เรียก lib/Emailsender.func.ts)
util/helper/sendNoti.tspush bridge → sendNotificationFrom3Party
util/helper/mapuser.tsmap empCode → profile ผ่าน cdb
util/helper/createSignnature.helper.tsPDF ลายเซ็น / เชิญ
util/helper/filenamegen.tsชื่อไฟล์ gen
util/helper/utils.tscheckFileType
lib/pdfgenbyhtml.func.tsEJS → PDF buffer
lib/Emailsender.func.tsSMTP + iCal
lib/uploadfile.func.tsเขียนไฟล์แนบ

ชื่อไฟล์ emailsender.ts vs Emailsender.func.ts ต่างกันแค่ตัวพิมพ์ — เสี่ยงบน Linux case-sensitive FS (ดู scorecard QUAL-MTVTRC-03)


Test / quality tooling

ToolConfigหมายเหตุ
Jestjest.config.js, script testมี __test__/test.spec.ts + coverage output
ESLint.eslintrc.json, script lint
Swagger/docsapis glob ./routes//.ts น่าจะผิดพลาด — อาจไม่ gen path จริง (app.ts:75)

ไฟล์ที่ห้ามแก้ / ไม่ใช่ source of truth

  • dist/, coverage/, ut-report/ — compiled / report
  • yarn-error.log, *.pdf ตัวอย่างใน root
  • _bk* ไม่พบใน repo นี้ แต่ถ้ามีให้ข้ามตามกฎ workspace

สรุปสำหรับผู้อ่านที่เพิ่งเข้า repo

  1. ยืนยัน branch prod-meeting-vtrc-api ก่อนอ่านโค้ด
  2. Persistence = Sequelize + MSSQL — ไม่ใช่ Mongoose
  3. อย่าเชื่อ path /secure/ ว่ามี auth — เปิดไฟล์ route + app.ts ทุกครั้ง
  4. Push ไม่ได้อยู่ใน service นี้ — อยู่ที่ sendNotivtrc-api
  5. Mock /meeting/mockuser/one เป็นพื้นผิว leak ที่มีเอกสารใน 7.1.4