260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
@@ -196,7 +196,7 @@ pnpm add @nestjs/typeorm typeorm mysql2 @nestjs/config
|
||||
สร้างไฟล์ `docker-compose.yml` ที่ root ของโปรเจกต์ (ถ้ายังไม่มี):
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
@@ -209,7 +209,7 @@ services:
|
||||
MYSQL_USER: admin
|
||||
MYSQL_PASSWORD: password123
|
||||
ports:
|
||||
- "3306:3306"
|
||||
- '3306:3306'
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
@@ -222,7 +222,7 @@ services:
|
||||
environment:
|
||||
PMA_HOST: mariadb
|
||||
ports:
|
||||
- "8080:80"
|
||||
- '8080:80'
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
@@ -248,36 +248,36 @@ docker-compose up -d
|
||||
|
||||
```typescript
|
||||
// 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";
|
||||
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
|
||||
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"),
|
||||
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",
|
||||
synchronize: configService.get<string>('NODE_ENV') === 'development',
|
||||
// Logging: เปิดดู Query SQL ตอน Dev
|
||||
logging: configService.get<string>("NODE_ENV") === "development",
|
||||
logging: configService.get<string>('NODE_ENV') === 'development',
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
@@ -397,14 +397,12 @@ pnpm add @nestjs/config joi
|
||||
|
||||
```typescript
|
||||
// File: src/common/config/env.validation.ts
|
||||
import Joi from "joi";
|
||||
import Joi from 'joi';
|
||||
|
||||
// สร้าง Schema สำหรับตรวจสอบค่า Environment Variables
|
||||
export const envValidationSchema = Joi.object({
|
||||
// 1. Application Environment
|
||||
NODE_ENV: Joi.string()
|
||||
.valid("development", "production", "test", "provision")
|
||||
.default("development"),
|
||||
NODE_ENV: Joi.string().valid('development', 'production', 'test', 'provision').default('development'),
|
||||
PORT: Joi.number().default(3000),
|
||||
|
||||
// 2. Database Configuration (MariaDB)
|
||||
@@ -417,11 +415,8 @@ export const envValidationSchema = Joi.object({
|
||||
|
||||
// 3. Security (JWT)
|
||||
// ต้องมีค่า และควรยาวพอ (ตรวจสอบความยาวได้ถ้าระบุ min)
|
||||
JWT_SECRET: Joi.string()
|
||||
.required()
|
||||
.min(32)
|
||||
.message("JWT_SECRET must be at least 32 characters long for security."),
|
||||
JWT_EXPIRATION: Joi.string().default("8h"),
|
||||
JWT_SECRET: Joi.string().required().min(32).message('JWT_SECRET must be at least 32 characters long for security.'),
|
||||
JWT_EXPIRATION: Joi.string().default('8h'),
|
||||
});
|
||||
```
|
||||
|
||||
@@ -431,19 +426,19 @@ export const envValidationSchema = Joi.object({
|
||||
|
||||
```typescript
|
||||
// File: 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";
|
||||
import { envValidationSchema } from "./common/config/env.validation.js"; // สังเกต .js สำหรับ ESM
|
||||
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';
|
||||
import { envValidationSchema } from './common/config/env.validation.js'; // สังเกต .js สำหรับ ESM
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// 1. Setup Config Module พร้อม Validation
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true, // เรียกใช้ได้ทั่วทั้ง App ไม่ต้อง import ซ้ำ
|
||||
envFilePath: ".env", // อ่านไฟล์ .env (สำหรับ Dev)
|
||||
envFilePath: '.env', // อ่านไฟล์ .env (สำหรับ Dev)
|
||||
validationSchema: envValidationSchema, // ใช้ Schema ที่เราสร้างเพื่อตรวจสอบ
|
||||
validationOptions: {
|
||||
// ถ้ามีค่าไหนไม่ผ่าน Validation ให้ Error และหยุดทำงานทันที
|
||||
@@ -456,15 +451,15 @@ import { envValidationSchema } from "./common/config/env.validation.js"; // ส
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
type: "mariadb",
|
||||
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"),
|
||||
type: 'mariadb',
|
||||
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'),
|
||||
autoLoadEntities: true,
|
||||
// synchronize: true เฉพาะตอน Dev เท่านั้น ห้ามใช้บน Prod
|
||||
synchronize: configService.get<string>("NODE_ENV") === "development",
|
||||
synchronize: configService.get<string>('NODE_ENV') === 'development',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
@@ -481,7 +476,7 @@ export class AppModule {}
|
||||
สร้างไฟล์: `docker-compose.override.yml.example` ที่ root project:
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Override ค่า Config ของ Service Backend (เมื่อเราสร้าง Container Backend ในอนาคต)
|
||||
@@ -533,7 +528,7 @@ App **ต้อง Crash** และแสดง Error Message ชัดเจ
|
||||
**ไฟล์: `docker-compose.yml`**
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ... (mariadb & pma เดิม) ...
|
||||
@@ -546,7 +541,7 @@ services:
|
||||
# ใช้ Command นี้เพื่อตั้ง Password
|
||||
command: redis-server --requirepass "redis_password_secure"
|
||||
ports:
|
||||
- "6379:6379"
|
||||
- '6379:6379'
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
@@ -614,20 +609,20 @@ pnpm add @nestjs/bullmq bullmq
|
||||
**ไฟล์: `src/app.module.ts`**
|
||||
|
||||
```typescript
|
||||
import { Module } from "@nestjs/common";
|
||||
import { ConfigModule, ConfigService } from "@nestjs/config";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
import { BullModule } from "@nestjs/bullmq"; // Import BullModule
|
||||
import { AppController } from "./app.controller";
|
||||
import { AppService } from "./app.service";
|
||||
import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { BullModule } from '@nestjs/bullmq'; // Import BullModule
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { envValidationSchema } from './common/config/env.validation.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// 1. Config (เดิม)
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: ".env",
|
||||
envFilePath: '.env',
|
||||
validationSchema: envValidationSchema,
|
||||
validationOptions: { abortEarly: true },
|
||||
}),
|
||||
@@ -637,14 +632,14 @@ import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
type: "mariadb",
|
||||
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"),
|
||||
type: 'mariadb',
|
||||
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'),
|
||||
autoLoadEntities: true,
|
||||
synchronize: configService.get<string>("NODE_ENV") === "development",
|
||||
synchronize: configService.get<string>('NODE_ENV') === 'development',
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -654,9 +649,9 @@ import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
connection: {
|
||||
host: configService.get<string>("REDIS_HOST"),
|
||||
port: configService.get<number>("REDIS_PORT"),
|
||||
password: configService.get<string>("REDIS_PASSWORD"),
|
||||
host: configService.get<string>('REDIS_HOST'),
|
||||
port: configService.get<number>('REDIS_PORT'),
|
||||
password: configService.get<string>('REDIS_PASSWORD'),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -686,25 +681,25 @@ pnpm start:dev
|
||||
ให้เพิ่มบรรทัดนี้ที่ส่วนบนสุดของไฟล์ `src/app.module.ts` ครับ:
|
||||
|
||||
```typescript
|
||||
import { BullModule } from "@nestjs/bullmq";
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
```
|
||||
|
||||
หรือลองตรวจสอบไฟล์ `src/app.module.ts` ให้ครบถ้วนตามนี้ครับ:
|
||||
|
||||
```typescript
|
||||
import { Module } from "@nestjs/common";
|
||||
import { ConfigModule, ConfigService } from "@nestjs/config";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
import { BullModule } from "@nestjs/bullmq"; // <--- ต้องมีบรรทัดนี้ครับ
|
||||
import { AppController } from "./app.controller";
|
||||
import { AppService } from "./app.service";
|
||||
import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { BullModule } from '@nestjs/bullmq'; // <--- ต้องมีบรรทัดนี้ครับ
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { envValidationSchema } from './common/config/env.validation.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: ".env",
|
||||
envFilePath: '.env',
|
||||
validationSchema: envValidationSchema,
|
||||
validationOptions: { abortEarly: true },
|
||||
}),
|
||||
@@ -712,14 +707,14 @@ import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
type: "mariadb",
|
||||
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"),
|
||||
type: 'mariadb',
|
||||
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'),
|
||||
autoLoadEntities: true,
|
||||
synchronize: configService.get<string>("NODE_ENV") === "development",
|
||||
synchronize: configService.get<string>('NODE_ENV') === 'development',
|
||||
}),
|
||||
}),
|
||||
// Queue Configuration
|
||||
@@ -728,9 +723,9 @@ import { envValidationSchema } from "./common/config/env.validation.js";
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
connection: {
|
||||
host: configService.get<string>("REDIS_HOST"),
|
||||
port: configService.get<number>("REDIS_PORT"),
|
||||
password: configService.get<string>("REDIS_PASSWORD"),
|
||||
host: configService.get<string>('REDIS_HOST'),
|
||||
port: configService.get<number>('REDIS_PORT'),
|
||||
password: configService.get<string>('REDIS_PASSWORD'),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user