251120:0800 add .
This commit is contained in:
@@ -24,7 +24,7 @@ DROP VIEW IF EXISTS v_user_tasks;
|
|||||||
DROP VIEW IF EXISTS v_contract_parties_all;
|
DROP VIEW IF EXISTS v_contract_parties_all;
|
||||||
DROP VIEW IF EXISTS v_current_rfas;
|
DROP VIEW IF EXISTS v_current_rfas;
|
||||||
DROP VIEW IF EXISTS v_current_correspondences;
|
DROP VIEW IF EXISTS v_current_correspondences;
|
||||||
DROP PROCEDURE IF EXISTS sp_get_next_document_number;
|
-- DROP PROCEDURE IF EXISTS sp_get_next_document_number;
|
||||||
-- 🗑️ DROP TABLE SCRIPT: LCBP3-DMS v1.4.2
|
-- 🗑️ DROP TABLE SCRIPT: LCBP3-DMS v1.4.2
|
||||||
-- คำเตือน: ข้อมูลทั้งหมดจะหายไป กรุณา Backup ก่อนรันบน Production
|
-- คำเตือน: ข้อมูลทั้งหมดจะหายไป กรุณา Backup ก่อนรันบน Production
|
||||||
SET FOREIGN_KEY_CHECKS = 0;
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
@@ -36,7 +36,8 @@ DROP TABLE IF EXISTS search_indices;
|
|||||||
DROP TABLE IF EXISTS notifications;
|
DROP TABLE IF EXISTS notifications;
|
||||||
DROP TABLE IF EXISTS audit_logs;
|
DROP TABLE IF EXISTS audit_logs;
|
||||||
-- [NEW v1.4.2] ตารางการตั้งค่าส่วนตัวของผู้ใช้ (FK -> users)
|
-- [NEW v1.4.2] ตารางการตั้งค่าส่วนตัวของผู้ใช้ (FK -> users)
|
||||||
DROP TABLE IF EXISTS user_preferencesว -- [NEW v1.4.2] ตารางเก็บ Schema สำหรับ Validate JSON (Stand-alone)
|
DROP TABLE IF EXISTS user_preferences;
|
||||||
|
-- [NEW v1.4.2] ตารางเก็บ Schema สำหรับ Validate JSON (Stand-alone)
|
||||||
DROP TABLE IF EXISTS json_schemas;
|
DROP TABLE IF EXISTS json_schemas;
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
-- ส่วนที่ 2: ตาราง Junction (เชื่อมโยงข้อมูล M:N)
|
-- ส่วนที่ 2: ตาราง Junction (เชื่อมโยงข้อมูล M:N)
|
||||||
@@ -333,6 +334,7 @@ CREATE TABLE users (
|
|||||||
last_login_at TIMESTAMP NULL COMMENT 'วันที่และเวลาที่ล็อกอินล่าสุด',
|
last_login_at TIMESTAMP NULL COMMENT 'วันที่และเวลาที่ล็อกอินล่าสุด',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
|
||||||
|
deleted_at DATETIME NULL DEFAULT NULL COMMENT 'วันที่ลบ',
|
||||||
FOREIGN KEY (primary_organization_id) REFERENCES organizations(id) ON DELETE
|
FOREIGN KEY (primary_organization_id) REFERENCES organizations(id) ON DELETE
|
||||||
SET NULL
|
SET NULL
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บข้อมูลผู้ใช้งาน (User)';
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บข้อมูลผู้ใช้งาน (User)';
|
||||||
@@ -340,7 +342,7 @@ CREATE TABLE users (
|
|||||||
INSERT INTO users (username, password_hash, email, is_active)
|
INSERT INTO users (username, password_hash, email, is_active)
|
||||||
VALUES (
|
VALUES (
|
||||||
'superadmin',
|
'superadmin',
|
||||||
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
|
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
|
||||||
'superadmin @example.com',
|
'superadmin @example.com',
|
||||||
1
|
1
|
||||||
) ON DUPLICATE KEY
|
) ON DUPLICATE KEY
|
||||||
@@ -352,7 +354,7 @@ VALUES(is_active);
|
|||||||
INSERT IGNORE INTO users (username, password_hash, email, is_active)
|
INSERT IGNORE INTO users (username, password_hash, email, is_active)
|
||||||
VALUES (
|
VALUES (
|
||||||
'editor01',
|
'editor01',
|
||||||
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
|
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
|
||||||
'editor01 @example.com',
|
'editor01 @example.com',
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
@@ -360,7 +362,7 @@ VALUES (
|
|||||||
INSERT IGNORE INTO users (username, password_hash, email, is_active)
|
INSERT IGNORE INTO users (username, password_hash, email, is_active)
|
||||||
VALUES (
|
VALUES (
|
||||||
'viewer01',
|
'viewer01',
|
||||||
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
|
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
|
||||||
'viewer01 @example.com',
|
'viewer01 @example.com',
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
@@ -1303,7 +1305,9 @@ CREATE TABLE correspondence_routings (
|
|||||||
'FOR_REVIEW',
|
'FOR_REVIEW',
|
||||||
'FOR_INFORMATION',
|
'FOR_INFORMATION',
|
||||||
'FOR_ACTION '
|
'FOR_ACTION '
|
||||||
) NOT NULL DEFAULT 'FOR_REVIEW' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้ เช่น เพื่ออนุมัติ, เพื่อตรวจสอบ, หรือเพื่อรับทราบ',
|
) NOT NULL DEFAULT 'FOR_REVIEW ' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้ เช่น เพื่ออนุมัติ,
|
||||||
|
เพื่อตรวจสอบ,
|
||||||
|
หรือเพื่อรับทราบ',
|
||||||
status ENUM(
|
status ENUM(
|
||||||
'SENT',
|
'SENT',
|
||||||
'RECEIVED',
|
'RECEIVED',
|
||||||
@@ -1373,7 +1377,11 @@ VALUES ('DFT', 'Draft', 'ฉบับร่าง', 1),
|
|||||||
-- ตาราง Master สำหรับรหัสผลการอนุมัติ RFA
|
-- ตาราง Master สำหรับรหัสผลการอนุมัติ RFA
|
||||||
CREATE TABLE rfa_approve_codes (
|
CREATE TABLE rfa_approve_codes (
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
|
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
|
||||||
approve_code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสผลการอนุมัติ (เช่น 1A - Approved, 3R - Revise and Resubmit)',
|
approve_code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสผลการอนุมัติ (
|
||||||
|
เช่น 1A - Approved,
|
||||||
|
3R - Revise
|
||||||
|
and Resubmit
|
||||||
|
)',
|
||||||
approve_name VARCHAR(100) NOT NULL COMMENT 'ชื่อผลการอนุมัติ',
|
approve_name VARCHAR(100) NOT NULL COMMENT 'ชื่อผลการอนุมัติ',
|
||||||
description TEXT COMMENT 'คำอธิบาย',
|
description TEXT COMMENT 'คำอธิบาย',
|
||||||
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
|
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
|
||||||
@@ -1390,7 +1398,8 @@ VALUES ('1A', 'Approved by Authority', 10, 1),
|
|||||||
('1N', 'Approved As Note', 12, 1),
|
('1N', 'Approved As Note', 12, 1),
|
||||||
('1R', 'Approved with Remarks', 13, 1),
|
('1R', 'Approved with Remarks', 13, 1),
|
||||||
('3C', 'Consultant Comments', 31, 1),
|
('3C', 'Consultant Comments', 31, 1),
|
||||||
('3R', 'Revise and Resubmit', 32, 1),
|
('3R', 'Revise
|
||||||
|
and Resubmit', 32, 1),
|
||||||
('4X', 'Reject', 40, 1),
|
('4X', 'Reject', 40, 1),
|
||||||
('5N', 'No Further Action', 50, 1);
|
('5N', 'No Further Action', 50, 1);
|
||||||
-- ตาราง "แม่" ของ RFA (มีความสัมพันธ์ 1:N กับ rfa_revisions)
|
-- ตาราง "แม่" ของ RFA (มีความสัมพันธ์ 1:N กับ rfa_revisions)
|
||||||
@@ -1748,9 +1757,12 @@ CREATE TABLE attachments (
|
|||||||
mime_type VARCHAR(100) NOT NULL COMMENT 'ประเภทไฟล์ (เช่น application / pdf)',
|
mime_type VARCHAR(100) NOT NULL COMMENT 'ประเภทไฟล์ (เช่น application / pdf)',
|
||||||
file_size INT NOT NULL COMMENT 'ขนาดไฟล์ (bytes)',
|
file_size INT NOT NULL COMMENT 'ขนาดไฟล์ (bytes)',
|
||||||
is_temporary BOOLEAN DEFAULT TRUE COMMENT 'True = ยังไม่ Commit ลง DB จริง',
|
is_temporary BOOLEAN DEFAULT TRUE COMMENT 'True = ยังไม่ Commit ลง DB จริง',
|
||||||
temp_id VARCHAR(100) NULL COMMENT 'ID ชั่วคราวสำหรับอ้างอิงตอน Upload Phase 1' uploaded_by_user_id INT NOT NULL COMMENT 'ผู้อัปโหลดไฟล์',
|
temp_id VARCHAR(100) NULL COMMENT 'ID ชั่วคราวสำหรับอ้างอิงตอน Upload Phase 1',
|
||||||
|
uploaded_by_user_id INT NOT NULL COMMENT 'ผู้อัปโหลดไฟล์',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่อัปโหลด',
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่อัปโหลด',
|
||||||
expires_at DATETIME NULL COMMENT 'เวลาหมดอายุของไฟล์ Temp' checksum VARCHAR(64) NULL COMMENT 'SHA-256 Checksum' FOREIGN KEY (uploaded_by_user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
expires_at DATETIME NULL COMMENT 'เวลาหมดอายุของไฟล์ Temp',
|
||||||
|
checksum VARCHAR(64) NULL COMMENT 'SHA -256 Checksum',
|
||||||
|
FOREIGN KEY (uploaded_by_user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
|
||||||
-- ตารางเชื่อม correspondences กับ attachments (M:N)
|
-- ตารางเชื่อม correspondences กับ attachments (M:N)
|
||||||
CREATE TABLE correspondence_attachments (
|
CREATE TABLE correspondence_attachments (
|
||||||
@@ -1835,7 +1847,8 @@ CREATE TABLE document_number_counters (
|
|||||||
-- เหตุผล: เพื่อ Validate โครงสร้าง JSON Details ของเอกสารแต่ละประเภทแบบ Centralized
|
-- เหตุผล: เพื่อ Validate โครงสร้าง JSON Details ของเอกสารแต่ละประเภทแบบ Centralized
|
||||||
CREATE TABLE IF NOT EXISTS json_schemas (
|
CREATE TABLE IF NOT EXISTS json_schemas (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
schema_code VARCHAR(100) NOT NULL UNIQUE COMMENT 'รหัส Schema เช่น RFA_DWG_V1, CORR_GENERIC',
|
schema_code VARCHAR(100) NOT NULL UNIQUE COMMENT 'รหัส Schema เช่น RFA_DWG_V1,
|
||||||
|
CORR_GENERIC',
|
||||||
version INT NOT NULL DEFAULT 1 COMMENT 'เวอร์ชันของ Schema',
|
version INT NOT NULL DEFAULT 1 COMMENT 'เวอร์ชันของ Schema',
|
||||||
schema_definition JSON NOT NULL COMMENT 'โครงสร้าง JSON Schema (Standard Format)',
|
schema_definition JSON NOT NULL COMMENT 'โครงสร้าง JSON Schema (Standard Format)',
|
||||||
is_active BOOLEAN DEFAULT TRUE,
|
is_active BOOLEAN DEFAULT TRUE,
|
||||||
@@ -1863,7 +1876,11 @@ CREATE TABLE audit_logs (
|
|||||||
audit_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของ Log',
|
audit_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของ Log',
|
||||||
request_id VARCHAR(100) NULL COMMENT 'Trace ID linking to app logs',
|
request_id VARCHAR(100) NULL COMMENT 'Trace ID linking to app logs',
|
||||||
user_id INT COMMENT 'ผู้กระทำ',
|
user_id INT COMMENT 'ผู้กระทำ',
|
||||||
action VARCHAR(100) NOT NULL COMMENT 'การกระทำ (เช่น rfa.create, correspondence.update, login.success)',
|
action VARCHAR(100) NOT NULL COMMENT 'การกระทำ (
|
||||||
|
เช่น rfa.create,
|
||||||
|
correspondence.update,
|
||||||
|
login.success
|
||||||
|
)',
|
||||||
severity ENUM('INFO', 'WARN', 'ERROR', 'CRITICAL ') DEFAULT 'INFO',
|
severity ENUM('INFO', 'WARN', 'ERROR', 'CRITICAL ') DEFAULT 'INFO',
|
||||||
entity_type VARCHAR(50) COMMENT 'ตาราง / โมดูล (เช่น ''rfa '', ''correspondence '')',
|
entity_type VARCHAR(50) COMMENT 'ตาราง / โมดูล (เช่น ''rfa '', ''correspondence '')',
|
||||||
entity_id VARCHAR(50) COMMENT 'Primary ID ของระเบียนที่ได้รับผลกระทำ',
|
entity_id VARCHAR(50) COMMENT 'Primary ID ของระเบียนที่ได้รับผลกระทำ',
|
||||||
@@ -1882,7 +1899,8 @@ CREATE TABLE notifications (
|
|||||||
message TEXT NOT NULL COMMENT 'รายละเอียดการแจ้งเตือน',
|
message TEXT NOT NULL COMMENT 'รายละเอียดการแจ้งเตือน',
|
||||||
notification_type ENUM('EMAIL', 'LINE', 'SYSTEM ') NOT NULL COMMENT 'ประเภท (EMAIL, LINE, SYSTEM)',
|
notification_type ENUM('EMAIL', 'LINE', 'SYSTEM ') NOT NULL COMMENT 'ประเภท (EMAIL, LINE, SYSTEM)',
|
||||||
is_read BOOLEAN DEFAULT FALSE COMMENT 'สถานะการอ่าน',
|
is_read BOOLEAN DEFAULT FALSE COMMENT 'สถานะการอ่าน',
|
||||||
entity_type VARCHAR(50) COMMENT 'เช่น ''rfa'', ''circulation''',
|
entity_type VARCHAR(50) COMMENT 'เช่น ''rfa '',
|
||||||
|
''circulation ''',
|
||||||
entity_id INT COMMENT 'ID ของเอนทิตีที่เกี่ยวข้อง',
|
entity_id INT COMMENT 'ID ของเอนทิตีที่เกี่ยวข้อง',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
||||||
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
||||||
|
|||||||
@@ -146,6 +146,7 @@
|
|||||||
| last_login_at | TIMESTAMP | NULL | Last successful login timestamp |
|
| last_login_at | TIMESTAMP | NULL | Last successful login timestamp |
|
||||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
|
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
|
||||||
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
|
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
|
||||||
|
| deleted_at | DATETIME | NULL | Deleted at |
|
||||||
|
|
||||||
**Indexes**:
|
**Indexes**:
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ PORT=3000
|
|||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
JWT_SECRET=your_super_secret_key_change_it
|
JWT_SECRET=eebc122aa65adde8c76c6a0847d9649b2b67a06db1504693e6c912e51499b76e
|
||||||
```
|
```
|
||||||
|
|
||||||
### ขั้นตอนต่อไป (Next Steps)
|
### ขั้นตอนต่อไป (Next Steps)
|
||||||
@@ -374,3 +374,144 @@ JWT_EXPIRATION=8h
|
|||||||
2. **Environment:** ควรแยก Secret ระหว่างเครื่อง `Development` และ `Production` ไม่ควรใช้ Key เดียวกัน
|
2. **Environment:** ควรแยก Secret ระหว่างเครื่อง `Development` และ `Production` ไม่ควรใช้ Key เดียวกัน
|
||||||
|
|
||||||
คุณต้องการให้ผมช่วยตั้งค่า `ConfigModule` ใน NestJS เพื่ออ่านค่า `JWT_SECRET` นี้อย่างปลอดภัยพร้อม Validate ว่าห้ามเป็นค่าว่างไหมครับ?
|
คุณต้องการให้ผมช่วยตั้งค่า `ConfigModule` ใน NestJS เพื่ออ่านค่า `JWT_SECRET` นี้อย่างปลอดภัยพร้อม Validate ว่าห้ามเป็นค่าว่างไหมครับ?
|
||||||
|
|
||||||
|
## ได้เลยครับ เรามาลุยงาน **T0.1 Secure Configuration Setup** ตามแผน Backend Plan กันต่อครับ
|
||||||
|
|
||||||
|
เป้าหมายของ Task นี้คือการทำให้ระบบอ่านค่า Environment Variables ได้อย่างถูกต้อง และ **"ต้องไม่ Start"** ถ้าค่า Config สำคัญๆ (เช่น Database Password, JWT Secret) หายไป หรือไม่ถูกต้อง เพื่อความปลอดภัยครับ
|
||||||
|
|
||||||
|
### 1. ติดตั้ง Library ที่จำเป็น
|
||||||
|
|
||||||
|
เราจะใช้ `@nestjs/config` สำหรับจัดการ Config และ `joi` สำหรับตรวจสอบความถูกต้อง (Validation) ครับ
|
||||||
|
|
||||||
|
รันคำสั่งนี้ใน Terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm add @nestjs/config joi
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. สร้าง Validation Schema
|
||||||
|
|
||||||
|
เราจะแยก Logic การตรวจสอบออกมาเป็นไฟล์เฉพาะ เพื่อให้โค้ดเป็นระเบียบครับ
|
||||||
|
|
||||||
|
สร้างไฟล์ใหม่: `src/common/config/env.validation.ts`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// File: src/common/config/env.validation.ts
|
||||||
|
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'),
|
||||||
|
PORT: Joi.number().default(3000),
|
||||||
|
|
||||||
|
// 2. Database Configuration (MariaDB)
|
||||||
|
// ห้ามเป็นค่าว่าง (required)
|
||||||
|
DB_HOST: Joi.string().required(),
|
||||||
|
DB_PORT: Joi.number().default(3306),
|
||||||
|
DB_USERNAME: Joi.string().required(),
|
||||||
|
DB_PASSWORD: Joi.string().required(),
|
||||||
|
DB_DATABASE: Joi.string().required(),
|
||||||
|
|
||||||
|
// 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'),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. อัปเดต `AppModule` ให้ใช้ Validation
|
||||||
|
|
||||||
|
กลับไปแก้ไขไฟล์ `src/app.module.ts` เพื่อนำ Schema ที่เราสร้างมาใช้งานครับ
|
||||||
|
|
||||||
|
```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
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
// 1. Setup Config Module พร้อม Validation
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
isGlobal: true, // เรียกใช้ได้ทั่วทั้ง App ไม่ต้อง import ซ้ำ
|
||||||
|
envFilePath: '.env', // อ่านไฟล์ .env (สำหรับ Dev)
|
||||||
|
validationSchema: envValidationSchema, // ใช้ Schema ที่เราสร้างเพื่อตรวจสอบ
|
||||||
|
validationOptions: {
|
||||||
|
// ถ้ามีค่าไหนไม่ผ่าน Validation ให้ Error และหยุดทำงานทันที
|
||||||
|
abortEarly: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 2. Setup TypeORM (MariaDB)
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
|
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'),
|
||||||
|
autoLoadEntities: true,
|
||||||
|
// synchronize: true เฉพาะตอน Dev เท่านั้น ห้ามใช้บน Prod
|
||||||
|
synchronize: configService.get<string>('NODE_ENV') === 'development',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4\. สร้างไฟล์ Template สำหรับ Docker Override (ตามแผน T0.1)
|
||||||
|
|
||||||
|
ตามแผนงาน เราต้องเตรียมไฟล์ `docker-compose.override.yml.example` เพื่อให้นักพัฒนาคนอื่นรู้ว่าต้อง Inject Secrets อย่างไร โดยไม่เปิดเผยความลับใน `docker-compose.yml` หลัก
|
||||||
|
|
||||||
|
สร้างไฟล์: `docker-compose.override.yml.example` ที่ root project:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Override ค่า Config ของ Service Backend (เมื่อเราสร้าง Container Backend ในอนาคต)
|
||||||
|
backend:
|
||||||
|
environment:
|
||||||
|
# ใส่ Secrets จริงในไฟล์ override นี้ (และห้าม commit ไฟล์นี้)
|
||||||
|
- DB_PASSWORD=secret_password_here
|
||||||
|
- JWT_SECRET=very_long_and_secure_secret_here
|
||||||
|
- NODE_ENV=development
|
||||||
|
|
||||||
|
# Override สำหรับ Database (Local Dev)
|
||||||
|
mariadb:
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=secret_password_here
|
||||||
|
- MYSQL_PASSWORD=secret_password_here
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5\. ทดสอบความปลอดภัย (Validation Check)
|
||||||
|
|
||||||
|
ลองทดสอบว่าระบบ Validation ทำงานถูกต้องหรือไม่ โดยการ **ลบ** หรือ **เปลี่ยนชื่อ** ตัวแปรสำคัญในไฟล์ `.env` (เช่น ลบ `JWT_SECRET`) แล้วลองรัน:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm start:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
**ผลลัพธ์ที่ควรได้:**
|
||||||
|
App **ต้อง Crash** และแสดง Error Message ชัดเจน เช่น:
|
||||||
|
`Config validation error: "JWT_SECRET" is required`
|
||||||
|
|
||||||
|
ถ้าขึ้นแบบนี้แสดงว่าระบบ **Secure Configuration** ของเราทำงานถูกต้องตามแผน T0.1 แล้วครับ\! 🎉
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
**ขั้นตอนถัดไป:**
|
||||||
|
เราจะไปต่อที่ **T0.2 Redis & Queue Infrastructure** เพื่อเตรียมระบบ Caching และ Background Job ไหมครับ?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user