Skip to content

2way-batch — Repository Map

บทนี้เป็นแผนที่ไฟล์ของ 2way-batch (branch: master, 96 tracked files) — NestJS worker ที่เหลือ cron survey เป็นหลัก


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

2way-batch/                            (branch: master)
├── package.json                       # name=2way-batch
├── config/configuration.ts            # port, jwt, db, lineToken, contentStatus maps
├── docs/document.config.ts            # Swagger; server default port 9340
├── libs/
│   ├── jwt/{jwt-auth.guard,jwt.strategy}.ts
│   ├── exception/http-exception.filter.ts
│   ├── log/logs.middleware.ts
│   └── common/{base64-to-file,ganarate-random-string,validator-date}.ts
├── nginx/
│   ├── conf/nginx.conf
│   └── conf.d/default.conf            # /2way-batch/ → :9340, /2way/ → :8201
├── src/
│   ├── main.ts                        # bootstrap
│   ├── app.module.ts                  # live: Config + TypeORM + Schedule + SurveyTask
│   ├── app.controller.ts              # empty @Controller()
│   ├── app.service.ts
│   ├── constants/surveys.constant.ts
│   ├── dto/                           # announce, common, complaint, employee, line, survey, upload, user
│   ├── entities/                      # 25 entity files
│   ├── modules/
│   │   ├── announces/                 # มีครบ แต่ไม่ import ใน AppModule
│   │   ├── employees/                 # มีครบ แต่ไม่ import
│   │   ├── surveys/                   # ใช้ทางอ้อมผ่าน SurveyTaskModule providers
│   │   ├── line/                      # LineService ใช้ใน cron; LineModule ไม่ import
│   │   └── uploadFiles/               # ไม่ import
│   ├── crontab/survey/
│   │   ├── survey.task.module.ts
│   │   └── survey.task.service.ts     # @Cron EVERY_10_SECONDS
│   └── utils/surveys.util.ts
├── Dockerfile                         # node:16-alpine
├── bitbucket-pipelines.yml
├── endpoint.txt                       # scratch notes (announce/employee/complaint/survey paths)
├── lineText.text                      # scratch LINE helper (ไม่ถูก import)
└── test/

Boot sequence

1. NestFactory.create(AppModule, I3GatewayLogger)
       │  main.ts:15-17

2. port = ConfigService.get('port') || 3000
       │  main.ts:21

3. setGlobalPrefix(`${BASE_PATH}api/v1`)
       │  main.ts:23-25

4. useStaticAssets(uploads) prefix '/2way-batch/'
       │  main.ts:26-28

5. bodyParser 50mb
       │  main.ts:29-30

6. Global filter / JwtAuthGuard / ValidationPipe
       │  main.ts:31-33

7. enableCors origin=*
       │  main.ts:34-38

8. Swagger `${BASE_PATH}docs`
       │  main.ts:40-41

9. listen(port, '0.0.0.0')
       │  main.ts:42-45

10. ScheduleModule triggers SurveyTaskService.handleCron
        every 10 seconds (survey.task.service.ts:32-37)

AppController ว่าง (app.controller.ts:3) — ไม่มี health endpoint ในไฟล์นี้


AppModule — สิ่งที่ถูกโหลดจริง

typescript
imports: [
  ConfigModule.forRoot({ load: [configuration], isGlobal: true }),
  TypeOrmModule.forRootAsync({ name: 'main', type: 'mssql', ... }),
  // AnnouncesModule, SurveysModule, ComplaintsModule,
  // EmployeesModule, LineModule, UploadModule,   ← comment ปิด
  ScheduleModule.forRoot(),
  SurveyTaskModule,
],
controllers: [AppController],
providers: [AppService, JwtStrategy],

แหล่ง: app.module.ts:11-48

TypeORM connection 'main'

Optionค่าอ้างอิง
typemssqlapp.module.ts:21
host/port/user/password/databaseจาก ConfigServiceconfiguration.ts db.*app.module.ts:22-26
synchronizefalseapp.module.ts:27
loggingerror, queryapp.module.ts:28
entities__dirname + '/**/*.entity{.ts,.js}'app.module.ts:29
encryptfalseapp.module.ts:32
trustServerCertificatetrueapp.module.ts:31

แม้ HTTP modules จะไม่ถูก import — TypeORM ยังโหลด ทุก *.entity ใต้ src/ รวม entity ของ announce/complaint ที่ cron ไม่ได้ใช้


SurveyTaskModule — wiring จริงของ cron

typescript
@Module({
  imports: [HttpModule],
  providers: [SurveyTaskService, LineService, SurveysService, SurveysRepository],
})
export class SurveyTaskModule {}

แหล่ง: crontab/survey/survey.task.module.ts:8-12

ไม่ได้ import SurveysModule / LineModule เต็ม ๆ — inject service/repository ตรงเป็น providers ของ task module เอง

ผลข้างเคียง:

  1. SurveysController / LineController ไม่ได้ mount เพราะ module ของพวกมันถูก comment ใน AppModule
  2. LineService ยังถูก instantiate สำหรับ cron
  3. SurveysService constructor เรียก SurveysUtil.initializer(entityManager) (surveys.service.ts:21-27) — โหลด map ของ MStatus / MErrorMessage / MContentFlow ตอน boot ของ provider นี้

Dead code — modules ที่มีไฟล์ครบแต่ไม่ wire

โฟลเดอร์มี controllerถูก import ใน AppModule?
src/modules/announces/ใช่ไม่ (app.module.ts:38)
src/modules/surveys/ใช่ไม่เป็น module — ใช้แค่ service/repo ใน task
src/modules/employees/ใช่ไม่
src/modules/line/มี LineController @Public()ไม่เป็น module — ใช้แค่ LineService
src/modules/uploadFiles/ใช่ไม่

ComplaintsModule ถูก mention ใน comment (app.module.ts:40) แต่โฟลเดอร์ modules/complaints/ ไม่มี ใน tree ของ branch master — มีแค่ complaint entities/DTOs ค้างจาก skeleton

LineController ใน batch มีแค่ POST /Line ที่ @Public() (line.controller.ts:9-17) — ไม่ได้ mount ในสถานะปัจจุบัน


Entities ที่ cron methods อ้างถึง (เมื่อเปิด logic)

จาก imports ใน survey.task.service.ts:6-17:

Entityใช้ใน
TContentquery หลักของ survey content
MContentTypefilter name_en = survey
TContentAssignผู้ถูกมอบหมาย
TContentStatus / MStatusสถานะ
TContentFlowHistory / MContentFlowflow history + short_name
UserLineผ่าน SurveysRepository.findLineIDAsEmpCode
MConfigผ่าน findEmployeeCodeOfHrAdmin

Constants: SurveysConstant (constants/surveys.constant.ts) — CONTENT_TYPE = 'survey', short names ACS/ACD/HAP, create code S00, config key list.empCode.hrAdmin

รายละเอียด schema และ query → 03-persistence-integrations


Config keys ที่ configuration.ts อ่าน

KeyEnvอ้างอิง
portPORTconfiguration.ts:2
jwtSecretKeySECRET_KEYconfiguration.ts:3
db.*DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAMEconfiguration.ts:4-10
lineTokenLINE_AUTH_TOKENconfiguration.ts:11
contentStatus.survey.*(static maps ในโค้ด)configuration.ts:19-40

ไม่มี .env.example ใน repo — ผู้ deploy ต้องรู้ชื่อตัวแปรจาก configuration.ts เอง (QUAL-2WAYBATCH-02)

หมายเหตุ: lineToken ถูกโหลดใน config แต่ LineService.pushMassage ของ batch ไม่ได้ใช้ token นี้ — ยิง HTTP ไป IP hardcode แทน (line.service.ts:25-26)


Nginx snippets ใน repo

nginx/conf.d/default.conf:

server_name api.vtrcapp.com;

location /2way-batch/ {
  proxy_pass http://0.0.0.0:9340/;
}

location /2way/ {
  proxy_pass http://0.0.0.0:8201/;
}

แหล่ง: nginx/conf.d/default.conf:1-16

/2way/ → 8201 น่าจะชี้ไปยังบริการอื่นในกลุ่ม — ไม่ยืนยันจาก compose ใน repo นี้ ว่า process ไหนฟัง 8201 (ไม่มี docker-compose.yml ใน 2way-batch)

nginx/conf/nginx.conf เป็น nginx มาตรฐาน (daemon off, gzip, include conf.d) — nginx.conf:1-28


LineService — hardcode IP (สำคัญ)

แม้ LineModule จะไม่ถูก import แต่ LineService.pushMassage ที่ cron จะเรียก (ถ้าเปิด fetchApproval / fetchCreateOutScope) ยิงไป:

typescript
this.http.post('http://10.188.128.126:9340/2way-batch/api/v1/line', data)

แหล่ง: src/modules/line/line.service.ts:25-26

จุดสังเกต:

  1. IP + port hardcode — ไม่ผ่าน env
  2. Path เป็น /2way-batch/api/v1/line ซึ่งตาม nginx คือตัวเองบน 9340
  3. แต่ LineController ไม่ได้ถูก mount ใน AppModule ปัจจุบัน → ถ้า cron เปิด logic จริงโดยไม่เปิด LineModule การ push มีแนวโน้มได้ 404 / fail
  4. Body map replyToken: body.lineId (line.service.ts:20-22) — ชื่อฟิลด์สับสนกับ LINE reply token จริง
  5. DTO ใน batch ใช้ lineId (dto/line.dto.ts:4-11) ไม่ใช่ replyToken แบบ 2way-line-service

เปรียบเทียบ: 2way-api เรียก rich-menu ของ 2way-line-service ที่ IP อื่น (20.212.116.206:8200) — คนละเส้นทางกับ hardcode ของ batch


Auth libs ที่โหลดแต่ไม่ได้ปกป้อง business route

ส่วนพฤติกรรมอ้างอิง
Global JwtAuthGuardข้ามถ้า @Public()main.ts:32, libs/jwt/jwt-auth.guard.ts:15-23
JwtStrategyBearer + jwtSecretKey จาก SECRET_KEYjwt.strategy.ts:11-15
Live controllersว่าง (AppController)app.controller.ts:3

ในสถานะ wiring ปัจจุบันไม่มี business HTTP route ให้ guard ปกป้อง — ความเสี่ยงจะกลับมาถ้า uncomment modules ที่ติด @Public()


CI / scratch files

  • bitbucket-pipelines.yml ใช้ image node:16 (bitbucket-pipelines.yml:6) — สอดคล้อง Dockerfile
  • endpoint.txt / lineText.text เป็น scratch ที่ commit ไว้ — ไม่ถูก import จาก src/

สิ่งที่อยู่นอกขอบเขตบทนี้