Files
lcbp3/Setting Project.md
2025-11-19 11:57:46 +07:00

17 KiB

BACKEND DEVELOPMENT

Backend Development Plan (Phase 0) และ Requirements เราจะสร้างโปรเจกต์ชื่อ lcbp3-backend โดยใช้ NestJS และจัดโครงสร้างแบบ Domain-Driven Design ตั้งแต่เริ่มต้นเพื่อให้รองรับการขยายตัวตามแผนงานครับ

นี่คือขั้นตอนและคำสั่งในการสร้างโปรเจกต์ครับ:

1. ติดตั้ง Nest CLI และสร้างโปรเจกต์

รันคำสั่งต่อไปนี้ใน Terminal ครับ (แนะนำให้ใช้ pnpm ตามแนวทาง FullStackJS Guidelines):

# 1. ติดตั้ง Nest CLI ทั่วโลก (ถ้ายังไม่ได้ติดตั้ง)
npm install -g @nestjs/cli

# 2. สร้างโปรเจกต์ใหม่ชื่อ lcbp3-backend
nest new backend

# 💡 ระบบจะถามหา Package Manager:
# ให้เลือก "pnpm" (เพื่อให้ตรงกับ Frontend และแผนงาน)

2. ปรับโครงสร้างโฟลเดอร์ (Domain-Driven Structure)

หลังจากสร้างโปรเจกต์เสร็จแล้ว เราจะปรับโครงสร้าง src ให้ตรงกับ Backend Plan หัวข้อ 3.10 ครับ

รันคำสั่งเหล่านี้ใน Terminal (ภายในโฟลเดอร์ lcbp3-backend):

# เข้าสู่โฟลเดอร์โปรเจกต์
cd backend

# สร้างโครงสร้างโฟลเดอร์หลัก
mkdir -p src/common/auth
mkdir -p src/common/config
mkdir -p src/common/decorators
mkdir -p src/common/entities
mkdir -p src/common/exceptions
mkdir -p src/common/file-storage
mkdir -p src/common/guards
mkdir -p src/common/interceptors
mkdir -p src/common/resilience
mkdir -p src/common/security
mkdir -p src/common/idempotency
mkdir -p src/common/maintenance

# สร้างโฟลเดอร์สำหรับ Modules ตาม Domain
mkdir -p src/modules/user
mkdir -p src/modules/project
mkdir -p src/modules/master
mkdir -p src/modules/correspondence
mkdir -p src/modules/rfa
mkdir -p src/modules/drawing
mkdir -p src/modules/circulation
mkdir -p src/modules/transmittal
mkdir -p src/modules/search
mkdir -p src/modules/monitoring
mkdir -p src/modules/workflow-engine
mkdir -p src/modules/document-numbering
mkdir -p src/modules/notification
mkdir -p src/modules/file-storage

# สร้างโฟลเดอร์ Database
mkdir -p src/database/migrations
mkdir -p src/database/seeds

3. ตรวจสอบและตั้งค่า TypeScript (Strict Mode)

อ้างอิงจาก FullStackJS Guidelines ข้อ 2.1, เราต้องเปิดใช้งาน Strict Mode เพื่อความปลอดภัยของ Type ครับ

เปิดไฟล์ tsconfig.json และตรวจสอบค่า config ดังนี้:

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ES2021",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    /* Strict Type-Checking Options */
    "strict": true,               // บังคับใช้ Strict Mode
    "noImplicitAny": true,        // ห้ามใช้ Any โดยไม่จำเป็น
    "strictNullChecks": true,     // ตรวจสอบค่า Null อย่างเคร่งครัด
    "strictBindCallApply": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true
  }
}

4. การตั้งค่า Environment (Docker Support)

ตาม Requirements ข้อ 2.1 และ 2.2, เราจะไม่ใช้ .env ในการ deploy จริงบน QNAP แต่จะใช้ Environment Variables ผ่าน docker-compose

อย่างไรก็ตาม สำหรับ Development ให้สร้างไฟล์ .env ไว้สำหรับการรัน Local (และอย่าลืมใส่ใน .gitignore)

สร้างไฟล์ .env ที่ root project:

# Database Configuration (สำหรับการ Dev บนเครื่อง Local)
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=password123
DB_DATABASE=lcbp3_dms

# Application
PORT=3000
NODE_ENV=development

# Security
JWT_SECRET=your_super_secret_key_change_it

ขั้นตอนต่อไป (Next Steps)

ตอนนี้โครงสร้างพื้นฐานพร้อมแล้วครับ ขั้นตอนต่อไปตาม Phase 0 คือ:

  1. Secure Configuration Setup: ติดตั้ง @nestjs/config และ joi เพื่อ validate ตัวแปร environment
  2. Database Connection: ติดตั้ง typeorm, @nestjs/typeorm และ mysql2 (สำหรับ MariaDB)

ต้องการให้ผมพาทำส่วน Configuration Setup (T0.1) ต่อเลยไหมครับ?

การติดตั้ง pnpm

1. ติดตั้งผ่าน npm (วิธีแนะนำ)

เปิด Terminal (หรือ Command Prompt / PowerShell) แล้วรันคำสั่ง:

npm install -g pnpm

คำอธิบาย: -g หมายถึง global install คือติดตั้งลงในเครื่องเพื่อให้เรียกใช้คำสั่ง pnpm ได้จากทุกโฟลเดอร์ครับ

2. ตรวจสอบการติดตั้ง

เมื่อติดตั้งเสร็จแล้ว ให้เช็คเวอร์ชันเพื่อความชัวร์ครับ:

pnpm --version

(ควรจะขึ้นเป็นตัวเลขเวอร์ชัน เช่น 9.x.x)


ทางเลือก: ติดตั้งผ่าน Corepack (สำหรับ Node.js เวอร์ชันใหม่)

หากคุณใช้ Node.js เวอร์ชัน 16.13 ขึ้นไป สามารถเปิดใช้งานฟีเจอร์ Corepack ที่แถมมากับ Node.js ได้เลย โดยไม่ต้องลงผ่าน npm ครับ:

corepack enable
corepack prepare pnpm@latest --activate

เมื่อติดตั้งเสร็จแล้ว

คุณสามารถใช้ pnpm แทน npm ได้เลยครับ เช่น:

  • ติดตั้ง Nest CLI (ถ้ายังไม่ได้ลง): pnpm add -g @nestjs/cli
  • สร้างโปรเจกต์ NestJS: nest new lcbp3-backend (แล้วเลือก pnpm ตอนระบบถาม)
  • รันโปรเจกต์: pnpm start:dev
  • ติดตั้ง Library เพิ่ม: pnpm add [package-name] (เช่น pnpm add typeorm)

ติดตั้งเสร็จแล้ว แจ้งผมได้เลยนะครับ จะได้ไปต่อที่ขั้นตอน Config Database กันครับ

การตั้งค่า MariaDB บน localhost เพื่อใช้กับ NestJS ตามแผนงาน Backend Plan T0.3 และ FullStackJS Guidelines 3.2 เราต้องทำ 2 ส่วนคือ เตรียม Database Server (Docker) และ เชื่อมต่อ NestJS (TypeORM) ครับ

1. ติดตั้ง Libraries ที่จำเป็น

ก่อนอื่นต้องติดตั้ง Module สำหรับ TypeORM, MariaDB Driver และ Config Module (เพื่ออ่านค่าจาก .env) ครับ

รันคำสั่งนี้ใน Terminal:

pnpm add @nestjs/typeorm typeorm mysql2 @nestjs/config

หมายเหตุ: เราใช้ mysql2 driver เพราะ MariaDB เข้ากันได้กับ MySQL Protocol และ mysql2 มีประสิทธิภาพสูงครับ

2. สร้าง MariaDB Server ด้วย Docker Compose

เพื่อให้มั่นใจว่า Environment ตรงกับ Production (ตามข้อกำหนด ** Requirements 2.1** ที่ใช้ Container) เราจะรัน MariaDB ผ่าน Docker ครับ

สร้างไฟล์ docker-compose.yml ที่ root ของโปรเจกต์ (ถ้ายังไม่มี):

version: '3.8'

services:
  mariadb:
    image: mariadb:10.11
    container_name: lcbp3-db-local
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password123
      MYSQL_DATABASE: lcbp3_dms
      MYSQL_USER: admin
      MYSQL_PASSWORD: password123
    ports:
      - '3306:3306'
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - lcbp3-net

  # Optional: phpMyAdmin สำหรับจัดการ DB ง่ายๆ
  pma:
    image: phpmyadmin/phpmyadmin
    container_name: lcbp3-pma-local
    environment:
      PMA_HOST: mariadb
    ports:
      - '8080:80'
    depends_on:
      - mariadb
    networks:
      - lcbp3-net

volumes:
  db_data:

networks:
  lcbp3-net:
    driver: bridge

จากนั้นรันคำสั่งเพื่อเริ่ม Database:

docker-compose up -d

3. ตั้งค่าการเชื่อมต่อใน app.module.ts

เราจะแก้ไขไฟล์ src/app.module.ts ให้เชื่อมต่อกับ Database โดยอ่านค่าจาก .env ผ่าน ConfigService เพื่อความปลอดภัยและยืดหยุ่นครับ

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    // 1. Load Config Module
    ConfigModule.forRoot({
      isGlobal: true, // ให้เรียกใช้ได้ทุกที่โดยไม่ต้อง import ใหม่
      envFilePath: '.env', // อ่านค่าจากไฟล์ .env
    }),

    // 2. Setup TypeORM Connection (Async เพื่อรออ่าน Config ก่อน)
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        type: 'mariadb', // หรือ 'mysql' ก็ได้เพราะใช้ driver เดียวกัน
        host: configService.get<string>('DB_HOST'),
        port: configService.get<number>('DB_PORT'),
        username: configService.get<string>('DB_USERNAME'),
        password: configService.get<string>('DB_PASSWORD'),
        database: configService.get<string>('DB_DATABASE'),
        // Auto Load Entities: โหลด Entity ทั้งหมดที่อยู่ในโปรเจกต์อัตโนมัติ
        autoLoadEntities: true,
        // Synchronize: true เฉพาะ Dev environment (ห้ามใช้ใน Prod)
        synchronize: configService.get<string>('NODE_ENV') === 'development',
        // Logging: เปิดดู Query SQL ตอน Dev
        logging: configService.get<string>('NODE_ENV') === 'development',
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

4. ตรวจสอบไฟล์ .env

ตรวจสอบไฟล์ .env ที่เราสร้างไว้ก่อนหน้านี้ว่าข้อมูลตรงกับ docker-compose.yml ไหมครับ

# Database Configuration
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
# หรือใช้ user: admin / password: password123 ตามที่ตั้งใน docker-compose ก็ได้
# แต่ถ้า connect จาก host (เครื่องเรา) ใช้ root ก็สะดวกดีครับ
DB_PASSWORD=password123
DB_DATABASE=lcbp3_dms

# App Environment
NODE_ENV=development
PORT=3000

5. ทดสอบรันโปรเจกต์

ลองรัน NestJS ดูครับว่าเชื่อมต่อได้ไหม:

pnpm start:dev

ถ้า Terminal ขึ้นข้อความสีเขียวๆ ว่า [NestApplication] Nest application successfully started และไม่มี Error เกี่ยวกับ TypeORM แสดงว่าเชื่อมต่อ MariaDB บน Localhost สำเร็จแล้วครับ! 🎉


ขั้นตอนถัดไป: เราควรสร้าง Base Entity (T1.1) และ Users Entity (T1.3) เพื่อเริ่มทำระบบ Login ไหมครับ?

การสร้าง JWT_SECRET (JSON Web Token Secret) ที่มีความปลอดภัยสูงเป็นสิ่งสำคัญมากสำหรับระบบ Authentication เพราะหาก Secret นี้หลุดหรือเดาง่าย ผู้ไม่หวังดีอาจปลอมแปลง Token เพื่อเข้าสู่ระบบในฐานะใครก็ได้ (เช่น Superadmin)

ในแผนพัฒนา Backend Plan Phase 0 (T0.1) และ FullStackJS Guidelines ระบุว่าต้องจัดการ Secrets อย่างปลอดภัย นี่คือวิธีสร้าง JWT_SECRET ที่มีความซับซ้อนและปลอดภัย (High Entropy) ครับ:

วิธีที่ 1: ใช้ OpenSSL (แนะนำสำหรับ Production)

วิธีนี้เป็นมาตรฐานและปลอดภัยที่สุด หากคุณใช้ Linux, macOS หรือ Git Bash บน Windows ให้เปิด Terminal แล้วพิมพ์คำสั่ง:

openssl rand -base64 64

ผลลัพธ์จะได้ String ยาวๆ ที่อ่านไม่รู้เรื่อง เช่น: h78/sT5...xYz==

วิธีที่ 2: ใช้ Node.js Crypto (ง่ายสำหรับ Developer)

เนื่องจากเราพัฒนาด้วย Node.js/NestJS คุณสามารถใช้คำสั่ง Node เพื่อสร้าง Key ได้เลย ไม่ต้องติดตั้งอะไรเพิ่มครับ

รันคำสั่งนี้ใน Terminal:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

ผลลัพธ์จะได้ Hex String ยาว 64 ตัวอักษร

วิธีที่ 3: ใช้ Password Manager Generator

หากใช้ 1Password, LastPass หรือ Bitwarden สามารถใช้ฟีเจอร์ "Generate Password" โดยตั้งค่าความยาว 64 ตัวอักษร (รวมตัวเลขและสัญลักษณ์) ก็ใช้ได้เช่นกันครับ


⚙️ การนำไปใช้งานในโปรเจกต์

เมื่อได้ Secret Key มาแล้ว ให้นำไปใส่ในไฟล์ .env ของคุณ (และ ห้าม Commit ไฟล์นี้ขึ้น Git เด็ดขาด ตามข้อกำหนด):

ไฟล์: .env

# Security
# แทนที่ค่าเดิมด้วยค่าที่ Gen ได้ใหม่
JWT_SECRET=d4a1b2... (ค่าที่คุณเพิ่งสร้าง)
JWT_EXPIRATION=8h

ข้อควรระวัง:

  1. ความยาว: ควรยาวอย่างน้อย 32 bytes (256 bits) เพื่อป้องกัน Brute-force
  2. Environment: ควรแยก Secret ระหว่างเครื่อง Development และ Production ไม่ควรใช้ Key เดียวกัน

คุณต้องการให้ผมช่วยตั้งค่า ConfigModule ใน NestJS เพื่ออ่านค่า JWT_SECRET นี้อย่างปลอดภัยพร้อม Validate ว่าห้ามเป็นค่าว่างไหมครับ?