260223:1415 20260223 nextJS & nestJS Best pratices
All checks were successful
Build and Deploy / deploy (push) Successful in 4m44s

This commit is contained in:
admin
2026-02-23 14:15:06 +07:00
parent c90a664f53
commit ef16817f38
164 changed files with 24815 additions and 311 deletions

View File

@@ -3,10 +3,10 @@
---
title: 'Objectives'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related: -
---

View File

@@ -0,0 +1,313 @@
# 4. Access Control & RBAC Matrix (V1.8.0)
---
title: 'Access Control & RBAC Matrix'
version: 1.8.0
status: APPROVED
owner: Nattanin Peancharoen / Development Team
last_updated: 2026-02-23
related:
- specs/02-architecture/02-01-system-architecture.md
- specs/03-implementation/03-02-backend-guidelines.md
- specs/07-database/07-01-data-dictionary-v1.8.0.md
- specs/05-decisions/ADR-005-redis-usage-strategy.md
- specs/05-decisions/ADR-001-unified-workflow-engine.md
references:
- [RBAC Implementation](../../99-archives/ADR-004-rbac-implementation.md)
- [Access Control](../../99-archives/01-04-access-control.md)
---
## 4.1. Overview and Problem Statement
LCBP3-DMS จัดการสิทธิ์การเข้าถึงข้อมูลที่ซับซ้อน ได้แก่:
- **Multi-Organization**: หลายองค์กรใช้ระบบร่วมกัน แต่ต้องแยกข้อมูลตามบริบท
- **Project-Based**: โครงการสามารถมีหลายสัญญาย่อย (Contracts)
- **Hierarchical Permissions**: สิทธิ์ระดับบนสามารถครอบคลุมระดับล่าง
- **Dynamic Roles**: สิทธิ์สามารถปรับเปลี่ยน Role หรือเพิ่ม Role พิเศษได้โดยไม่ต้อง Deploy ระบบใหม่.
Users และ Organizations สามารถเข้าดูหรือแก้ไขเอกสารได้จากสิทธิ์ที่ได้รับ ระบบออกแบบด้วย **4-Level Hierarchical Role-Based Access Control (RBAC)** ដើម្បីรองรับความซับซ้อนนี้.
### Key Requirements
1. User หนึ่งคนสามารถมีหลาย Roles ในหลาย Scopes
2. Permission Inheritance (Global → Organization → Project → Contract)
3. Fine-grained Access Control (เช่น "อนุญาตให้ดู Correspondence เฉพาะใน Project A รวมถึง Contract ภายใต้ Project A เท่านั้น")
4. Performance (Check permission ผ่าน Redis ต้องเร็ว < 10ms)
---
## 4.2. Permission Hierarchy & Enforcement
### 4-Level Scope Hierarchy
การออกแบบสิทธิ์ครอบคลุม Scope ลำดับขั้นดังนี้:
```text
Global (ทั้งระบบ)
├─ Organization (ระดับองค์กร)
│ ├─ Project (ระดับโครงการ)
│ │ └─ Contract (ระดับสัญญา)
│ │
│ └─ Project B
│ └─ Contract B
└─ Organization 2
└─ Project C
```
**Permission Enforcement:**
- เมื่อตรวจสอบสิทธิ์ ระบบจะพิจารณาสิทธิ์จากทุก Level ที่ผู้ใช้มี และใช้สิทธิ์ที่ **"ครอบคลุมที่สุด (Most Permissive)"** ในบริบท (Context) นั้นมาเป็นเกณฑ์.
- *Example*: User A เป็น `Viewer` ในองค์กร (ระดับ Organization Level) แต่มอบหมายหน้าที่ให้เป็น `Editor` ในตำแหน่งของ Project X. เมื่อ User A ดำเนินการในบริบท Context ของ Project X (หรือ Contract ที่อยู่ใต้ Project X), User A จะสามารถทำงานด้วยสิทธิ์ `Editor` ทันที.
---
## 4.3. Role and Scope Summary
| Role | Scope | Description | Key Permissions |
| :------------------- | :----------- | :------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| **Superadmin** | Global | System administrator | Do everything in the system, manage organizations, manage global data |
| **Org Admin** | Organization | Organization administrator | Manage users in the organization, manage roles/permissions within the organization, view organization reports |
| **Document Control** | Organization | Document controller | Add/edit/delete documents, set document permissions within the organization |
| **Editor** | Organization | Document editor | Edit documents that have been assigned to them |
| **Viewer** | Organization | Document viewer | View documents that have access permissions |
| **Project Manager** | Project | Project manager | Manage members in the project (add/delete/assign roles), create/manage contracts in the project, view project reports |
| **Contract Admin** | Contract | Contract administrator | Manage users in the contract, manage roles/permissions within the contract, view contract reports |
### Master Data Management Authority
| Master Data | Manager | Scope |
| :-------------------------------------- | :------------------------------ | :------------------------------ |
| Document Type (Correspondence, RFA) | **Superadmin** | Global |
| Document Status (Draft, Approved, etc.) | **Superadmin** | Global |
| Shop Drawing Category | **Project Manager** | Project (สร้างใหม่ได้ภายในโครงการ) |
| Tags | **Org Admin / Project Manager** | Organization / Project |
| Custom Roles | **Superadmin / Org Admin** | Global / Organization |
| Document Numbering Formats | **Superadmin / Admin** | Global / Organization |
---
## 4.4. Onboarding Workflow
- **4.4.1. Create Organization**
- **Superadmin** สร้าง Organization ใหม่ (e.g. Company A)
- **Superadmin** แต่งตั้ง User อย่างน้อย 1 คน ให้เป็น **Org Admin** หรือ **Document Control**
- **4.4.2. Add Users to Organization**
- **Org Admin** เพิ่ม users (`Editor`, `Viewer`) เข้าสู่งองค์กร
- **4.4.3. Assign Users to Project**
- **Project Manager** เชิญ/กำหนดผู้ใช้เข้าสู่ Project. ในขั้นตอนนี้จะกำหนด **Project Role**
- **4.4.4. Assign Users to Contract**
- **Contract Admin** เลือก users จาก Project และมอบหมายหน้าที่เจาะจงใน Contract ขั้นตอนนี้จะกำหนด **Contract Role**
- **4.4.5. Security Onboarding**
- บังคับ Users to change password เป็นครั้งแรก
- ฝึกอบรม (Security awareness training) สำหรับ users ที่มีสิทธิ์สูงระดับแอดมิน.
- บันทึก Audit Log ทุกเหตุการณ์เกี่ยวกับการมอบหมาย/ตั้งค่า Permissions.
---
## 4.5. Implementation Details
### 4.5.1 Database Schema (RBAC Tables)
```sql
-- Role Definitions with Scope
CREATE TABLE roles (
role_id INT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(100) NOT NULL,
scope ENUM('Global', 'Organization', 'Project', 'Contract') NOT NULL,
description TEXT,
is_system BOOLEAN DEFAULT FALSE
);
-- Granular Permissions
CREATE TABLE permissions (
permission_id INT PRIMARY KEY AUTO_INCREMENT,
permission_name VARCHAR(100) NOT NULL UNIQUE,
description TEXT,
module VARCHAR(50),
-- Scope Reference ENUM includes CONTRACT
scope_level ENUM('GLOBAL', 'ORG', 'PROJECT', 'CONTRACT')
);
-- Role -> Permissions Mapping
CREATE TABLE role_permissions (
role_id INT,
permission_id INT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(permission_id) ON DELETE CASCADE
);
-- User Role Assignments with Context Map
CREATE TABLE user_assignments (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
role_id INT NOT NULL,
organization_id INT NULL,
project_id INT NULL,
contract_id INT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE,
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE CASCADE,
-- ควบคุมโครงสร้าง: ไม่ให้ระบุ Scope เลื่อนลอยข้ามขั้นต้องมีชั้นเดียวชัดเจน
CONSTRAINT chk_scope CHECK (
(organization_id IS NOT NULL AND project_id IS NULL AND contract_id IS NULL) OR
(organization_id IS NULL AND project_id IS NOT NULL AND contract_id IS NULL) OR
(organization_id IS NULL AND project_id IS NULL AND contract_id IS NOT NULL) OR
(organization_id IS NULL AND project_id IS NULL AND contract_id IS NULL)
)
);
```
### 4.5.2 Setup CASL Ability Rules
เพื่อให้ **"การสืบทอดสิทธิ์ (Inheritance Logic)"** ทำงานได้ถูกต้อง เช่น บทบาทระดับ `Project Manager` ให้แผ่คลุมไปถึงทรัพยากรระดับ `Contract` ด้านในด้วย (Logic `project_id -> all embedded contracts`).
```typescript
// ability.factory.ts
import { AbilityBuilder, PureAbility } from '@casl/ability';
export type AppAbility = PureAbility<[string, any]>;
@Injectable()
export class AbilityFactory {
async createForUser(user: User): Promise<AppAbility> {
const { can, cannot, build } = new AbilityBuilder<AppAbility>(PureAbility);
const assignments = await this.getUserAssignments(user.user_id);
for (const assignment of assignments) {
const role = await this.getRole(assignment.role_id);
const permissions = await this.getRolePermissions(role.role_id);
for (const permission of permissions) {
// e.g. 'correspondence.create', 'project.view'
const [subject, action] = permission.permission_name.split('.');
// Apply Scope conditions based on the Role's specified scope level
switch (role.scope) {
case 'Global':
// ได้รับสิทธิ์กับองค์ประกอบทั้งหมด
can(action, subject);
break;
case 'Organization':
// อนุญาตการ Action ทั้งในองค์กร และโปรเจกต์ภายใต้องค์กร
can(action, subject, { organization_id: assignment.organization_id });
// Advanced Case: In some queries mapped to Projects/Contracts, support fallback checks
// can(action, subject, { '__orgIdFallback': assignment.organization_id });
break;
case 'Project':
// สืบทอดสิทธิ์ไปยัง Project ID นั้นๆ เสมอ และสิทธิ์ครอบคลุมถึงทุก Contracts ที่ผูกกับ Project นี้
can(action, subject, { project_id: assignment.project_id });
break;
case 'Contract':
// จำกัดเฉพาะใน Contract นั้น ตรงเป้าหมาย
can(action, subject, { contract_id: assignment.contract_id });
break;
}
}
}
return build();
}
}
```
### 4.5.3 Token Management & Redis Permission Cache
- **Payload Optimization**: JWT Access Token ให้เก็บเฉพาะ `userId` และ ข้อมูล Sessions ขั้นต้น. โครงสร้าง Permissions List ปริมาณมากจะ**ไม่อยู่ใน Token**.
- **Permission Caching**: นำโครงสร้างสิทธิ์ทั้งหมด (Ability Rules ที่ประกอบแล้วจาก 4.5.2) ไป Cache ไว้เป็น Key ภายใต้ฐานข้อมูล **Redis** โดยคงระยะการตั้ง TTL ประมาณ 30 นาที `1800` วินาที. ลดขนาด Payload ลง และเพื่อเป้าหมาย Performance ที่ `< 10ms`.
### 4.5.4 Permission Guard Enforcement (NestJS)
```typescript
// permission.guard.ts
@Injectable()
export class PermissionGuard implements CanActivate {
constructor(
private reflector: Reflector,
private abilityFactory: AbilityFactory,
private redis: Redis
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const permission = this.reflector.get<string>('permission', context.getHandler());
if (!permission) return true; // Route without specific permission requirements
const request = context.switchToHttp().getRequest();
const user = request.user;
// Check Redis cache first
const cacheKey = `user:${user.user_id}:permissions`;
let abilityRules = await this.redis.get(cacheKey);
if (!abilityRules) {
const newAbility = await this.abilityFactory.createForUser(user);
abilityRules = newAbility.rules;
// Store in Cache (1800ms TTL)
await this.redis.set(cacheKey, JSON.stringify(abilityRules), 'EX', 1800);
} else {
abilityRules = JSON.parse(abilityRules);
}
const ability = new PureAbility(abilityRules);
const [action, subject] = permission.split('.');
// Evaluate mapped payload / resource parameters directly into CASL engine
const resource = { ...request.params, ...request.body };
return ability.can(action, subject, resource);
}
}
```
Controller Example Usage:
```typescript
@Controller('correspondences')
@UseGuards(JwtAuthGuard, PermissionGuard)
export class CorrespondenceController {
@Post()
@RequirePermission('correspondence.create')
async create(@Body() dto: CreateCorrespondenceDto) {
// Accessible only when CASL Evaluate "correspondence.create" successfully fits the parameters limits (Project/Contract scope check)
}
}
```
---
## 4.6. Cache Invalidation Strategy
เพื่อให้ระบบ Security Update ได้รวดเร็วและปลอดภัย ต้องมีกลไกสั่งรีเซ็ตสิทธิ์ (Invalidation):
1. **When Role Assignemnt Modified**: เมื่อช้อมูลในตาราง `user_assignments` (เช่นลบ/เพิ่ม user ระดับโปรเจกต์) หรือตาราง `role_permissions` (สลับสิทธิ์ของกลุ่ม) เกิดการแก้ไขในฐานข้อมูลแล้ว.
2. **Execute Invalidation**: API Services ต้องทำการลบ Cache เก่าที่ฝั่งขัดข้องทันที ผ่านคำสั่ง `DEL user:{user_id}:permissions` ณ ฝั่ง Redis.
3. ระบบจะทำงานโปรโตซ้ำ (Cold Boot) เข้ามาหยิบ DB -> สร้าง CASL Factory ใหม่ ใน First API Request อีกครั้งในทันที.
---
## 4.7. Appendix: ADR-004 Decision History & Justification
ส่วนอ้างอิงและประวัติศาสตร์การตัดสินใจพิจารณาในอดีต (Reference) ก่อนการนำมาปรับใช้ร่าง Architecture ฉบับ V1.8.0.
### Considered Options Before Version 1.5.0
1. **Option 1**: Simple Role-Based (No Scope)
- *Pros*: Very simple implementation, Easy to understand
- *Cons*: ไม่รองรับ Multi-organization, Superadmin เห็นข้อมูลองค์กรอื่นมั่วข้ามกลุ่ม
2. **Option 2**: Organization-Only Scope
- *Pros*: แยกข้อมูลระหว่าง Organizations ได้ชัดเจน
- *Cons*: ไม่รองรับระดับ Sub-level Permissions (Project/Contract) ไม่เพียงพอกับ Business Rule.
3. **Option 3**: **4-Level Hierarchical RBAC (Selected)**
- *Pros*: ครอบคลุม Use Case สูงสุด (Maximum Flexibility), รองรับ Hierarchy สืบทอดสิทธิ์ (Inheritance), ขอบเขตจำกัดข้อมูลอย่างรัดกุมระดับ Contract (Data Isolation).
- *Cons*: Complexity ทางด้านการ Implement, Invalidate Caching หางานให้ฝั่ง Operations, Developer Learning Curve.
**Decision Rationale:**
เลือกแนวทางที่ 3 รองรับความต้องการของ Construction Projects ที่มีการแบ่งกลุ่มรับเหมาช่วงย่อยระดับ Contracts ต่อเนื่อง (Future proof). แก้ไขปัญหา Performance Cons ด้วยแนวคิดการประจุ Redis Caching ข้ามขั้ว และล้าง Invalidation เฉพาะเมื่อ Triggering Database Updates (อ้างอิงหัวข้อ 4.6).

View File

@@ -0,0 +1,786 @@
# 3.11 Document Numbering Management & Implementation (V1.8.0)
---
title: 'Specifications & Implementation Guide: Document Numbering System'
version: 1.8.0
status: draft
owner: Nattanin Peancharoen / Development Team
last_updated: 2026-02-23
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/03-implementation/03-02-backend-guidelines.md
- specs/04-operations/04-08-document-numbering-operations.md
- specs/07-database/07-01-data-dictionary-v1.8.0.md
- specs/05-decisions/ADR-002-document-numbering-strategy.md
Clean Version v1.8.0 Scope of Changes:
- รวม Functional Requirements เข้ากับ Implementation Guide
- เลือกใช้ Single Numbering System (Option A) `document_number_counters` เป็น Authoritative Counter
- เพิ่ม Idempotency Key, Reservation (Two-Phase Commit)
- Number State Machine, Pattern Validate UTF-8, Cancellation Rule (Void/Replace)
references:
- [Document Numbering](../../99-archives/01-03.11-document-numbering.md)
- [Document Numbering](../../99-archives/03-04-document-numbering.md)
---
> **📖 เอกสารฉบับนี้เป็นการรวมรายละเอียดจาก `01-03.11-document-numbering.md` และ `03-04-document-numbering.md` ให้อยู่ในฉบับเดียวสำหรับใช้อ้างอิงการออกแบบเชิง Functional และการพัฒนา Technology Component**
---
## 1. Overview & วัตถุประสงค์ (Purpose)
ระบบ Document Numbering สำหรับสร้างเลขที่เอกสารอัตโนมัติที่มีความเป็นเอกลักษณ์ (unique) และสามารถติดตามได้ (traceable) สำหรับเอกสารทุกประเภทในระบบ LCBP3-DMS
### 1.1 Requirements Summary & Scope
- **Auto-generation**: สร้างเลขที่อัตโนมัติ ไม่ซ้ำ (Unique) ยืดหยุ่น
- **Configurable Templates**: รองรับแบบฟอร์มกำหนดค่า สำหรับโปรเจกต์ ประเภทเอกสาร ฯลฯ
- **Uniqueness Guarantee**: การันตี Uniqueness ใน Concurrent Environment (Race Conditions)
- **Manual override**: รองรับการ Import หรือ Override สำหรับเอกสารเก่า
- **Cancelled/Void Handling**: ไม่นำหมายเลขที่ใช้ หรือ Cancel/Void กลับมาใช้ใหม่ (No reuse)
- **Audit Logging**: บันทึกเหตุการณ์ Operation ทั้งหมดอย่างละเอียดครบถ้วน 7 ปี
### 1.2 Technology Stack
| Component | Technology |
| ----------------- | -------------------- |
| Backend Framework | NestJS 10.x |
| ORM | TypeORM 0.3.x |
| Database | MariaDB 11.8 |
| Cache/Lock | Redis 7.x + Redlock |
| Message Queue | BullMQ |
| Monitoring | Prometheus + Grafana |
### 1.3 Architectural Decision (AD-DN-001)
ระบบเลือกใช้ **Option A**:
- `document_number_counters` เป็น Core / Authoritative Counter System.
- `document_numbering_configs` (หรือ `document_number_formats`) ใช้เฉพาะกำหนดระเบียบเลข (Template format) และ Permission.
- เหตุผล: ลดความซ้ำซ้อน, ป้องกัน Counter Mismatch, Debug ง่าย, Ops เคลียร์.
---
## 2. Business Rules & Logic
### 2.1 Counter Logic & Reset Policy
การนับเลขจะแยกตาม **Counter Key** ที่ประกอบด้วยหลายส่วน ซึ่งขึ้นกับประเภทเอกสาร
* `(project_id, originator_organization_id, recipient_organization_id, correspondence_type_id, sub_type_id, rfa_type_id, discipline_id, reset_scope)`
| Document Type | Reset Policy | Counter Key Format / Details |
| ---------------------------------- | ------------------ | ------------------------------------------------------------------------------ |
| Correspondence (LETTER, MEMO, RFI) | Yearly reset | `(project_id, originator, recipient, type_id, 0, 0, 0, 'YEAR_2025')` |
| Transmittal | Yearly reset | `(project_id, originator, recipient, type_id, sub_type_id, 0, 0, 'YEAR_2025')` |
| RFA | No reset | `(project_id, originator, 0, type_id, 0, rfa_type_id, discipline_id, 'NONE')` |
| Drawing | Separate Namespace | `DRAWING::<project>::<contract>` (ไม่ได้ใช้ counter rules เดียวกัน) |
### 2.2 Format Templates & Supported Tokens
**Supported Token Types**:
* `{PROJECT}`: รหัสโครงการ (เช่น `LCBP3`)
* `{ORIGINATOR}`: รหัสองค์กรส่ง (เช่น `คคง.`)
* `{RECIPIENT}`: รหัสองค์กรรับหลัก (เช่น `สคฉ.3`) *ไม่ใช้กับ RFA
* `{CORR_TYPE}`: รหัสประเภทเอกสาร (เช่น `RFA`, `LETTER`)
* `{SUB_TYPE}`: ประเภทย่อย (สำหรับ Transmittal)
* `{RFA_TYPE}`: รหัสประเภท RFA (เช่น `SDW`, `RPT`)
* `{DISCIPLINE}`: รหัสสาขาวิชา (เช่น `STR`, `CV`)
* `{SEQ:n}`: Running Number ตามจำนวนหลัก `n` ลบด้วยศูนย์นำหน้า
* `{YEAR:B.E.}`, `{YEAR:A.D.}`, `{YYYY}`, `{YY}`, `{MM}`: สัญลักษณ์บอกเวลาและปฏิทิน.
* `{REV}`: Revision Code (เช่น `A`, `B`)
**Token Validation Grammar**
```ebnf
TEMPLATE := TOKEN ("-" TOKEN)*
TOKEN := SIMPLE | PARAM
SIMPLE := "{PROJECT}" | "{ORIGINATOR}" | "{RECIPIENT}" | "{CORR_TYPE}" | "{DISCIPLINE}" | "{RFA_TYPE}" | "{REV}" | "{YYYY}" | "{YY}" | "{MM}"
PARAM := "{SEQ:" DIGIT+ "}"
DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
```
### 2.3 Character & Format Rules (BR-DN-002, BR-DN-003)
- Document number **must be printable UTF8** (Thai, English, Numbers, `-`, `_`, `.`). ไม่อนุญาต Control characters, newlines.
- ต้องยาวระหว่าง 10 ถึง 50 ตัวอักษร
- ต้องกำหนด Token `{SEQ:n}` ลำดับที่ exactly once. ห้ามเป็น Unknown token ใดๆ.
### 2.4 Number State Machine & Idempotency
1. **States Lifecycle**: `RESERVED` (TTL 5 mins) → `CONFIRMED``VOID` / `CANCELLED`. Document ที่ Confirmed แล้วสามารถมีพฤติกรรม VOID ในอนาคตเพื่อแทนที่ด้วยเอกสารใหม่ได้ การ Request จะได้ Document ชุดใหม่ทดแทนต่อเนื่องทันที. ห้าม Reuse เลขเดิมโดยสิ้นเชิง.
2. **Idempotency Key Support**: ทุก API ในการ Generator จำเป็นต้องระบุ HTTP Header `Idempotency-Key` ป้องกันระบบสร้างเลขเบิ้ล (Double Submission). ถ้าระบบได้รับคู่ Request + Key ชุดเดิม จะ Response เลขที่เอกสารเดิม.
---
## 3. Functional Requirements
* **FR-DN-001 (Sequential Auto-generation)**: ระบบตอบกลับความรวดเร็วที่ระดับ < 100ms โดยที่ทน Concurrent ได้ ทนต่อปัญหา Duplicate
* **FR-DN-002 (Configurable)**: สามารถเปลี่ยนรูปแบบเทมเพลตผ่านระบบ Admin ได้ด้วยการ Validation ก่อน حفظ
* **FR-DN-003 (Scope-based sequences)**: รองรับ Scope แยกระดับเอกสาร
* **FR-DN-004 (Manual Override)**: ระบบรองรับการตั้งเลขด้วยตนเองสำหรับ Admin Level พร้อมระบุเหตุผลผ่าน Audit Trails เป็นหลักฐานสำคัญ (Import Legacy, Correction)
* **FR-DN-005 (Bulk Import)**: รับเข้าระบบจากไฟล์ Excel/CSV และแก้ไข Counters Sequence ต่อเนื่องพร้อมเช็ค Duplicates.
* **FR-DN-006 (Skip Cancelled)**: ไม่ให้สิทธิ์ดึงเอกสารยกเลิกใช้งานซ้ำ. คงรักษาสภาพ Audit ต่อไป.
* **FR-DN-007 (Void & Replace)**: เปลี่ยน Status เลขเป็น VOID ไม่มีการ Delete. Reference Link เอกสารใหม่ที่เกิดขึ้นทดแทนอิงตาม `voided_from_id`.
* **FR-DN-008 (Race Condition Prevention)**: จัดการ Race Condition (RedLock + Database Pessimistic Locking) เพื่อ Guarantee zero duplicate numbers ที่ Load 1000 req/s.
* **FR-DN-009 (Two-phase Commit)**: แบ่งการออกเลขเป็นช่วง Reserve 5 นาที แล้วค่อยเรียก Confirm หลังจากได้เอกสารที่ Submit เรียบร้อย (ลดอาการเลขหาย/เลขฟันหลอที่ยังไม่ถูกใช้).
* **FR-DN-010/011 (Audit / Metrics Alerting)**: Audit ทุกๆ Step / Transaction ไว้ใน DB ให้เสิร์ชได้เกิน 7 ปี. ส่งแจ้งเตือนถ้า Sequence เริ่มเต็ม (เกิน 90%) หรือ Rate error เริ่มสูง.
---
## 4. Module System & Code Architecture
### 4.1 Folder Structure
```
backend/src/modules/document-numbering/
├── document-numbering.module.ts
├── controllers/ # document-numbering.controller.ts, admin.controller.ts, metrics.controller.ts
├── services/ # Main orchestration (document-numbering.service.ts), lock, counter, reserve, format, audit
├── entities/ # DB Entities mappings
├── dto/ # DTOs
├── validators/ # template.validator.ts
├── guards/ # manual-override.guard.ts
└── jobs/ # counter-reset.job.ts (Cron)
```
### 4.2 Sequence Process Architecture
**1. Number Generation Process Diagram**
```mermaid
sequenceDiagram
participant C as Client
participant S as NumberingService
participant L as LockService
participant CS as CounterService
participant DB as Database
participant R as Redis
C->>S: generateDocumentNumber(dto)
S->>L: acquireLock(counterKey)
L->>R: REDLOCK acquire
R-->>L: lock acquired
L-->>S: lock handle
S->>CS: incrementCounter(counterKey)
CS->>DB: BEGIN TRANSACTION
CS->>DB: SELECT FOR UPDATE
CS->>DB: UPDATE last_number
CS->>DB: COMMIT
DB-->>CS: newNumber
CS-->>S: sequence
S->>S: formatNumber(template, seq)
S->>L: releaseLock()
L->>R: REDLOCK release
S-->>C: documentNumber
```
**2. Two-Phase Commit Pattern (Reserve / Confirm)**
```mermaid
sequenceDiagram
participant C as Client
participant RS as ReservationService
participant SS as SequenceService
participant R as Redis
Note over C,R: Phase 1: Reserve
C->>RS: reserve(documentType)
RS->>SS: getNextSequence()
SS-->>RS: documentNumber
RS->>R: SETEX reservation:{token} (TTL: 5min)
RS-->>C: {token, documentNumber, expiresAt}
Note over C,R: Phase 2: Confirm
C->>RS: confirm(token)
RS->>R: GET reservation:{token}
R-->>RS: reservationData
RS->>R: DEL reservation:{token}
RS-->>C: documentNumber (confirmed)
```
### 4.3 Lock Service (Redis Redlock Example)
```typescript
@Injectable()
export class DocumentNumberingLockService {
constructor(@InjectRedis() private readonly redis: Redis) {
this.redlock = new Redlock([redis], { driftFactor: 0.01, retryCount: 5, retryDelay: 100, retryJitter: 50 });
}
async acquireLock(counterKey: CounterKey): Promise<Redlock.Lock> {
const lockKey = this.buildLockKey(counterKey);
return await this.redlock.acquire([lockKey], /* ttl */ 5000); // 5 sec retention
}
}
```
### 4.4 Counter Service & Transaction Strategy (Optimistic Example)
```typescript
async incrementCounter(counterKey: CounterKey): Promise<number> {
const MAX_RETRIES = 2;
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
return await this.dataSource.transaction(async (manager) => {
const counter = await manager.findOne(DocumentNumberCounter, { /* rules */ });
if (!counter) {
// Insert base 1
return 1;
}
counter.lastNumber += 1;
await manager.save(counter); // Trigger Optimistic Version Check
return counter.lastNumber;
});
} catch (error) {
// Loop if version mismatch
}
}
}
```
---
## 5. Database Schema Details
### 5.1 Format Storage & Counters
```sql
-- Format Template Configuration
CREATE TABLE document_number_formats (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
correspondence_type_id INT NULL,
format_template VARCHAR(100) NOT NULL,
reset_sequence_yearly TINYINT(1) DEFAULT 1,
UNIQUE KEY idx_unique_project_type (project_id, correspondence_type_id),
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
-- Active Sequences
CREATE TABLE document_number_counters (
project_id INT NOT NULL,
correspondence_type_id INT NULL,
originator_organization_id INT NOT NULL,
recipient_organization_id INT NOT NULL DEFAULT 0,
sub_type_id INT DEFAULT 0,
rfa_type_id INT DEFAULT 0,
discipline_id INT DEFAULT 0,
reset_scope VARCHAR(20) NOT NULL,
last_number INT DEFAULT 0 NOT NULL,
version INT DEFAULT 0 NOT NULL,
PRIMARY KEY (... 8 fields combination ...),
INDEX idx_counter_lookup (project_id, correspondence_type_id, reset_scope)
);
```
### 5.2 Two-Phase Commit Reservations
```sql
CREATE TABLE document_number_reservations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
token VARCHAR(36) NOT NULL UNIQUE COMMENT 'UUID v4',
document_number VARCHAR(100) NOT NULL UNIQUE,
status ENUM('RESERVED', 'CONFIRMED', 'CANCELLED', 'VOID') NOT NULL DEFAULT 'RESERVED',
document_id INT NULL COMMENT 'Link after confirmed',
expires_at DATETIME(6) NOT NULL,
... Context fields ...
);
```
### 5.3 Audit Trails & Error Logs
```sql
CREATE TABLE document_number_audit (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
document_number VARCHAR(100) NOT NULL,
operation ENUM('RESERVE', 'CONFIRM', 'CANCEL', 'MANUAL_OVERRIDE', 'VOID', 'GENERATE') NOT NULL,
counter_key JSON NOT NULL,
is_success BOOLEAN DEFAULT TRUE,
lock_wait_ms INT,
... Extraneous Auditing fields ...
);
CREATE TABLE document_number_errors (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
error_type ENUM('LOCK_TIMEOUT','VERSION_CONFLICT','DB_ERROR','REDIS_ERROR','VALIDATION_ERROR','SEQUENCE_EXHAUSTED') NOT NULL,
stack_trace TEXT,
context_data JSON
);
```
---
## 6. Endpoints & API Definitions
| Endpoint | Method | Permission | Meaning |
| -------------------------------------------- | -------- | ------------------------ | ------------------------------------------ |
| `/document-numbering/preview` | POST | `correspondence.read` | Preview Formats |
| `/document-numbering/reserve` | POST | `correspondence.create` | Reserve Token & Logic Number (2PC) |
| `/document-numbering/confirm` | POST | `correspondence.create` | Confirm Reservation (2PC) |
| `/document-numbering/cancel` | POST | `correspondence.create` | Manual or System Cancel Reservation |
| `/admin/document-numbering/manual-override` | POST | `system.manage_settings` | Inject / Legacy specific number generation |
| `/admin/document-numbering/void-and-replace` | POST | `system.manage_settings` | Replace document marking old logic as VOID |
| `/admin/document-numbering/bulk-import` | POST | `system.manage_settings` | Batch Migration Numbers from legacy |
| `/admin/document-numbering/templates` | GET/POST | `system.manage_settings` | Setting Pattern Configurations |
---
## 7. Security, Error Handling & Concurrency Checklists
**Fallback Strategy for Database Lock Failures**:
1. System attempt to acquire `Redlock`.
2. Redis Down? → **Fallback DB-only Lock** Transaction Layer.
3. Redis Online but Timeout `>3 Times`? → Return HTTP 503 (Exponential Backoff).
4. Save Failed via TypeORM Version Confilct? → Retry Loop `2 Times`, otherwise Return 409 Conflict.
**Rate Limiting Profiles**:
* Single User Threshold: `10 requests/minute`.
* Specific Request IP: `50 requests/minute`.
**Authorization Policies**:
* `Super Admin` เท่านั้นที่บังคับสั่ง `Reset Counter` ให้เริ่มนับศูนย์ได้เมื่อฉุกเฉิน.
* กฎ Audit Log System ระบุชัดเจนว่าต้อง Retain Information ไม่ต่ำกว่า 7 ปี.
## 8. Monitoring / Observability (Prometheus + Grafana)
| Condition Event | Prometheus Counter Target | Severity Reaction |
| ---------------------- | -------------------------------- | ----------------------------------------------------------------- |
| Utilization `>95%` | `numbering_sequence_utilization` | 🔴 **CRITICAL** (PagerDuty/Slack). Limit Maximum sequence reached. |
| Redis Downtime `>1M` | Health System | 🔴 **CRITICAL** (PagerDuty/Slack) |
| Lock Latency p95 `>1s` | `numbering_lock_wait_seconds` | 🟡 **WARNING** (Slack). Redis connection struggling. |
| Error Rate Burst | `numbering_lock_failures_total` | 🟡 **WARNING** (Slack). Need investigation logs check |
---
## 9. Testing & Rollout Migration Strategies
### 9.1 Test Approach Requirements
* **Unit Tests**: Template Tokens Validations, Error handling retry, Optimistic locking checks.
* **Concurrency Integration Test**: Assert >1000 requests without double generating numbers simultaneously per `project_id`.
* **E2E Load Sequence Flow**: Mocking bulk API loads over 500 requests per seconds via CI/CD load pipeline.
### 9.2 Data Rollout Plan (Legacy Legacy Import)
1. Dump out existing Sequence numbers (Extracted Document Strings).
2. Write validation script for Sequence Max Counts.
3. Import to Table `document_number_counters` as Manual Override API Method context (`FR-DN-004`).
4. Re-Verify next sequence logic output `+1` count seamlessly integrates to `nextNumber()`.
---
**Best Practices Checklist**
-**DO**: Two-Phase Commit (`Reserve` + `Confirm`) ให้เป็น Routine System Concept.
-**DO**: DB Fallback เมื่อ Redis ดาวน์. ให้ Availability สูงสุด ไม่หยุดทำงาน.
-**DO**: ข้ามเลขที่ยกเลิกทั้งหมดห้ามมีการ Re-Use เด็ดขาด ไม่ว่าเจตนาใดๆ.
-**DON'T**: ไม่แก้ Sequence จาก DB Console ตรงๆ โดยเด็ดขาด.
-**DON'T**: ลืม Validate format หรือ Tokens แปลกๆ ในระบบ Template (ต้อง Check Grammar ตลอดไป).
-**DON'T**: ลืมเขียน Idempotency-Key สำหรับ Request.
---
**Document Version**: 1.8.0
**Created By**: Development Team
**End of Document**
---
## 10. Operations & Infrastructure Guidelines
### 1. Performance Requirements
### 1.1. Response Time Targets
| Metric | Target | Measurement |
| ---------------- | -------- | ------------------------ |
| 95th percentile | ≤ 2 วินาที | ตั้งแต่ request ถึง response |
| 99th percentile | ≤ 5 วินาที | ตั้งแต่ request ถึง response |
| Normal operation | ≤ 500ms | ไม่มี retry |
### 1.2. Throughput Targets
| Load Level | Target | Notes |
| -------------- | ----------- | ------------------------ |
| Normal load | ≥ 50 req/s | ใช้งานปกติ |
| Peak load | ≥ 100 req/s | ช่วงเร่งงาน |
| Burst capacity | ≥ 200 req/s | Short duration (< 1 min) |
### 1.3. Availability SLA
- **Uptime**: ≥ 99.5% (excluding planned maintenance)
- **Maximum downtime**: ≤ 3.6 ชั่วโมง/เดือน (~ 8.6 นาที/วัน)
- **Recovery Time Objective (RTO)**: ≤ 30 นาที
- **Recovery Point Objective (RPO)**: ≤ 5 นาที
### 2. Infrastructure Setup
### 2.1. Database Configuration
#### MariaDB Connection Pool
```typescript
// ormconfig.ts
{
type: 'mysql',
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
extra: {
connectionLimit: 20, // Pool size
queueLimit: 0, // Unlimited queue
acquireTimeout: 10000, // 10s timeout
retryAttempts: 3,
retryDelay: 1000
}
}
```
#### High Availability Setup
```yaml
# docker-compose.yml
services:
mariadb-master:
image: mariadb:11.8
environment:
MYSQL_REPLICATION_MODE: master
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- mariadb-master-data:/var/lib/mysql
networks:
- backend
mariadb-replica:
image: mariadb:11.8
environment:
MYSQL_REPLICATION_MODE: slave
MYSQL_MASTER_HOST: mariadb-master
MYSQL_MASTER_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- mariadb-replica-data:/var/lib/mysql
networks:
- backend
```
### 2.2. Redis Configuration
#### Redis Sentinel for High Availability
```yaml
# docker-compose.yml
services:
redis-master:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-master-data:/data
networks:
- backend
redis-replica:
image: redis:7-alpine
command: redis-server --replicaof redis-master 6379 --appendonly yes
volumes:
- redis-replica-data:/data
networks:
- backend
redis-sentinel:
image: redis:7-alpine
command: >
redis-sentinel /etc/redis/sentinel.conf
--sentinel monitor mymaster redis-master 6379 2
--sentinel down-after-milliseconds mymaster 5000
--sentinel failover-timeout mymaster 10000
networks:
- backend
```
#### Redis Connection Pool
```typescript
// redis.config.ts
import IORedis from 'ioredis';
export const redisConfig = {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
maxRetriesPerRequest: 3,
enableReadyCheck: true,
lazyConnect: false,
poolSize: 10,
retryStrategy: (times: number) => {
if (times > 3) {
return null; // Stop retry
}
return Math.min(times * 100, 3000);
},
};
```
### 2.3. Load Balancing
#### Nginx Configuration
```nginx
# nginx.conf
upstream backend {
least_conn; # Least connections algorithm
server backend-1:3000 max_fails=3 fail_timeout=30s weight=1;
server backend-2:3000 max_fails=3 fail_timeout=30s weight=1;
server backend-3:3000 max_fails=3 fail_timeout=30s weight=1;
keepalive 32;
}
server {
listen 80;
server_name api.lcbp3.local;
location /api/v1/document-numbering/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
```
#### Docker Compose Scaling
```yaml
# docker-compose.yml
services:
backend:
image: lcbp3-backend:latest
deploy:
replicas: 3
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
environment:
NODE_ENV: production
DB_POOL_SIZE: 20
networks:
- backend
```
### 4. Troubleshooting Runbooks
### 4.1. Scenario: Redis Unavailable
**Symptoms:**
- Alert: `RedisUnavailable`
- System falls back to DB-only locking
- Performance degraded 30-50%
**Action Steps:**
1. **Check Redis status:**
```bash
docker exec lcbp3-redis redis-cli ping
# Expected: PONG
```
2. **Check Redis logs:**
```bash
docker logs lcbp3-redis --tail=100
```
3. **Restart Redis (if needed):**
```bash
docker restart lcbp3-redis
```
4. **Verify failover (if using Sentinel):**
```bash
docker exec lcbp3-redis-sentinel redis-cli -p 26379 SENTINEL masters
```
5. **Monitor recovery:**
- Check metric: `docnum_redis_connection_status` returns to 1
- Check performance: P95 latency returns to normal (< 500ms)
### 4.2. Scenario: High Lock Failure Rate
**Symptoms:**
- Alert: `HighLockFailureRate` (> 10%)
- Users report "ระบบกำลังยุ่ง" errors
**Action Steps:**
1. **Check concurrent load:**
```bash
# Check current request rate
curl http://prometheus:9090/api/v1/query?query=rate(docnum_generation_duration_ms_count[1m])
```
2. **Check database connections:**
```sql
SHOW PROCESSLIST;
-- Look for waiting/locked queries
```
3. **Check Redis memory:**
```bash
docker exec lcbp3-redis redis-cli INFO memory
```
4. **Scale up if needed:**
```bash
# Increase backend replicas
docker-compose up -d --scale backend=5
```
5. **Check for deadlocks:**
```sql
SHOW ENGINE INNODB STATUS;
-- Look for LATEST DETECTED DEADLOCK section
```
### 4.3. Scenario: Slow Performance
**Symptoms:**
- Alert: `SlowDocumentNumberGeneration`
- P95 > 2 seconds
**Action Steps:**
1. **Check database query performance:**
```sql
SELECT * FROM document_number_counters USE INDEX (idx_counter_lookup)
WHERE project_id = 2 AND correspondence_type_id = 6 AND current_year = 2025;
-- Check execution plan
EXPLAIN SELECT ...;
```
2. **Check for missing indexes:**
```sql
SHOW INDEX FROM document_number_counters;
```
3. **Check Redis latency:**
```bash
docker exec lcbp3-redis redis-cli --latency
```
4. **Check network latency:**
```bash
ping mariadb-master
ping redis-master
```
5. **Review slow query log:**
```bash
docker exec lcbp3-mariadb-master cat /var/log/mysql/slow.log
```
### 4.4. Scenario: Version Conflicts
**Symptoms:**
- High retry count
- Users report "เลขที่เอกสารถูกเปลี่ยน" errors
**Action Steps:**
1. **Check concurrent requests to same counter:**
```sql
SELECT
project_id,
correspondence_type_id,
COUNT(*) as concurrent_requests
FROM document_number_audit
WHERE created_at > NOW() - INTERVAL 5 MINUTE
GROUP BY project_id, correspondence_type_id
HAVING COUNT(*) > 10
ORDER BY concurrent_requests DESC;
```
2. **Investigate specific counter:**
```sql
SELECT * FROM document_number_counters
WHERE project_id = X AND correspondence_type_id = Y;
-- Check audit trail
SELECT * FROM document_number_audit
WHERE counter_key LIKE '%project_id:X%'
ORDER BY created_at DESC
LIMIT 20;
```
3. **Check for application bugs:**
- Review error logs for stack traces
- Check if retry logic is working correctly
4. **Temporary mitigation:**
- Increase retry count in application config
- Consider manual counter adjustment (last resort)
### 5. Maintenance Procedures
### 5.1. Counter Reset (Manual)
**Requires:** SUPER_ADMIN role + 2-person approval
**Steps:**
1. **Request approval via API:**
```bash
POST /api/v1/document-numbering/configs/{configId}/reset-counter
{
"reason": "เหตุผลที่ชัดเจน อย่างน้อย 20 ตัวอักษร",
"approver_1": "user_id",
"approver_2": "user_id"
}
```
2. **Verify in audit log:**
```sql
SELECT * FROM document_number_config_history
WHERE config_id = X
ORDER BY changed_at DESC
LIMIT 1;
```
### 5.2. Template Update
**Best Practices:**
1. Always test template in staging first
2. Preview generated numbers before applying
3. Document reason for change
4. Template changes do NOT affect existing documents
**API Call:**
```bash
PUT /api/v1/document-numbering/configs/{configId}
{
"template": "{ORIGINATOR}-{RECIPIENT}-{SEQ:4}-{YEAR:B.E.}",
"change_reason": "เหตุผลในการเปลี่ยนแปลง"
}
```
### 5.3. Database Maintenance
**Weekly Tasks:**
- Check slow query log
- Optimize tables if needed:
```sql
OPTIMIZE TABLE document_number_counters;
OPTIMIZE TABLE document_number_audit;
```
**Monthly Tasks:**
- Review and archive old audit logs (> 2 years)
- Check index usage:
```sql
SELECT * FROM sys.schema_unused_indexes
WHERE object_schema = 'lcbp3_db';
```

View File

@@ -3,10 +3,10 @@
---
title: 'UI/UX Requirements'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/02-architecture/data-model.md#correspondence

View File

@@ -3,10 +3,10 @@
---
title: 'Non-Functional Requirements'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/02-architecture/data-model.md#correspondence

View File

@@ -3,10 +3,10 @@
---
title: 'Testing Requirements'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/02-architecture/data-model.md#correspondence

View File

@@ -1,75 +0,0 @@
# 📦Section 3: ข้อกำหนดด้านฟังก์ชันการทำงาน (Functional Requirements)
---
title: "Functional Requirements: Correspondence Management"
version: 1.5.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03.1-project-management.md
- specs/01-requirements/03.2-correspondence.md
- specs/01-requirements/03.3-rfa.md
- specs/01-requirements/03.4-contract-drawing.md
- specs/01-requirements/03.5-shop-drawing.md
- specs/01-requirements/03.6-unified-workflow.md
- specs/01-requirements/03.7-transmittals.md
- specs/01-requirements/03.8-circulation-sheet.md
- specs/01-requirements/03.9-logs.md
- specs/01-requirements/03.10-file-handling.md
- specs/01-requirements/03.11-document-numbering.md
- specs/01-requirements/03.12-json-details.md
---
## 3.1 การจัดการโครงสร้างโครงการและองค์กร (Project Management)
[specs/01-requirements/03.1-project-management.md](01-03.1-project-management.md)
## 3.2 การจัดการเอกสารโครงการ (Correspondence)
[specs/01-requirements/03.2-correspondence.md](01-03.2-correspondence.md)
## 3.3 การจัดการเอกสารโครงการ (RFA)
[specs/01-requirements/03.3-rfa.md](01-03.3-rfa.md)
## 3.4 การจัดการแบบคู่สัญญา (Contract Drawing)
[specs/01-requirements/03.4-contract-drawing.md](01-03.4-contract-drawing.md)
## 3.5 การจัดกาแบบก่อสร้าง (Shop Drawing)
[specs/01-requirements/03.5-shop-drawing.md](01-03.5-shop-drawing.md)
## 3.6 การจัดการ Workflow (Unified Workflow)
[specs/01-requirements/03.6-unified-workflow.md](01-03.6-unified-workflow.md)
## 3.7 การจัดการเอกสารนำส่ง (Transmittals)
[specs/01-requirements/03.7-transmittals.md](01-03.7-transmittals.md)
## 3.8 การจัดการใบเวียนเอกสาร (Circulation Sheet)
[specs/01-requirements/03.8-circulation-sheet.md](01-03.8-circulation-sheet.md)
## 3.9 ประวัติการแก้ไข (logs)
[specs/01-requirements/03.9-logs.md](01-03.9-logs.md)
## 3.10 การจัดเก็บไฟล์ (File Handling)
[specs/01-requirements/03.10-file-handling.md](01-03.10-file-handling.md)
## 3.11 การจัดการเลขที่เอกสาร (Document Numbering)
[specs/01-requirements/03.11-document-numbering.md](01-03.11-document-numbering.md)
## 3.12 การจัดการ JSON Details (JSON & Performance - ปรับปรุง)
[specs/01-requirements/03.12-json-details.md](01-03.12-json-details.md)

View File

@@ -0,0 +1,43 @@
# 📦 01.2 ข้อกำหนดด้านฟังก์ชันการทำงานระดับโมดูล (Functional Requirements: Modules)
---
title: "Functional Requirements: Modules Index"
version: 1.8.0
status: active
owner: Nattanin Peancharoen
last_updated: 2026-02-23
---
หน้านี้รวบรวมข้อกำหนดการใช้งาน (Functional Requirements) ที่แบ่งตามระบบย่อย (Modules) ทั้งหมด
## 1. การจัดการโครงการและองค์กร (Project Management)
[01-02-01-project-management.md](01-02-01-project-management.md)
## 2. การจัดการจดหมายรับ-ส่ง (Correspondence)
[01-02-02-correspondence.md](01-02-02-correspondence.md)
## 3. การจัดการขออนุมัติวัสดุอุปกรณ์ (RFA)
[01-02-03-rfa.md](01-02-03-rfa.md)
## 4. การจัดการแบบคู่สัญญา (Contract Drawing)
[01-02-04-contract-drawing.md](01-02-04-contract-drawing.md)
## 5. การจัดการแบบก่อสร้าง (Shop Drawing)
[01-02-05-shop-drawing.md](01-02-05-shop-drawing.md)
## 6. กระบวนการอนุมัติ (Unified Workflow)
[01-02-06-unified-workflow.md](01-02-06-unified-workflow.md)
## 7. เอกสารนำส่ง (Transmittals)
[01-02-07-transmittals.md](01-02-07-transmittals.md)
## 8. ใบเวียนเอกสาร (Circulation Sheet)
[01-02-08-circulation-sheet.md](01-02-08-circulation-sheet.md)
## 9. ประวัติการแก้ไข (Logs / Revisions)
[01-02-09-logs.md](01-02-09-logs.md)
## 10. รายละเอียด JSON (JSON Details)
[01-02-10-json-details.md](01-02-10-json-details.md)

View File

@@ -3,15 +3,15 @@
---
title: "Functional Requirements: Project Management"
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Correspondence Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---
@@ -27,7 +27,7 @@ related:
## 3.2.3. การสร้างเอกสาร (Correspondence):
- ผู้ใช้ที่มีสิทธิ์ (เช่น Document Control) สามารถสร้างเอกสารรอไว้ในสถานะ ฉบับร่าง" (Draft) ได้ ซึ่งผู้ใช้งานต่างองค์กรจะมองไม่เห็น
- เมื่อกด "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
- เมื่อเอกสารเปลี่ยนสถานะเป็น "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
## 3.2.4. การอ้างอิงและจัดกลุ่ม:

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: RFA Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---
@@ -28,7 +28,7 @@ related:
## 3.3.3. การสร้างเอกสาร:
- ผู้ใช้ที่มีสิทธิ์ (เช่น Document Control) สามารถสร้างเอกสารขออนุมัติ (RFA) รอไว้ในสถานะ ฉบับร่าง" (Draft) ได้ ซึ่งผู้ใช้งานต่างองค์กรจะมองไม่เห็น
- เมื่อกด "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
- เมื่อเอกสารเปลี่ยนสถานะเป็น "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
## 3.3.4. การอ้างอิงและจัดกลุ่ม:

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Contract Drawing Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Shop Drawing Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,21 +3,21 @@
---
title: 'Functional Requirements: Unified Workflow Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---
## 3.6.1 Workflow Definition:
- Admin ต้องสามารถสร้าง/แก้ไข Workflow Rule ได้ผ่านหน้าจอ UI (DSL Editor)
- Admin ต้องสามารถกำหนดและสร้าง/แก้ไข Workflow Rule ได้ (DSL)
- รองรับการกำหนด State, Transition, Required Role, Condition (JS Expression)
## 3.6.2 Workflow Execution:

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Transmittals Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Circulation Sheet Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: Logs Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---

View File

@@ -3,15 +3,15 @@
---
title: 'Functional Requirements: JSON Details Management'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
---
@@ -93,8 +93,8 @@ related:
- สามารถเลือก สร้างในนามองค์กร (Create on behalf of) ได้ เพื่อให้สามารถออกเลขที่เอกสาร (Running Number) ขององค์กรอื่นได้โดยไม่ต้องล็อกอินใหม่
- สามารถทำงานแทนผู้ใช้งานอื่นได้ Routing & Workflow ของ Correspondence, RFA, Circulation Sheet
## 3.14. การจัดการข้อมูลหลักขั้นสูง (Admin Panel for Master Data)
## 3.14. การจัดการข้อมูลหลักขั้นสูง (Master Data Management)
- 3.14.1. Disciplines Management: Admin ต้องสามารถ เพิ่ม/ลบ/แก้ไข สาขางาน (Disciplines) แยกตามสัญญา (Contract) ได้
- 3.14.2. Sub-Type Mapping: Admin ต้องสามารถกำหนด Correspondence Sub-types และ Mapping รหัสตัวเลข (เช่น MAT = 11) ได้
- 3.14.3. Numbering Format Configuration: Admin ต้องมี UI สำหรับตั้งค่า Format Template ของแต่ละ Project/Type ได้โดยไม่ต้องแก้โค้ด
- 3.14.3. Numbering Format Configuration: ระบบต้องรองรับการตั้งค่า Format Template ของแต่ละ Project/Type ได้โดยไม่ต้องแก้โค้ด

View File

@@ -1,8 +1,8 @@
# 📋 Requirements Specification
**Version:** 1.7.0
**Version:** 1.8.0
**Status:** Active
**Last Updated:** 2025-12-18
**Last Updated:** 2026-02-23
---
@@ -17,30 +17,30 @@ This directory contains the functional and non-functional requirements for the L
### Core Requirements
1. [Objectives & Goals](./01-01-objectives.md) - Project objectives and success criteria
2. [System Architecture & Technology](./01-02-architecture.md) - High-level architecture requirements
3. [Functional Requirements](./01-03-functional-requirements.md) - Detailed feature specifications
2. [System Architecture & Technology](../02-Architecture/README.md) - High-level architecture requirements
3. [Functional Requirements](./01-02-modules/01-02-00-index.md) - Detailed feature specifications
### Functional Areas
#### Document Management
- [3.1 Project & Organization Management](./01-03.1-project-management.md) - Projects, contracts, organizations
- [3.2 Correspondence Management](./01-03.2-correspondence.md) - Letters and communications
- [3.3 RFA Management](./01-03.3-rfa.md) - Request for Approval
- [3.4 Contract Drawing Management](./01-03.4-contract-drawing.md) - Contract drawings (แบบคู่สัญญา)
- [3.5 Shop Drawing Management](./01-03.5-shop-drawing.md) - Shop drawings (แบบก่อสร้าง)
- [3.1 Project & Organization Management](./01-02-modules/01-02-01-project-management.md) - Projects, contracts, organizations
- [3.2 Correspondence Management](./01-02-modules/01-02-02-correspondence.md) - Letters and communications
- [3.3 RFA Management](./01-02-modules/01-02-03-rfa.md) - Request for Approval
- [3.4 Contract Drawing Management](./01-02-modules/01-02-04-contract-drawing.md) - Contract drawings (แบบคู่สัญญา)
- [3.5 Shop Drawing Management](./01-02-modules/01-02-05-shop-drawing.md) - Shop drawings (แบบก่อสร้าง)
#### Supporting Features
- [3.6 Unified Workflow](./01-03.6-unified-workflow.md) - Workflow engine and routing
- [3.7 Transmittals Management](./01-03.7-transmittals.md) - Document transmittals
- [3.8 Circulation Sheet Management](./01-03.8-circulation-sheet.md) - Document circulation
- [3.9 Revisions Management](./01-03.9-logs.md) - Version control
- [3.10 File Handling](./01-03.10-file-handling.md) - File storage and processing
- [3.6 Unified Workflow](./01-02-modules/01-02-06-unified-workflow.md) - Workflow engine and routing
- [3.7 Transmittals Management](./01-02-modules/01-02-07-transmittals.md) - Document transmittals
- [3.8 Circulation Sheet Management](./01-02-modules/01-02-08-circulation-sheet.md) - Document circulation
- [3.9 Revisions Management](./01-02-modules/01-02-09-logs.md) - Version control
- [3.10 JSON Details](./01-02-modules/01-02-10-json-details.md) - JSON field specifications
#### **⭐ Document Numbering System**
- [3.11 Document Numbering](./01-03.11-document-numbering.md) - **Requirements**
- [3.11 Document Numbering](./01-01-business-rules/01-01-02-doc-numbering-rules.md) - **Requirements**
- Automatic number generation
- Template-based formatting
- Concurrent request handling
@@ -51,16 +51,14 @@ This directory contains the functional and non-functional requirements for the L
- 📘 [Implementation Guide](../03-implementation/03-04-document-numbering.md) - NestJS, TypeORM, Redis code examples
- 📗 [Operations Guide](../04-operations/04-08-document-numbering-operations.md) - Monitoring, troubleshooting, runbooks
#### Technical Details
- [3.12 JSON Details](./01-03.12-json-details.md) - JSON field specifications
### Cross-Cutting Concerns
4. [Access Control & RBAC](./01-04-access-control.md) - 4-level hierarchical RBAC
5. [UI/UX Requirements](./01-05-ui-ux.md) - User interface specifications
6. [Non-Functional Requirements](./01-06-non-functional.md) - Performance, security, scalability
7. [Testing Requirements](./01-07-testing.md) - Test strategy and coverage
4. [Access Control & RBAC](./01-01-business-rules/01-01-01-rbac-matrix.md) - 4-level hierarchical RBAC
5. [UI/UX Requirements](./01-01-business-rules/01-01-03-ui-ux-rules.md) - User interface specifications
6. [Non-Functional Requirements](./01-01-business-rules/01-01-04-non-functional-rules.md) - Performance, security, scalability
7. [Testing Requirements](./01-01-business-rules/01-01-05-testing-rules.md) - Test strategy and coverage
---
@@ -101,19 +99,19 @@ See [CHANGELOG.md](../../CHANGELOG.md) for detailed version history.
### By Feature Status
| Feature Area | Requirements Doc | Status | Implementation | Operations |
| ------------------------- | ----------------------------------------- | ---------- | ----------------------------------------------------------- | ------------------------------------------------------------------ |
| Correspondence Management | [03.2](./01-03.2-correspondence.md) | ✅ Complete | ✅ Complete | Available |
| RFA Management | [03.3](./01-03.3-rfa.md) | ✅ Complete | ✅ Complete | Available |
| Contract Drawing | [03.4](./01-03.4-contract-drawing.md) | ✅ Complete | ✅ Complete | Available |
| Shop Drawing | [03.5](./01-03.5-shop-drawing.md) | ✅ Complete | ✅ Complete | Available |
| Workflow Engine | [03.6](./01-03.6-unified-workflow.md) | ✅ Complete | ✅ Complete | Available |
| Transmittals | [03.7](./01-03.7-transmittals.md) | ✅ Complete | ✅ Complete | Available |
| Circulation Sheets | [03.8](./01-03.8-circulation-sheet.md) | ✅ Complete | ✅ Complete | Available |
| **Document Numbering** | [03.11](./01-03.11-document-numbering.md) | ✅ Complete | ✅ [Guide](../03-implementation/03-04-document-numbering.md) | ✅ [Guide](../04-operations/04-08-document-numbering-operations.md) |
| Access Control (RBAC) | [04](./01-04-access-control.md) | ✅ Complete | ✅ Complete | Available |
| Search (Elasticsearch) | N/A | ✅ Complete | 🔄 95% | Available |
| Dashboard & Analytics | N/A | ✅ Complete | ✅ Complete | Available |
| Feature Area | Requirements Doc | Status | Implementation | Operations |
| ------------------------- | ---------------------------------------------------- | ---------- | ----------------------------------------------------------- | ------------------------------------------------------------------ |
| Correspondence Management | [03.2](./01-03.2-correspondence.md) | ✅ Complete | ✅ Complete | Available |
| RFA Management | [03.3](./01-03.3-rfa.md) | ✅ Complete | ✅ Complete | Available |
| Contract Drawing | [03.4](./01-03.4-contract-drawing.md) | ✅ Complete | ✅ Complete | Available |
| Shop Drawing | [03.5](./01-03.5-shop-drawing.md) | ✅ Complete | ✅ Complete | Available |
| Workflow Engine | [03.6](./01-03.6-unified-workflow.md) | ✅ Complete | ✅ Complete | Available |
| Transmittals | [03.7](./01-03.7-transmittals.md) | ✅ Complete | ✅ Complete | Available |
| Circulation Sheets | [03.8](./01-03.8-circulation-sheet.md) | ✅ Complete | ✅ Complete | Available |
| **Document Numbering** | [03.11](./01-03.11-document-numbering.md) | ✅ Complete | ✅ [Guide](../03-implementation/03-04-document-numbering.md) | ✅ [Guide](../04-operations/04-08-document-numbering-operations.md) |
| Access Control (RBAC) | [04](./01-02-business-rules/01-02-01-rbac-matrix.md) | ✅ Complete | ✅ Complete | Available |
| Search (Elasticsearch) | N/A | ✅ Complete | 🔄 95% | Available |
| Dashboard & Analytics | N/A | ✅ Complete | ✅ Complete | Available |
### By Priority
@@ -178,8 +176,8 @@ All requirements documents must meet these criteria:
## 📝 Document Control
- **Version:** 1.7.0
- **Version:** 1.8.0
- **Owner:** System Architect (Nattanin Peancharoen)
- **Last Review:** 2025-12-18
- **Next Review:** 2026-01-01
- **Last Review:** 2026-02-23
- **Next Review:** 2026-03-01
- **Classification:** Internal Use Only

View File

@@ -0,0 +1,95 @@
# 00.1 System Context & Architecture (สถาปัตยกรรมและบริบทของระบบ)
---
title: 'System Context & Architecture'
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2026-02-23
related:
- specs/01-requirements/01-objectives.md
- specs/03-implementation/03-01-fullftack-js-v1.7.0.md
---
## 1. 📋 ภาพรวมระบบ (System Overview)
ระบบ LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System) ถูกออกแบบด้วยสถาปัตยกรรมแบบ **Headless/API-First Architecture** โดยทำงานแบบ **On-Premise 100%** บนเครื่องเซอร์ฟเวอร์ QNAP และ ASUSTOR
ระบบทั้งหมดทำงานอยู่ภายใต้สภาวะแวดล้อมแบบ **Container Isolation** (ผ่าน Container Station) เพื่อความปลอดภัย, ง่ายต่อการจัดการ, และไม่ยึดติดกับ Hardware (Hardware Agnostic)
### 1.1 Architecture Principles
1. **Data Integrity First:** ความถูกต้องของข้อมูลต้องมาก่อนทุกอย่าง
2. **Security by Design & Container Isolation:** รักษาความปลอดภัยที่ทุกชั้น และแยกส่วนการทำงานของแต่ละระบบอย่างชัดเจน (Network Segmentation & Containerization)
3. **On-Premise First:** ข้อมูลและระบบงานทั้งหมดต้องอยู่ภายในเครือข่ายของโครงการเท่านั้น
4. **Resilience:** ทนทานต่อ Failure และ Recovery ได้รวดเร็ว โดยมี Backup NAS
5. **Observability:** ติดตามและวิเคราะห์สถานะระบบได้ง่าย
## 2. 🏢 มาตรฐานการติดตั้ง On-Premise (QNAP/ASUSTOR Installation Standards)
### 2.1 Hardware Infrastructure
- **Primary Server (QNAP TS-473A):**
- IP: 192.168.10.8 (VLAN 10)
- Role: Primary NAS for DMS, Container Host
- Storage: `/share/dms-data` (RAID 5 HDD + SSD Caching)
- **Backup Server (ASUSTOR AS5304T):**
- IP: 192.168.10.9 (VLAN 10)
- Role: Backup / Secondary NAS
- **Network Interface:** NAS ทั้งสองตัวใช้ LACP bonding แบบ IEEE 802.3ad เพื่อเพิ่ม bandwidth และ redundancy
### 2.2 Container Isolation & Environment
อ้างอิงข้อจำกัดและมาตรฐานของระบบ Container Station บน QNAP:
- **Containerization Engine:** Docker & Docker Compose
- **Network Isolation:** ทุกคอนเทนเนอร์ (Frontend, Backend, Database, Redis, Search) จะต้องเชื่อมต่อกันผ่าน Internal Docker Network ชื่อ `lcbp3` เท่านั้น ห้าม Expose Port ออกสู่ภายนอกโดยไม่จำเป็น
- **Reverse Proxy:** ใช้ Nginx Proxy Manager (`npm.np-dms.work`) เป็น Gateway (Load Balancer & SSL Termination) รับ Traffic เพียงจุดเดียวบน Port 80/443 และ Map เข้าสู่ Internal Docker Network
- **Configuration Defaults:**
- **ห้ามใช้ `.env` แบบ bind mount สำหรับ secret บน Production** ตามข้อจำกัดของ Container Station
- การกำหนดตัวแปรให้ใช้ผ่าน `docker-compose.yml` สำหรับค่าทั่วไปใน Container
- Sensitive Secrets ต้องใช้ `docker-compose.override.yml` ที่ไม่ถูกนำขึ้น Git หรือผ่าน Docker Secrets
## 3. 🌐 Network Segmentation & Security
ระบบจัดแบ่งเครือข่ายออกเป็น VLANs ต่างๆ เพื่อการควบคุมการเข้าถึงตามหลักการ Zero Trust ย่อยๆ โดยใช้อุปกรณ์เครือข่าย (ER7206 Router & SG2428P Core Switch) ในการบังคับใช้ ACL:
### 3.1 VLAN Configuration
| VLAN ID | Name | Purpose | Subnet | Gateway | Notes |
| ------- | ------ | ------------------ | --------------- | ------------ | ----------------------------------------- |
| 10 | SERVER | Server & Storage | 192.168.10.0/24 | 192.168.10.1 | Servers (QNAP, ASUSTOR). Static IPs ONLY. |
| 20 | MGMT | Management & Admin | 192.168.20.0/24 | 192.168.20.1 | Network devices, Admin PC. |
| 30 | USER | User Devices | 192.168.30.0/24 | 192.168.30.1 | Staff PC, Printers. |
| 40 | CCTV | Surveillance | 192.168.40.0/24 | 192.168.40.1 | Cameras, NVR. Isolated. |
| 50 | VOICE | IP Phones | 192.168.50.0/24 | 192.168.50.1 | SIP traffic. Isolated. |
| 60 | DMZ | Public Services | 192.168.60.0/24 | 192.168.60.1 | DMZ. Isolated from Internal. |
| 70 | GUEST | Guest Wi-Fi | 192.168.70.0/24 | 192.168.70.1 | Isolated Internet Access only. |
### 3.2 Network ACL & Isolation Rules
- **SERVER Isolation:** `VLAN 30 (USER)` สามารถเข้าถึง `VLAN 10 (SERVER)` ได้เฉพาะพอร์ตที่จำเป็น (HTTP/HTTPS/SSH)
- **MGMT Restriction:** ไม่อนุญาตให้ `VLAN 30 (USER)` เข้าถึง `VLAN 20 (MGMT)` โดยเด็ดขาด
- **Device Isolation:** `CCTV`, `VOICE`, และ `GUEST` แยกขาดออกจากวงอื่นๆ (Deny-All to Internal)
- **Strict Default:** ใช้หลักการ Default Deny บน Gateway (ER7206)
- **Container Level ACL:** ภายในวง `SERVER` Docker Network จะแยกออกไปอีกชั้น ทำให้ Host ในเครือข่าย `VLAN 10` ไม่สามารถเข้าถึง Database หรือ Redis ได้โดยตรง หากไม่ผ่าน Nginx Proxy Manager
## 4. 🧩 Core Services Architecture
| Service | Application Name | Domain | Technology | Purpose |
| ------------ | ---------------- | ------------------- | --------------- | ------------------ |
| **Frontend** | lcbp3-frontend | lcbp3.np-dms.work | Next.js 14+ | Web UI |
| **Backend** | lcbp3-backend | backend.np-dms.work | NestJS | API Server & Logic |
| **Database** | lcbp3-db | db.np-dms.work | MariaDB 11.8 | Primary Data |
| **DB Admin** | lcbp3-db | pma.np-dms.work | phpMyAdmin | DB Administration |
| **Proxy** | lcbp3-npm | npm.np-dms.work | Nginx Proxy Mgr | Gateway & SSL |
| **Workflow** | lcbp3-n8n | n8n.np-dms.work | n8n | Process Automation |
| **Git** | git | git.np-dms.work | Gitea | Code Repository |
| **Cache** | - | - | Redis | Caching, Locking |
| **Search** | - | - | Elasticsearch | Full-text Indexing |
## 5. 📊 Data Flow & Interactions
1. **User Request:** ผู้ใช้งานส่ง Request ไปที่โดเมนผ่าน HTTP/HTTPS
2. **Reverse Proxy:** Nginx Proxy Manager รับ Request, ตรวจสอบ SSL, และ Forward ไปให้ Frontend หรือ Backend ในวง Docker Network
3. **API Processing:** Backend รัน Business Logic, ประมวลผล Authentication (JWT) และ Permissions (RBAC via Redis Cache)
4. **Data Persistence:** Backend ติดต่อ MariaDB (Database) และ Elasticsearch (Search) ที่ถูกซ่อนไว้ในระบบปิด (Isolations)
5. **Storage Process:** ไฟล์ถูกคัดกรองผ่าน ClamAV (ถ้ามี) และเก็บลง Storage `/share/dms-data` บน QNAP แบบ Two-Phase Storage (Temp -> Permanent) เพื่อป้องกัน Orphan Files
## 6. 💾 Backup & Disaster Recovery (DR)
- **Database Backup:** ทำ Automated Backup รายวันด้วย QNAP HBS 3 หรือ mysqldump
- **File Backup:** ทำ Snapshot หรือ rsync จาก `/share/dms-data` บนเครื่องหลัก (QNAP) ไปยังเครื่องสำรอง (ASUSTOR) อย่างสม่ำเสมอ
- **Recovery Standard:** หาก NAS พัง สามารถ Restore Config ย้ายข้อมูล และรัน `docker-compose up` ขึ้นใหม่บนเครื่อง Backup ได้ทันที เนื่องจาก Architecture ออกแบบแบบ Stateless สำหรับตัวแอพพลิเคชั่น และ Data แยกลง Volume Storage ชัดเจน

View File

@@ -0,0 +1,125 @@
# 02.3 Software Architecture & Design (สถาปัตยกรรมซอฟต์แวร์และการออกแบบ)
---
title: 'Software Architecture'
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2026-02-23
related:
- specs/02-Architecture/00-01-system-context.md
---
## 1. 🧱 Backend Module Architecture (NestJS)
### 1.1 Modular Design
```mermaid
graph TB
subgraph "Core Modules"
Common[CommonModule<br/>Shared Services]
Auth[AuthModule<br/>JWT & Guards]
User[UserModule<br/>User Management]
end
subgraph "Business Modules"
Project[ProjectModule<br/>Projects & Contracts]
Corr[CorrespondenceModule<br/>Correspondences]
RFA[RfaModule<br/>RFA Management]
Drawing[DrawingModule<br/>Shop & Contract Drawings]
Circ[CirculationModule<br/>Circulation Sheets]
end
subgraph "Supporting Modules"
Workflow[WorkflowEngineModule<br/>Unified Workflow]
Numbering[DocumentNumberingModule<br/>Auto Numbering]
Search[SearchModule<br/>Elasticsearch]
end
Corr --> Workflow
RFA --> Workflow
Circ --> Workflow
Corr --> Numbering
RFA --> Numbering
Search --> Corr
Search --> RFA
Search --> Drawing
```
### 1.2 Key Architectural Patterns
#### Unified Workflow Engine (DSL-Based)
ระบบการเดินเอกสาร (Correspondence, RFA, Circulation) ใช้ Engine กลางเดียวกัน ผ่าน **Workflow DSL (JSON Configuration)**
- **Separation of Concerns:** Modules เก็บเฉพาะข้อมูล (Data) ส่วน Flow/State ถูกจัดการโดย Engine
- **Versioning:** อาศัย Workflow Definition Version ป้องกันความขัดแย้งของ State เมื่อมีการแก้ไข Flow
#### Double-Locking Mechanism (Auto Numbering)
เพื่อป้องกัน Race Condition ในการขอเลขเอกสารพร้อมกัน:
- **Layer 1:** Redis Distributed Lock (ล็อคการเข้าถึงในระดับ Server/Network)
- **Layer 2:** Optimistic Database Lock ผ่าน `@VersionColumn()` (ป้องกันระดับ Data Record)
#### Idempotency
ทุก API ที่แก้ไขสถานะจะต้องส่ง `Idempotency-Key` ป้องกันผู้ใช้กดยืนยันซ้ำสองรอบ
## 2. 📊 Data Flow & Processes
### 2.1 Main Request Flow
```mermaid
sequenceDiagram
participant Client as Client
participant NPM as Nginx Proxy
participant BE as Backend (NestJS)
participant Redis as Redis Cache
participant DB as MariaDB
Client->>NPM: HTTP Request + JWT
NPM->>BE: Forward Request
BE->>BE: Rate Limit Check & Validate Input
BE->>Redis: Get User Permissions (RBAC Cache)
Redis-->>BE: Permission Data
BE->>BE: Verify Permission
BE->>DB: Process Logic & Save
BE->>Redis: Invalidate affected Cache
BE-->>Client: JSON Response
```
### 2.2 File Upload Flow (Two-Phase Storage)
ใช้แบบ **Two-Phase** เพื่อลดความเสี่ยงเกิดไฟล์ขยะ (Orphan Files):
1. **[Phase 1]:** Client อัปโหลดไฟล์ -> ตรวจ Virus -> วางไว้ที่โฟลเดอร์ `temp/` -> ส่ง `temp_id` กลับให้ Client
2. **[Phase 2]:** Client สั่ง Create Document (แนบ `temp_id`) -> Backend บันทึกฐานข้อมูล -> ย้ายไฟล์จาก `temp/` ไปที่ `permanent/` -> สร้างตาราง Attachment -> Commit Transaction
3. **[Cleanup Job]:** ครอนจ็อบตามลบไฟล์ที่ค้างอยู่ใน `temp/` เกิน 24 ชั่วโมง
## 3. 🛡️ Security Architecture
### 3.1 Rate Limiting (Redis-backed)
- Anonymous: 100 req/hour
- File Upload: 50 req/hour
- Document Control: 2000 req/hour
- Admin: 5000 req/hour
### 3.2 Authorization checking flow (CASL)
1. ดึง JWT Token ตรวจสอบความถูกต้อง
2. โหลด User Permissions จาก Redis (`user:{user_id}:permissions`)
3. ตรวจสอบเงื่อนไขตาม Context:
- Superadmin Override
- Orgnization Level
- Project Level
- Contract Level
4. พิจารณาอนุญาตหากระดับใดระดับหนึ่งอนุญาต (Most Permissive approach)
### 3.3 OWASP Top 10 Protections implemented
- **SQL Injection:** Parameterized Queries via TypeORM
- **XSS/CSRF:** Input Sanitization, CSRF Tokens
- **Insecure File Upload:** Magic Number Validation (ไม่ใช่แค่ extension), ไวรัสสแกน, สิทธิเข้าถึงไฟล์ถูกห่อหุ้มด้วย Authorization endpoint เสมอ ไม่ปล่อย public link
## 4. 🔄 Resilience & Error Handling
- **Circuit Breaker:** ใช้งานครอบ API ภายนอก (Email, LINE Notify). หาก fail ติดต่อกัน 5 ครั้งใน 1 นาที ให้หยุดส่ง (Timeout 30s) แล้วใช้โหมด Half-open
- **Retry Mechanism (Exponential Backoff):** สำหรับกระบวนการสำคัญชั่วคราว เช่น จังหวะล็อก Database ล้มเหลวตอน Generate Number
- **Graceful Degradation:** หาก Search Engine ล่ม (Elasticsearch down), ระบบต้องสลับไปใช้ Database Query พื้นฐานชั่วคราวได้ หรือตัดฟีเจอร์บางส่วนโดยไม่กระทบ CRUD หลัก

View File

@@ -0,0 +1,188 @@
# 02.4 Network Design & Security (การออกแบบเครือข่ายและความปลอดภัย)
---
title: 'Network Design & Security'
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2026-02-23
related:
- specs/02-Architecture/00-01-system-context.md
- specs/02-Architecture/02-03-software-architecture.md
---
## 1. 🌐 Network Segmentation (VLANs) และหลักการ Zero Trust
ระบบ LCBP3-DMS จัดแบ่งเครือข่ายออกเป็นเครือข่ายย่อย (VLANs) เพื่อการควบคุมการเข้าถึง (Access Control) ตามหลักการ Zero Trust โดยใช้อุปกรณ์ Network ของ Omada (ER7206 Router & SG2428P Core Switch) และ Switch ต่างๆ ในเครือข่าย
| VLAN ID | Name | Purpose | Subnet | Gateway | Notes |
| ------- | -------------- | ----------------------- | --------------- | ------------ | ---------------------------------------------------- |
| 10 | SERVER | Server & Storage | 192.168.10.0/24 | 192.168.10.1 | Servers (QNAP, ASUSTOR). Static IPs ONLY. |
| 20 | MGMT (Default) | Management & Admin | 192.168.20.0/24 | 192.168.20.1 | Network devices (ER7206, OC200, Switches), Admin PC. |
| 30 | USER | User Devices | 192.168.30.0/24 | 192.168.30.1 | Staff PC, Notebooks, Wi-Fi. |
| 40 | CCTV | Surveillance | 192.168.40.0/24 | 192.168.40.1 | Cameras, NVR. Isolated. |
| 50 | VOICE | IP Phones | 192.168.50.0/24 | 192.168.50.1 | SIP traffic. Isolated. |
| 60 | DMZ | Public Services | 192.168.60.0/24 | 192.168.60.1 | DMZ. Isolated from Internal. |
| 70 | GUEST | Guest Wi-Fi (Untrusted) | 192.168.70.0/24 | 192.168.70.1 | Guest Wi-Fi. Isolated Internet Access only. |
## 2. 🔐 Security Zones และสิทธิการเข้าถึงของ Container
```mermaid
flowchart TB
subgraph PublicZone["🌐 PUBLIC ZONE"]
direction LR
NPM["NPM (Reverse Proxy)<br/>Ports: 80, 443"]
SSL["SSL/TLS Termination"]
end
subgraph AppZone["📱 APPLICATION ZONE (Docker Network 'lcbp3' on QNAP)"]
direction LR
Frontend["Next.js"]
Backend["NestJS"]
N8N["n8n"]
Gitea["Gitea"]
end
subgraph DataZone["💾 DATA ZONE (QNAP - Internal Only)"]
direction LR
MariaDB["MariaDB"]
Redis["Redis"]
ES["Elasticsearch"]
end
subgraph InfraZone["🛠️ INFRASTRUCTURE ZONE (ASUSTOR)"]
direction LR
Backup["Backup Services"]
Registry["Docker Registry"]
Monitoring["Prometheus + Grafana"]
Logs["Loki / Syslog"]
end
PublicZone -->|HTTPS Only| AppZone
AppZone -->|Internal API| DataZone
DataZone -.->|Backup| InfraZone
AppZone -.->|Metrics| InfraZone
```
### 2.1 กฎเหล็ก: การเข้าถึงระบบฐานข้อมูล (Database Access Restriction)
> [!CAUTION]
> **MariaDB และ Redis ตั้งอยู่ใน DATA ZONE ภายใต้ Docker Network ภายในชื่อ `lcbp3` เท่านั้น**
- **ห้าม Expose Port ออกสู่ Host โดยตรง:** `mariadb:3306` และ `redis:6379` จะต้องไม่ถูกเปิดสิทธิออกสู่ภายนอก Container Station
- **การเข้าถึงจากระบบอื่น:** เฉพาะ Service ใน **APPLICATION ZONE** (เช่น NestJS Backend) และ Service อื่นบน Network `lcbp3` เท่านั้นที่จะสามารถเรียกใช้งาน Database ได้
- **การจัดการโดย Admin:** หากผู้ดูแลระบบต้องการเข้าไปจัดการฐานข้อมูล จะต้องใช้งานผ่าน **phpMyAdmin** (`pma.np-dms.work`) ซึ่งถูกจำกัดสิทธิเข้าถึงผ่าน Nginx Proxy Manager อีกชั้น หรือผ่าน SSH Tunnel เข้าสู่เซิร์ฟเวอร์เท่านั้น
## 3. 🗺️ Network Topology & Switch Profiles
```mermaid
graph TB
subgraph Internet
WAN[("🌐 Internet<br/>WAN")]
end
subgraph Router["ER7206 Router"]
R[("🔲 ER7206<br/>192.168.20.1")]
end
subgraph CoreSwitch["SG2428P Core Switch"]
CS[("🔲 SG2428P<br/>192.168.20.2")]
end
subgraph ServerSwitch["AMPCOM 2.5G Switch"]
SS[("🔲 AMPCOM<br/>192.168.20.3")]
end
subgraph Servers["VLAN 10 - Servers"]
QNAP[("💾 QNAP<br/>192.168.10.8")]
ASUSTOR[("💾 ASUSTOR<br/>192.168.10.9")]
end
subgraph AccessPoints["EAP610 x16"]
AP[("📶 WiFi APs")]
end
WAN --> R
R -->|Port 3| CS
CS -->|LAG Port 3-4| SS
SS -->|Port 3-4 LACP| QNAP
SS -->|Port 5-6 LACP| ASUSTOR
CS -->|Port 5-20| AP
```
### 3.1 Switch Profiles & Interfaces
- **01_CORE_TRUNK:** Router & switch uplinks (Native: 20, Tagged: All)
- **02_MGMT_ONLY:** Management only (Native: 20, Untagged: 20)
- **03_SERVER_ACCESS:** QNAP / ASUSTOR (Native: 10, Untagged: 10)
- **04_CCTV_ACCESS:** CCTV cameras (Native: 40, Untagged: 40)
- **05_USER_ACCESS:** PC / Printer (Native: 30, Untagged: 30)
- **06_AP_TRUNK:** EAP610 Access Points (Native: 20, Tagged: 30, 70)
- **07_VOICE_ACCESS:** IP Phones (Native: 30, Tagged: 50, Untagged: 30)
### 3.2 NAS NIC Bonding Configuration
| Device | Bonding Mode | Member Ports | VLAN Mode | Tagged VLAN | IP Address | Gateway | Notes |
| ------- | ------------------- | ------------ | --------- | ----------- | --------------- | ------------ | ---------------------- |
| QNAP | IEEE 802.3ad (LACP) | Adapter 1, 2 | Untagged | 10 (SERVER) | 192.168.10.8/24 | 192.168.10.1 | Primary NAS for DMS |
| ASUSTOR | IEEE 802.3ad (LACP) | Port 1, 2 | Untagged | 10 (SERVER) | 192.168.10.9/24 | 192.168.10.1 | Backup / Secondary NAS |
## 4. 🔥 Firewall Rules (ACLs) & Port Forwarding
กฎของ Firewall จะถูกกำหนดบน Omada Controller และอุปกรณ์ Gateway (ER7206) ตามหลักการอนุญาตแค่สิ่งที่ต้องการ (Default Deny)
### 4.1 IP Groups & Port Groups (อ้างอิงบ่อย)
**IP Groups:**
- `Server`: 192.168.10.8, 192.168.10.9, 192.168.10.111
- `Omada-Controller`: 192.168.20.250
- `DHCP-Gateways`: 192.168.30.1, 192.168.70.1
- `QNAP_Services`: 192.168.10.8
- `Internal`: 192.168.10.0/24, 192.168.20.0/24, 192.168.30.0/24
- `Blacklist`: (เพิ่ม IP ประสงค์ร้าย)
**Port Groups:**
- `Web`: TCP 443, 8443, 80, 81, 2222
- `Omada-Auth`: TCP 443, 8043, 8088, 8843, 29810-29814
- `VoIP`: UDP 5060, 5061, 10000-20000 (SIP + RTP)
- `DHCP`: UDP 67, 68
### 4.2 Switch ACL (สำหรับ Omada OC200)
> ⚠️ **ลำดับความสำคัญ (Priority Level):** (1) Allow rules (DHCP, Auth) -> (2) Isolate/Deny rules -> (3) Allow specific services -> (4) Default Deny
| ลำดับ | Name | Policy | Source | Destination | Ports |
| :--- | :------------------------ | :----- | :---------------- | :---------------------------- | :---------------------------------------- |
| 1 | 01 Allow-User-DHCP | Allow | Network → VLAN 30 | IP → 192.168.30.1 | Port Group → DHCP |
| 2 | 02 Allow-Guest-DHCP | Allow | Network → VLAN 70 | IP → 192.168.70.1 | Port Group → DHCP |
| 3 | 03 Allow-WiFi-Auth | Allow | Network → VLAN 30 | IP Group → Omada-Controller | Port Group → Omada-Auth |
| 4 | 04 Allow-Guest-WiFi-Auth | Allow | Network → VLAN 70 | IP Group → Omada-Controller | Port Group → Omada-Auth |
| 5 | 05 Isolate-Guests | Deny | Network → VLAN 70 | Network → VLAN 10, 20, 30, 60 | All |
| 6 | 06 Isolate-Servers | Deny | Network → VLAN 10 | Network → VLAN 30 (USER) | All |
| 7 | 07 Block-User-to-Mgmt | Deny | Network → VLAN 30 | Network → VLAN 20 (MGMT) | All |
| 8 | 08 Allow-User-to-Services | Allow | Network → VLAN 30 | IP → QNAP (192.168.10.8) | Port Group → Web (443,8443, 80, 81, 2222) |
| 9 | 09 Allow-Voice-to-User | Allow | Network → VLAN 50 | Network → VLAN 30,50 | All |
| 10 | 10 Allow-MGMT-to-All | Allow | Network → VLAN 20 | Any | All |
| 11 | 11 Allow-Server-Internal | Allow | IP Group : Server | IP Group : Server | All |
| 12 | 12 Allow-Server → CCTV | Allow | IP Group : Server | Network → VLAN 40 (CCTV) | All |
| 13 | 100 (Default) | Deny | Any | Any | All |
### 4.3 Gateway ACL (สำหรับ ER7206)
| ลำดับ | Name | Policy | Direction | PROTOCOLS | Source | Destination |
| :--- | :---------------------- | :----- | :-------- | :-------- | :------------------- | :--------------------------- |
| 1 | 01 Blacklist | Deny | [WAN2] IN | All | IP Group:Blacklist | IP Group:Internal |
| 2 | 02 Geo | Permit | [WAN2] IN | All | Location Group:Allow | IP Group:Internal |
| 3 | 03 Allow-Voice-Internet | Permit | LAN->WAN | UDP | Network → VLAN 50 | Any |
| 4 | 04 Internal → Internet | Permit | LAN->WAN | All | IP Group:Internal | Domain Group:DomainGroup_Any |
### 4.4 Port Forwarding
Traffic สาธารณะ (WAN) จะถูกเชื่อมต่อไปยัง Nginx Proxy Manager เพียงจุดเดียว
- **Allow-NPM-HTTPS:** External Port 443 -> QNAP (192.168.10.8) Port 443 (TCP)
- **Allow-NPM-HTTP (สำหรับ Let's Encrypt):** External Port 80 -> QNAP (192.168.10.8) Port 80 (TCP)
## 5. 📡 EAP ACL (Wireless Data Flow Rules)
ตั้งค่าสำหรับ Access Points ให้ป้องกันการ Broadcast ลดทอนกันเอง หรือรบกวนโซนอื่นๆ
* **SSID: PSLCBP3 (Staff WiFi) - VLAN 30**
- อนุญาต DNS, 192.168.10.0/24 (Servers), Printer, Internet
- **บล็อค** การเข้าสู่ 192.168.20.0/24 (MGMT), 192.168.40.0/24 (CCTV), และ **Client Isolation (Client-2-Client Deny)**
* **SSID: GUEST (Guest WiFi) - VLAN 70**
- อนุญาต DNS, Internet (HTTP/HTTPS)
- **บล็อคเครือข่ายส่วนตัวทั้งหมด (RFC1918):** 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 และสั่ง **Client Isolation**

View File

@@ -0,0 +1,339 @@
# 02.4 API Design & Error Handling (การออกแบบ API และการจัดการข้อผิดพลาด)
---
**title:** 'API Design & Error Handling'
**version:** 1.8.0
**status:** active
**owner:** Nattanin Peancharoen
**last_updated:** 2026-02-23
**related:**
- specs/02-Architecture/00-01-system-context.md
- specs/02-Architecture/02-03-software-architecture.md
- specs/03-Implementation/03-01-fullstack-js-v1.7.0.md
---
## 1. 📋 ภาพรวม (Overview)
เอกสารนี้กำหนดมาตรฐานการออกแบบ API สำหรับระบบ LCBP3-DMS โดยใช้แนวทาง **API-First Design** ที่เน้นความชัดเจน ความสอดคล้อง และความปลอดภัย รวมถึงกลยุทธ์การจัดการ Error (Error Handling) สำหรับ Backend (NestJS)
## 2. 🎯 หลักการออกแบบ API (API Design Principles)
### 2.1 API-First Approach
- **ออกแบบ API ก่อนการ Implement:** ทำการออกแบบ API Endpoint และ Data Contract ให้ชัดเจนก่อนเริ่มเขียนโค้ด
- **Documentation-Driven:** ใช้ OpenAPI/Swagger เป็นเอกสารอ้างอิงหลัก
- **Contract Testing:** ทดสอบ API ตาม Contract ที่กำหนดไว้
### 2.2 RESTful Principles
- ใช้ HTTP Methods อย่างถูกต้อง: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`
- ใช้ HTTP Status Codes ที่เหมาะสม
- Resource-Based URL Design
- Stateless Communication
### 2.3 Consistency & Predictability
- **Naming Conventions:** ใช้ `kebab-case` สำหรับ URL paths
- **Property Naming:** ใช้ `camelCase` สำหรับ JSON properties และ query parameters (สอดคล้องกับ TypeScript/JavaScript conventions)
- **Database Columns:** Database ใช้ `snake_case` (mapped via TypeORM decorators)
- **Versioning:** รองรับการ Version API ผ่าน URL path (`/api/v1/...`)
## 3. 🔐 Authentication & Authorization
### 3.1 Authentication
- **JWT-Based Authentication:** ใช้ JSON Web Token สำหรับการยืนยันตัวตน
- **Token Management:**
- Access Token Expiration: 8 ชั่วโมง
- Refresh Token Expiration: 7 วัน
- Token Rotation: รองรับการหมุนเวียน Refresh Token
- Token Revocation: บันทึก Revoked Tokens จนกว่าจะหมดอายุ
**Endpoints คอร์:**
```typescript
POST /api/v1/auth/login
POST /api/v1/auth/logout
POST /api/v1/auth/refresh
POST /api/v1/auth/change-password
```
### 3.2 Authorization (RBAC) (CASL)
ใช้ระบบ 4-Level Permission Hierarchy (Global, Organization, Project, Contract)
- **Permission Checking:** ใช้ Decorator `@RequirePermission('resource.action')`
**Example:**
```typescript
@RequirePermission('correspondence.create')
@Post('correspondences')
async createCorrespondence(@Body() dto: CreateCorrespondenceDto) {
// Implementation
}
```
### 3.3 Token Payload Optimization
- JWT Payload เก็บเฉพาะ `userId` และ `scope` ปัจจุบัน
- **Permissions Caching:** เก็บ Permission List ใน Redis และดึงมาตรวจสอบเมื่อมี Request
## 4. 📡 API Conventions
### 4.1 Base URL Structure
```
https://backend.np-dms.work/api/v1/{resource}
```
### 4.2 HTTP Methods & Usage
| Method | Usage | Idempotent | Example |
| :------- | :--------------------------- | :--------- | :----------------------------------- |
| `GET` | ดึงข้อมูล (Read) | ✅ Yes | `GET /api/v1/correspondences` |
| `POST` | สร้างข้อมูลใหม่ (Create) | ❌ No\* | `POST /api/v1/correspondences` |
| `PUT` | อัปเดตทั้งหมด (Full Update) | ✅ Yes | `PUT /api/v1/correspondences/:id` |
| `PATCH` | อัปเดตบางส่วน (Partial Update) | ✅ Yes | `PATCH /api/v1/correspondences/:id` |
| `DELETE` | ลบข้อมูล (Soft Delete) | ✅ Yes | `DELETE /api/v1/correspondences/:id` |
* **Note:** `POST` เป็น Idempotent ได้เมื่อใช้ `Idempotency-Key` Header
### 4.3 Request Format
**Request Headers:**
```http
Content-Type: application/json
Authorization: Bearer <access_token>
Idempotency-Key: <uuid> # POST/PUT/DELETE
```
### 4.4 HTTP Status Codes
| Status | Use Case |
| ------------------------- | ------------------------------------------- |
| 200 OK | Successful GET, PUT, PATCH |
| 201 Created | Successful POST |
| 204 No Content | Successful DELETE |
| 400 Bad Request | Validation error, Invalid input |
| 401 Unauthorized | Missing or invalid JWT token |
| 403 Forbidden | Insufficient permissions (RBAC) |
| 404 Not Found | Resource not found |
| 409 Conflict | Duplicate resource, Business rule violation |
| 422 Unprocessable Entity | Business logic error |
| 429 Too Many Requests | Rate limit exceeded |
| 500 Internal Server Error | Unexpected server error |
## 5. 🔄 Response Formats (Standard REST with Meta Data)
เราใช้ Standard REST with Custom Error Format ซึ่งเรียบง่ายและยืดหยุ่นกว่า
### 5.1 Success Response
**Single Resource:**
```typescript
{
"data": {
"id": 1,
"document_number": "CORR-2024-0001",
"subject": "...",
},
"meta": {
"timestamp": "2024-01-01T00:00:00Z",
"version": "1.0"
}
}
```
**Collection (Pagination):**
```typescript
{
"data": [
{ "id": 1, ... },
{ "id": 2, ... }
],
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
},
"timestamp": "2024-01-01T00:00:00Z"
}
}
```
### 5.2 Error Response Format
```typescript
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed on input data",
"statusCode": 400,
"timestamp": "2024-01-01T00:00:00Z",
"path": "/api/correspondences",
"details": [
{
"field": "subject",
"message": "Subject is required",
"value": null
}
]
}
}
```
## 6. 🛠️ NestJS Implementation Details
### 6.1 Global Exception Filter
คลาสจัดการ Error หลักที่จะจับและดัดแปลง Error ส่งคืน Client อย่างสม่ำเสมอ
```typescript
// File: backend/src/common/filters/global-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
let status = HttpStatus.INTERNAL_SERVER_ERROR;
let code = 'INTERNAL_SERVER_ERROR';
let message = 'An unexpected error occurred';
let details = null;
if (exception instanceof HttpException) {
status = exception.getStatus();
const exceptionResponse = exception.getResponse();
if (typeof exceptionResponse === 'object') {
code = (exceptionResponse as any).error || exception.name;
message = (exceptionResponse as any).message || exception.message;
details = (exceptionResponse as any).details;
} else {
message = exceptionResponse;
}
}
// Log error (but don't expose internal details to client)
console.error('Exception:', exception);
response.status(status).json({
error: {
code,
message,
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
...(details && { details }),
},
});
}
}
```
### 6.2 Custom Business Exception
สำหรับจัดการข้อผิดพลาดเชิงความสัมพันธ์ หรือเงื่อนไขธุรกิจ เช่น State Conflict.
```typescript
// File: backend/src/common/exceptions/business.exception.ts
export class BusinessException extends HttpException {
constructor(message: string, code: string = 'BUSINESS_ERROR') {
super(
{
error: code,
message,
},
HttpStatus.UNPROCESSABLE_ENTITY
);
}
}
// Usage Example:
throw new BusinessException(
'Cannot approve correspondence in current status',
'INVALID_WORKFLOW_TRANSITION'
);
```
### 6.3 Validation Pipe Configuration
บังคับ Validation Pipe ก่อนส่งพารามิเตอร์ให้กับ Controller
```typescript
// File: backend/src/main.ts
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // Strip properties not in DTO
forbidNonWhitelisted: true, // Throw error if unknown properties
transform: true, // Auto-transform payloads to DTO instances
transformOptions: {
enableImplicitConversion: true,
},
exceptionFactory: (errors) => {
const details = errors.map((error) => ({
field: error.property,
message: Object.values(error.constraints || {}).join(', '),
value: error.value,
}));
return new HttpException(
{
error: 'VALIDATION_ERROR',
message: 'Validation failed',
details,
},
HttpStatus.BAD_REQUEST
);
},
})
);
```
## 7. 🛡️ API Security & Rate Limiting
### 7.1 Rate Limiting (Redis-backed)
| Endpoint Type | Limit | Scope |
| :------------------ | :----------------- | :---- |
| Anonymous Endpoints | 100 requests/hour | IP |
| Viewer | 500 requests/hour | User |
| Editor | 1000 requests/hour | User |
| Document Control | 2000 requests/hour | User |
| Admin/Superadmin | 5000 requests/hour | User |
| File Upload | 50 requests/hour | User |
| Search | 500 requests/hour | User |
| Authentication | 10 requests/minute | IP |
### 7.2 File Upload Security
- **Virus Scanning:** ใช้ ClamAV scan ทุกไฟล์
- **File Type Validation:** White-list (PDF, DWG, DOCX, XLSX, ZIP)
- **File Size Limit:** 50MB per file
- **Two-Phase Storage:**
1. Upload to `temp/` folder
2. Commit to `permanent/{YYYY}/{MM}/` when operation succeeds
## 8. 🔄 Idempotency
- **ทุก Critical Operation** (Create, Update, Delete) ต้องรองรับ Idempotency
- Client ส่ง Header: `Idempotency-Key: <uuid>`
- Server เช็คว่า Key นี้เคยประมวลผลสำเร็จแล้วหรือไม่
- ถ้าเคยทำแล้ว: ส่งผลลัพธ์เดิมกลับไป (ไม่ทำซ้ำ)
## 9. 📈 Optimization & Additional Guidelines
### 9.1 Caching Strategy
- Master Data: 1 hour
- User Sessions: 30 minutes
- Search Results: 15 minutes
- File Metadata: 1 hour
### 9.2 API Versioning
- **URL-Based Versioning:** `/api/v1/...`, `/api/v2/...`
- **Backward Compatibility:** รองรับ API เวอร์ชันเก่าอย่างน้อย 1 เวอร์ชัน
- ใช้ Deprecation Headers เมื่อมีการยกเลิก Endpoints
### 9.3 Documentation
- **Swagger/OpenAPI:** Auto-generated จาก NestJS Decorators
- **URL:** `https://backend.np-dms.work/api/docs`
## 🎯 สรุป Best Practices
1. **ใช้ DTOs สำหรับ Validation ทุก Request**
2. **ส่ง Idempotency-Key สำหรับ Critical Operations**
3. **ใช้ Proper HTTP Status Codes**
4. **Implement Rate Limiting บน Client Side**
5. **Handle Errors Gracefully และอย่าเปิดเผยข้อผิดพลาดภายใน (DB Errors) สู่ Client**
6. **Cache Frequently-Accessed Data**
7. **Use Pagination สำหรับ Large Datasets เสมอ**
8. **Document ทุก Endpoint ด้วย Swagger**

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,856 @@
# 04.2 Backup & Disaster Recovery
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Status:** Active
**Owner:** Nattanin Peancharoen / DevOps Team
**Last Updated:** 2026-02-23
> 📍 **Backup Target Server:** ASUSTOR AS5403T (Infrastructure & Backup)
> 🖥️ **Primary Source Server:** QNAP TS-473A (Application & Database)
---
## 📖 Overview
This document outlines the backup strategies, scripts (ASUSTOR pulling from QNAP), recovery procedures, and comprehensive disaster recovery planning for LCBP3-DMS.
---
# Backup & Recovery Procedures
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Last Updated:** 2025-12-02
---
## 📋 Overview
This document outlines backup strategies, recovery procedures, and disaster recovery planning for LCBP3-DMS.
---
## 🎯 Backup Strategy
### Backup Schedule
| Data Type | Frequency | Retention | Method |
| ---------------------- | -------------- | --------- | ----------------------- |
| Database (Full) | Daily at 02:00 | 30 days | mysqldump + compression |
| Database (Incremental) | Every 6 hours | 7 days | Binary logs |
| File Uploads | Daily at 03:00 | 30 days | rsync to backup server |
| Configuration Files | Weekly | 90 days | Git repository |
| Elasticsearch Indexes | Weekly | 14 days | Snapshot to S3/NFS |
| Application Logs | Daily | 90 days | Rotation + archival |
### Backup Locations
**Primary Backup:** QNAP NAS `/backup/lcbp3-dms`
**Secondary Backup:** External backup server (rsync)
**Offsite Backup:** Cloud storage (optional - for critical data)
---
## 💾 Database Backup
### Automated Daily Backup Script
```bash
#!/bin/bash
# File: /scripts/backup-database.sh
# Configuration
BACKUP_DIR="/backup/lcbp3-dms/database"
DB_CONTAINER="lcbp3-mariadb"
DB_NAME="lcbp3_dms"
DB_USER="backup_user"
DB_PASS="<BACKUP_USER_PASSWORD>"
RETENTION_DAYS=30
# Create backup directory
BACKUP_FILE="$BACKUP_DIR/lcbp3_$(date +%Y%m%d_%H%M%S).sql.gz"
mkdir -p "$BACKUP_DIR"
# Perform backup
echo "Starting database backup to $BACKUP_FILE"
docker exec $DB_CONTAINER mysqldump \
--user=$DB_USER \
--password=$DB_PASS \
--single-transaction \
--routines \
--triggers \
--databases $DB_NAME \
| gzip > "$BACKUP_FILE"
# Check backup success
if [ $? -eq 0 ]; then
echo "Backup completed successfully"
# Delete old backups
find "$BACKUP_DIR" -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
echo "Old backups cleaned up (retention: $RETENTION_DAYS days)"
else
echo "ERROR: Backup failed!"
exit 1
fi
```
### Schedule with Cron
```bash
# Edit crontab
crontab -e
# Add backup job (runs daily at 2 AM)
0 2 * * * /scripts/backup-database.sh >> /var/log/backup-database.log 2>&1
```
### Manual Database Backup
```bash
# Backup specific database
docker exec lcbp3-mariadb mysqldump \
-u root -p \
--single-transaction \
lcbp3_dms > backup_$(date +%Y%m%d).sql
# Compress backup
gzip backup_$(date +%Y%m%d).sql
```
---
## 📂 File Uploads Backup
### Automated Rsync Backup
```bash
#!/bin/bash
# File: /scripts/backup-uploads.sh
SOURCE="/var/lib/docker/volumes/lcbp3_uploads/_data"
DEST="/backup/lcbp3-dms/uploads"
RETENTION_DAYS=30
# Create incremental backup with rsync
rsync -av --delete \
--backup --backup-dir="$DEST/backup-$(date +%Y%m%d)" \
"$SOURCE/" "$DEST/current/"
# Cleanup old backups
find "$DEST" -maxdepth 1 -type d -name "backup-*" -mtime +$RETENTION_DAYS -exec rm -rf {} \;
echo "Upload backup completed: $(date)"
```
### Schedule Uploads Backup
```bash
# Run daily at 3 AM
0 3 * * * /scripts/backup-uploads.sh >> /var/log/backup-uploads.log 2>&1
```
---
## 🔄 Database Recovery
### Full Database Restore
```bash
# Step 1: Stop backend application
docker stop lcbp3-backend
# Step 2: Restore database from backup
gunzip < backup_20241201.sql.gz | \
docker exec -i lcbp3-mariadb mysql -u root -p lcbp3_dms
# Step 3: Verify restore
docker exec lcbp3-mariadb mysql -u root -p -e "
USE lcbp3_dms;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM correspondences;
"
# Step 4: Restart backend
docker start lcbp3-backend
```
### Point-in-Time Recovery (Using Binary Logs)
```bash
# Step 1: Restore last full backup
gunzip < backup_20241201_020000.sql.gz | \
docker exec -i lcbp3-mariadb mysql -u root -p lcbp3_dms
# Step 2: Apply binary logs since backup
docker exec lcbp3-mariadb mysqlbinlog \
--start-datetime="2024-12-01 02:00:00" \
--stop-datetime="2024-12-01 14:30:00" \
/var/lib/mysql/mysql-bin.000001 | \
docker exec -i lcbp3-mariadb mysql -u root -p lcbp3_dms
```
---
## 📁 File Uploads Recovery
### Restore from Backup
```bash
# Stop backend to prevent file operations
docker stop lcbp3-backend
# Restore files
rsync -av \
/backup/lcbp3-dms/uploads/current/ \
/var/lib/docker/volumes/lcbp3_uploads/_data/
# Verify permissions
docker exec lcbp3-backend chown -R node:node /app/uploads
# Restart backend
docker start lcbp3-backend
```
---
## 🚨 Disaster Recovery Plan
### RTO & RPO
- **RTO (Recovery Time Objective):** 4 hours
- **RPO (Recovery Point Objective):** 24 hours (for files), 6 hours (for database)
### DR Scenarios
#### Scenario 1: Database Corruption
**Detection:** Database errors in logs, application errors
**Recovery Time:** 30 minutes
**Steps:**
1. Stop backend
2. Restore last full backup
3. Apply binary logs (if needed)
4. Verify data integrity
5. Restart services
#### Scenario 2: Complete Server Failure
**Detection:** Server unresponsive
**Recovery Time:** 4 hours
**Steps:**
1. Provision new QNAP server or VM
2. Install Docker & Container Station
3. Clone Git repository
4. Restore database backup
5. Restore file uploads
6. Deploy containers
7. Update DNS (if needed)
8. Verify functionality
#### Scenario 3: Ransomware Attack
**Detection:** Encrypted files, ransom note
**Recovery Time:** 6 hours
**Steps:**
1. **DO NOT pay ransom**
2. Isolate infected server
3. Provision clean environment
4. Restore from offsite backup
5. Scan restored backup for malware
6. Deploy and verify
7. Review security logs
8. Implement additional security measures
---
## ✅ Backup Verification
### Weekly Backup Testing
```bash
#!/bin/bash
# File: /scripts/test-backup.sh
# Create temporary test database
docker exec lcbp3-mariadb mysql -u root -p -e "
CREATE DATABASE IF NOT EXISTS test_restore;
"
# Restore latest backup to test database
LATEST_BACKUP=$(ls -t /backup/lcbp3-dms/database/*.sql.gz | head -1)
gunzip < "$LATEST_BACKUP" | \
sed 's/USE `lcbp3_dms`/USE `test_restore`/g' | \
docker exec -i lcbp3-mariadb mysql -u root -p
# Verify table counts
docker exec lcbp3-mariadb mysql -u root -p -e "
SELECT COUNT(*) FROM test_restore.users;
SELECT COUNT(*) FROM test_restore.correspondences;
"
# Cleanup
docker exec lcbp3-mariadb mysql -u root -p -e "
DROP DATABASE test_restore;
"
echo "Backup verification completed: $(date)"
```
### Monthly DR Drill
- Test full system restore on standby server
- Document time taken and issues encountered
- Update DR procedures based on findings
---
## 📊 Backup Monitoring
### Backup Status Dashboard
Monitor:
- ✅ Last successful backup timestamp
- ✅ Backup file size (detect anomalies)
- ✅ Backup success/failure rate
- ✅ Available backup storage space
### Alerts
Send alert if:
- ❌ Backup fails
- ❌ Backup file size < 50% of average (possible corruption)
- ❌ No backup in last 48 hours
- ❌ Backup storage < 20% free
---
## 🔧 Maintenance
### Optimize Backup Performance
```sql
-- Enable InnoDB compression for large tables
ALTER TABLE correspondences ROW_FORMAT=COMPRESSED;
ALTER TABLE workflow_history ROW_FORMAT=COMPRESSED;
-- Archive old audit logs
-- Move records older than 1 year to archive table
INSERT INTO audit_logs_archive
SELECT * FROM audit_logs
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
DELETE FROM audit_logs
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
```
---
## 📚 Backup Checklist
### Daily Tasks
- [ ] Verify automated backups completed
- [ ] Check backup log files for errors
- [ ] Monitor backup storage space
### Weekly Tasks
- [ ] Test restore from random backup
- [ ] Review backup size trends
- [ ] Verify offsite backups synced
### Monthly Tasks
- [ ] Full DR drill
- [ ] Review and update DR procedures
- [ ] Test backup restoration on different server
### Quarterly Tasks
- [ ] Audit backup access controls
- [ ] Review backup retention policies
- [ ] Update backup documentation
---
## 🔗 Related Documents
- [Deployment Guide](04-01-deployment-guide.md)
- [Monitoring & Alerting](04-03-monitoring-alerting.md)
- [Incident Response](04-07-incident-response.md)
---
**Version:** 1.8.0
**Last Review:** 2025-12-01
**Next Review:** 2026-03-01
---
# Backup Strategy สำหรับ LCBP3-DMS
> 📍 **Deploy on:** ASUSTOR AS5403T (Infrastructure Server)
> 🎯 **Backup Target:** QNAP TS-473A (Application & Database)
> 📄 **Version:** v1.8.0
---
## Overview
ระบบ Backup แบบ Pull-based: ASUSTOR ดึงข้อมูลจาก QNAP เพื่อความปลอดภัย
หาก QNAP ถูกโจมตี ผู้โจมตีจะไม่สามารถลบ Backup บน ASUSTOR ได้
```
┌─────────────────────────────────────────────────────────────────┐
│ BACKUP ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ QNAP (Source) ASUSTOR (Backup Target) │
│ 192.168.10.8 192.168.10.9 │
│ │
│ ┌──────────────┐ SSH/Rsync ┌──────────────────────┐ │
│ │ MariaDB │ ─────────────▶ │ /volume1/backup/db/ │ │
│ │ (mysqldump) │ Daily 2AM │ (Restic Repository) │ │
│ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Redis RDB │ ─────────────▶ │ /volume1/backup/ │ │
│ │ + AOF │ Daily 3AM │ redis/ │ │
│ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ App Config │ ─────────────▶ │ /volume1/backup/ │ │
│ │ + Volumes │ Weekly Sun │ config/ │ │
│ └──────────────┘ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 1. MariaDB Backup
### 1.1 Daily Database Backup Script
```bash
#!/bin/bash
# File: /volume1/np-dms/scripts/backup-mariadb.sh
# Run on: ASUSTOR (Pull from QNAP)
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/volume1/backup/db"
QNAP_IP="192.168.10.8"
DB_NAME="lcbp3_db"
DB_USER="root"
DB_PASSWORD="${MARIADB_ROOT_PASSWORD}"
echo "🔄 Starting MariaDB backup at $DATE"
# Create backup directory
mkdir -p $BACKUP_DIR
# Remote mysqldump via SSH
ssh admin@$QNAP_IP "docker exec mariadb mysqldump \
--single-transaction \
--routines \
--triggers \
-u $DB_USER -p$DB_PASSWORD $DB_NAME" > $BACKUP_DIR/lcbp3_$DATE.sql
# Compress
gzip $BACKUP_DIR/lcbp3_$DATE.sql
# Add to Restic repository
restic -r $BACKUP_DIR/restic-repo backup $BACKUP_DIR/lcbp3_$DATE.sql.gz
# Keep only last 30 days of raw files
find $BACKUP_DIR -name "lcbp3_*.sql.gz" -mtime +30 -delete
echo "✅ MariaDB backup complete: lcbp3_$DATE.sql.gz"
```
### 1.2 Cron Schedule (ASUSTOR)
```cron
# MariaDB daily backup at 2 AM
0 2 * * * /volume1/np-dms/scripts/backup-mariadb.sh >> /var/log/backup-mariadb.log 2>&1
```
---
## 2. Redis Backup
### 2.1 Redis Backup Script
```bash
#!/bin/bash
# File: /volume1/np-dms/scripts/backup-redis.sh
# Run on: ASUSTOR (Pull from QNAP)
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/volume1/backup/redis"
QNAP_IP="192.168.10.8"
echo "🔄 Starting Redis backup at $DATE"
mkdir -p $BACKUP_DIR
# Trigger BGSAVE on QNAP Redis
ssh admin@$QNAP_IP "docker exec cache redis-cli BGSAVE"
sleep 10
# Copy RDB and AOF files
scp admin@$QNAP_IP:/share/np-dms/services/cache/data/dump.rdb $BACKUP_DIR/redis_$DATE.rdb
scp admin@$QNAP_IP:/share/np-dms/services/cache/data/appendonly.aof $BACKUP_DIR/redis_$DATE.aof
# Compress
tar -czf $BACKUP_DIR/redis_$DATE.tar.gz \
$BACKUP_DIR/redis_$DATE.rdb \
$BACKUP_DIR/redis_$DATE.aof
# Cleanup raw files
rm $BACKUP_DIR/redis_$DATE.rdb $BACKUP_DIR/redis_$DATE.aof
echo "✅ Redis backup complete: redis_$DATE.tar.gz"
```
### 2.2 Cron Schedule
```cron
# Redis daily backup at 3 AM
0 3 * * * /volume1/np-dms/scripts/backup-redis.sh >> /var/log/backup-redis.log 2>&1
```
---
## 3. Application Config Backup
### 3.1 Weekly Config Backup Script
```bash
#!/bin/bash
# File: /volume1/np-dms/scripts/backup-config.sh
# Run on: ASUSTOR (Pull from QNAP)
DATE=$(date +%Y%m%d)
BACKUP_DIR="/volume1/backup/config"
QNAP_IP="192.168.10.8"
echo "🔄 Starting config backup at $DATE"
mkdir -p $BACKUP_DIR
# Sync Docker compose files and configs
rsync -avz --delete \
admin@$QNAP_IP:/share/np-dms/ \
$BACKUP_DIR/np-dms_$DATE/ \
--exclude='*/data/*' \
--exclude='*/logs/*' \
--exclude='node_modules'
# Compress
tar -czf $BACKUP_DIR/config_$DATE.tar.gz $BACKUP_DIR/np-dms_$DATE
# Cleanup
rm -rf $BACKUP_DIR/np-dms_$DATE
echo "✅ Config backup complete: config_$DATE.tar.gz"
```
### 3.2 Cron Schedule
```cron
# Config weekly backup on Sunday at 4 AM
0 4 * * 0 /volume1/np-dms/scripts/backup-config.sh >> /var/log/backup-config.log 2>&1
```
---
## 4. Retention Policy
| Backup Type | Frequency | Retention | Storage Est. |
| :---------- | :-------- | :-------- | :----------- |
| MariaDB | Daily | 30 days | ~5GB/month |
| Redis | Daily | 7 days | ~500MB |
| Config | Weekly | 4 weeks | ~200MB |
| Restic | Daily | 6 months | Deduplicated |
---
## 5. Restic Repository Setup
```bash
# Initialize Restic repository (one-time)
restic init -r /volume1/backup/restic-repo
# Set password in environment
export RESTIC_PASSWORD="your-secure-backup-password"
# Check repository status
restic -r /volume1/backup/restic-repo snapshots
# Prune old snapshots (keep 30 daily, 4 weekly, 6 monthly)
restic -r /volume1/backup/restic-repo forget \
--keep-daily 30 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
```
---
## 6. Verification Script
```bash
#!/bin/bash
# File: /volume1/np-dms/scripts/verify-backup.sh
echo "📋 Backup Verification Report"
echo "=============================="
echo ""
# Check latest MariaDB backup
LATEST_DB=$(ls -t /volume1/backup/db/*.sql.gz 2>/dev/null | head -1)
if [ -n "$LATEST_DB" ]; then
echo "✅ Latest DB backup: $LATEST_DB"
echo " Size: $(du -h $LATEST_DB | cut -f1)"
else
echo "❌ No DB backup found!"
fi
# Check latest Redis backup
LATEST_REDIS=$(ls -t /volume1/backup/redis/*.tar.gz 2>/dev/null | head -1)
if [ -n "$LATEST_REDIS" ]; then
echo "✅ Latest Redis backup: $LATEST_REDIS"
else
echo "❌ No Redis backup found!"
fi
# Check Restic repository
echo ""
echo "📦 Restic Snapshots:"
restic -r /volume1/backup/restic-repo snapshots --latest 5
```
---
> 📝 **หมายเหตุ**: เอกสารนี้อ้างอิงจาก Architecture Document **v1.8.0**
---
# Disaster Recovery Plan สำหรับ LCBP3-DMS
> 📍 **Version:** v1.8.0
> 🖥️ **Primary Server:** QNAP TS-473A (Application & Database)
> 💾 **Backup Server:** ASUSTOR AS5403T (Infrastructure & Backup)
---
## RTO/RPO Targets
| Scenario | RTO | RPO | Priority |
| :-------------------------- | :------ | :----- | :------- |
| Single backend node failure | 0 min | 0 | P0 |
| Redis failure | 5 min | 0 | P0 |
| MariaDB failure | 10 min | 0 | P0 |
| QNAP total failure | 2 hours | 15 min | P1 |
| Data corruption | 4 hours | 1 day | P2 |
---
## 1. Quick Recovery Procedures
### 1.1 Service Not Responding
```bash
# Check container status
docker ps -a | grep <service-name>
# Restart specific service
docker restart <container-name>
# Check logs for errors
docker logs <container-name> --tail 100
```
### 1.2 Redis Failure
```bash
# Check status
docker exec cache redis-cli ping
# Restart
docker restart cache
# Verify
docker exec cache redis-cli ping
```
### 1.3 MariaDB Failure
```bash
# Check status
docker exec mariadb mysql -u root -p -e "SELECT 1"
# Restart
docker restart mariadb
# Wait for startup
sleep 30
# Verify
docker exec mariadb mysql -u root -p -e "SHOW DATABASES"
```
---
## 2. Full System Recovery
### 2.1 Recovery Prerequisites (ASUSTOR)
ตรวจสอบว่า Backup files พร้อมใช้งาน:
```bash
# SSH to ASUSTOR
ssh admin@192.168.10.9
# List available backups
ls -la /volume1/backup/db/
ls -la /volume1/backup/redis/
ls -la /volume1/backup/config/
# Check Restic snapshots
restic -r /volume1/backup/restic-repo snapshots
```
### 2.2 QNAP Recovery Script
```bash
#!/bin/bash
# File: /volume1/np-dms/scripts/disaster-recovery.sh
# Run on: ASUSTOR (Push to QNAP)
QNAP_IP="192.168.10.8"
BACKUP_DIR="/volume1/backup"
echo "🚨 Starting Disaster Recovery..."
echo "================================"
# 1. Restore Docker Network
echo "1⃣ Creating Docker network..."
ssh admin@$QNAP_IP "docker network create lcbp3 || true"
# 2. Restore config files
echo "2⃣ Restoring configuration files..."
LATEST_CONFIG=$(ls -t $BACKUP_DIR/config/*.tar.gz | head -1)
tar -xzf $LATEST_CONFIG -C /tmp/
rsync -avz /tmp/np-dms/ admin@$QNAP_IP:/share/np-dms/
# 3. Start infrastructure services
echo "3⃣ Starting MariaDB..."
ssh admin@$QNAP_IP "cd /share/np-dms/mariadb && docker-compose up -d"
sleep 30
# 4. Restore database
echo "4⃣ Restoring database..."
LATEST_DB=$(ls -t $BACKUP_DIR/db/*.sql.gz | head -1)
gunzip -c $LATEST_DB | ssh admin@$QNAP_IP "docker exec -i mariadb mysql -u root -p\$MYSQL_ROOT_PASSWORD lcbp3_db"
# 5. Start Redis
echo "5⃣ Starting Redis..."
ssh admin@$QNAP_IP "cd /share/np-dms/services && docker-compose up -d cache"
# 6. Restore Redis data (if needed)
echo "6⃣ Restoring Redis data..."
LATEST_REDIS=$(ls -t $BACKUP_DIR/redis/*.tar.gz | head -1)
tar -xzf $LATEST_REDIS -C /tmp/
scp /tmp/redis_*.rdb admin@$QNAP_IP:/share/np-dms/services/cache/data/dump.rdb
ssh admin@$QNAP_IP "docker restart cache"
# 7. Start remaining services
echo "7⃣ Starting application services..."
ssh admin@$QNAP_IP "cd /share/np-dms/services && docker-compose up -d"
ssh admin@$QNAP_IP "cd /share/np-dms/npm && docker-compose up -d"
# 8. Health check
echo "8⃣ Running health checks..."
sleep 60
curl -f https://lcbp3.np-dms.work/health || echo "⚠️ Frontend not ready"
curl -f https://backend.np-dms.work/health || echo "⚠️ Backend not ready"
echo ""
echo "✅ Disaster Recovery Complete"
echo "⚠️ Please verify system functionality manually"
```
---
## 3. Data Corruption Recovery
### 3.1 Point-in-Time Recovery (Database)
```bash
# List available Restic snapshots
restic -r /volume1/backup/restic-repo snapshots
# Restore specific snapshot
restic -r /volume1/backup/restic-repo restore <snapshot-id> --target /tmp/restore/
# Apply restored backup
gunzip -c /tmp/restore/lcbp3_*.sql.gz | \
ssh admin@192.168.10.8 "docker exec -i mariadb mysql -u root -p\$MYSQL_ROOT_PASSWORD lcbp3_db"
```
### 3.2 Selective Table Recovery
```bash
# Extract specific tables from backup
gunzip -c /volume1/backup/db/lcbp3_YYYYMMDD.sql.gz | \
grep -A1000 "CREATE TABLE \`documents\`" | \
grep -B1000 "UNLOCK TABLES" > /tmp/documents_table.sql
# Restore specific table
ssh admin@192.168.10.8 "docker exec -i mariadb mysql -u root -p\$MYSQL_ROOT_PASSWORD lcbp3_db" < /tmp/documents_table.sql
```
---
## 4. Communication & Escalation
### 4.1 Incident Response
| Severity | Response Time | Notify |
| :------- | :------------ | :----------------------------- |
| P0 | Immediate | Admin Team + Management |
| P1 | 30 minutes | Admin Team |
| P2 | 2 hours | Admin Team (next business day) |
### 4.2 Post-Incident Checklist
- [ ] Identify root cause
- [ ] Document timeline of events
- [ ] Verify all services restored
- [ ] Check data integrity
- [ ] Update monitoring alerts if needed
- [ ] Create incident report
---
## 5. Testing Schedule
| Test Type | Frequency | Last Tested | Next Due |
| :---------------------- | :-------- | :---------- | :------- |
| Backup Verification | Weekly | - | - |
| Single Service Recovery | Monthly | - | - |
| Full DR Test | Quarterly | - | - |
---
> 📝 **หมายเหตุ**: เอกสารนี้อ้างอิงจาก Architecture Document **v1.8.0**

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,937 @@
# Deployment Guide: LCBP3-DMS
---
**Project:** LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)
**Version:** 1.8.0
**Last Updated:** 2025-12-02
**Owner:** Operations Team
**Status:** Active
---
## 📋 Overview
This guide provides step-by-step instructions for deploying the LCBP3-DMS system on QNAP Container Station using Docker Compose with Blue-Green deployment strategy.
### Deployment Strategy
- **Platform:** QNAP TS-473A with Container Station
- **Orchestration:** Docker Compose
- **Deployment Method:** Blue-Green Deployment
- **Zero Downtime:** Yes
- **Rollback Capability:** Instant rollback via NGINX switch
---
## 🎯 Prerequisites
### Hardware Requirements
| Component | Minimum Specification |
| ---------- | -------------------------- |
| CPU | 4 cores @ 2.0 GHz |
| RAM | 16 GB |
| Storage | 500 GB SSD (System + Data) |
| Network | 1 Gbps Ethernet |
| QNAP Model | TS-473A or equivalent |
### Software Requirements
| Software | Version | Purpose |
| ----------------- | ------- | ------------------------ |
| QNAP QTS | 5.x+ | Operating System |
| Container Station | 3.x+ | Docker Management |
| Docker | 20.10+ | Container Runtime |
| Docker Compose | 2.x+ | Multi-container Orchestr |
### Network Requirements
- Static IP address for QNAP server
- Domain name (e.g., `lcbp3-dms.example.com`)
- SSL certificate (Let's Encrypt or commercial)
- Firewall rules:
- Port 80 (HTTP → HTTPS redirect)
- Port 443 (HTTPS)
- Port 22 (SSH for management)
---
## 🏗️ Infrastructure Setup
### 1. Directory Structure
Create the following directory structure on QNAP:
```bash
# SSH into QNAP
ssh admin@qnap-ip
# Create base directory
mkdir -p /volume1/lcbp3
# Create blue-green environments
mkdir -p /volume1/lcbp3/blue
mkdir -p /volume1/lcbp3/green
# Create shared directories
mkdir -p /volume1/lcbp3/shared/uploads
mkdir -p /volume1/lcbp3/shared/logs
mkdir -p /volume1/lcbp3/shared/backups
# Create persistent volumes
mkdir -p /volume1/lcbp3/volumes/mariadb-data
mkdir -p /volume1/lcbp3/volumes/redis-data
mkdir -p /volume1/lcbp3/volumes/elastic-data
# Create NGINX proxy directory
mkdir -p /volume1/lcbp3/nginx-proxy
# Set permissions
chmod -R 755 /volume1/lcbp3
chown -R admin:administrators /volume1/lcbp3
```
**Final Structure:**
```
/volume1/lcbp3/
├── blue/ # Blue environment
│ ├── docker-compose.yml
│ ├── .env.production
│ └── nginx.conf
├── green/ # Green environment
│ ├── docker-compose.yml
│ ├── .env.production
│ └── nginx.conf
├── nginx-proxy/ # Main reverse proxy
│ ├── docker-compose.yml
│ ├── nginx.conf
│ └── ssl/
│ ├── cert.pem
│ └── key.pem
├── shared/ # Shared across blue/green
│ ├── uploads/
│ ├── logs/
│ └── backups/
├── volumes/ # Persistent data
│ ├── mariadb-data/
│ ├── redis-data/
│ └── elastic-data/
├── scripts/ # Deployment scripts
│ ├── deploy.sh
│ ├── rollback.sh
│ └── health-check.sh
└── current # File containing "blue" or "green"
```
### 2. SSL Certificate Setup
```bash
# Option 1: Let's Encrypt (Recommended)
# Install certbot on QNAP
opkg install certbot
# Generate certificate
certbot certonly --standalone \
-d lcbp3-dms.example.com \
--email admin@example.com \
--agree-tos
# Copy to nginx-proxy
cp /etc/letsencrypt/live/lcbp3-dms.example.com/fullchain.pem \
/volume1/lcbp3/nginx-proxy/ssl/cert.pem
cp /etc/letsencrypt/live/lcbp3-dms.example.com/privkey.pem \
/volume1/lcbp3/nginx-proxy/ssl/key.pem
# Option 2: Commercial Certificate
# Upload cert.pem and key.pem to /volume1/lcbp3/nginx-proxy/ssl/
```
---
## 📝 Configuration Files
### 1. Environment Variables (.env.production)
Create `.env.production` in both `blue/` and `green/` directories:
```bash
# File: /volume1/lcbp3/blue/.env.production
# DO NOT commit this file to Git!
# Application
NODE_ENV=production
APP_NAME=LCBP3-DMS
APP_URL=https://lcbp3-dms.example.com
# Database
DB_HOST=lcbp3-mariadb
DB_PORT=3306
DB_USERNAME=lcbp3_user
DB_PASSWORD=<CHANGE_ME_STRONG_PASSWORD>
DB_DATABASE=lcbp3_dms
DB_POOL_SIZE=20
# Redis
REDIS_HOST=lcbp3-redis
REDIS_PORT=6379
REDIS_PASSWORD=<CHANGE_ME_STRONG_PASSWORD>
REDIS_DB=0
# JWT Authentication
JWT_SECRET=<CHANGE_ME_RANDOM_64_CHAR_STRING>
JWT_EXPIRES_IN=8h
JWT_REFRESH_EXPIRES_IN=7d
# File Storage
UPLOAD_PATH=/app/uploads
MAX_FILE_SIZE=52428800
ALLOWED_FILE_TYPES=.pdf,.doc,.docx,.xls,.xlsx,.dwg,.zip
# Email (SMTP)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USERNAME=<YOUR_EMAIL>
SMTP_PASSWORD=<YOUR_APP_PASSWORD>
SMTP_FROM=noreply@example.com
# Elasticsearch
ELASTICSEARCH_NODE=http://lcbp3-elasticsearch:9200
ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=<CHANGE_ME>
# Rate Limiting
THROTTLE_TTL=60
THROTTLE_LIMIT=100
# Logging
LOG_LEVEL=info
LOG_FILE_PATH=/app/logs
# ClamAV (Virus Scanning)
CLAMAV_HOST=lcbp3-clamav
CLAMAV_PORT=3310
```
### 2. Docker Compose - Blue Environment
```yaml
# File: /volume1/lcbp3/blue/docker-compose.yml
version: '3.8'
services:
backend:
image: lcbp3-backend:latest
container_name: lcbp3-blue-backend
restart: unless-stopped
env_file:
- .env.production
volumes:
- /volume1/lcbp3/shared/uploads:/app/uploads
- /volume1/lcbp3/shared/logs:/app/logs
depends_on:
- mariadb
- redis
- elasticsearch
networks:
- lcbp3-network
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
frontend:
image: lcbp3-frontend:latest
container_name: lcbp3-blue-frontend
restart: unless-stopped
environment:
- NEXT_PUBLIC_API_URL=https://lcbp3-dms.example.com/api
depends_on:
- backend
networks:
- lcbp3-network
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000']
interval: 30s
timeout: 10s
retries: 3
mariadb:
image: mariadb:11.8
container_name: lcbp3-mariadb
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- /volume1/lcbp3/volumes/mariadb-data:/var/lib/mysql
networks:
- lcbp3-network
command: >
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--max_connections=200
--innodb_buffer_pool_size=2G
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: lcbp3-redis
restart: unless-stopped
command: >
redis-server
--requirepass ${REDIS_PASSWORD}
--appendonly yes
--appendfsync everysec
--maxmemory 2gb
--maxmemory-policy allkeys-lru
volumes:
- /volume1/lcbp3/volumes/redis-data:/data
networks:
- lcbp3-network
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 3s
retries: 3
elasticsearch:
image: elasticsearch:8.11.0
container_name: lcbp3-elasticsearch
restart: unless-stopped
environment:
- discovery.type=single-node
- xpack.security.enabled=true
- ELASTIC_PASSWORD=${ELASTICSEARCH_PASSWORD}
- "ES_JAVA_OPTS=-Xms2g -Xmx2g"
volumes:
- /volume1/lcbp3/volumes/elastic-data:/usr/share/elasticsearch/data
networks:
- lcbp3-network
healthcheck:
test: ['CMD-SHELL', 'curl -f http://localhost:9200/_cluster/health || exit 1']
interval: 30s
timeout: 10s
retries: 5
networks:
lcbp3-network:
name: lcbp3-blue-network
driver: bridge
```
### 3. Docker Compose - NGINX Proxy
```yaml
# File: /volume1/lcbp3/nginx-proxy/docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: lcbp3-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- /volume1/lcbp3/shared/logs/nginx:/var/log/nginx
networks:
- lcbp3-blue-network
- lcbp3-green-network
healthcheck:
test: ['CMD', 'nginx', '-t']
interval: 30s
timeout: 10s
retries: 3
networks:
lcbp3-blue-network:
external: true
lcbp3-green-network:
external: true
```
### 4. NGINX Configuration
```nginx
# File: /volume1/lcbp3/nginx-proxy/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 50M;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss;
# Upstream backends (switch between blue/green)
upstream backend {
server lcbp3-blue-backend:3000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream frontend {
server lcbp3-blue-frontend:3000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
# HTTP to HTTPS redirect
server {
listen 80;
server_name lcbp3-dms.example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS server
server {
listen 443 ssl http2;
server_name lcbp3-dms.example.com;
# SSL configuration
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Frontend (Next.js)
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# Backend API
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts for file uploads
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
# Health check endpoint (no logging)
location /health {
proxy_pass http://backend/health;
access_log off;
}
# Static files caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://frontend;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
```
---
## 🚀 Initial Deployment
### Step 1: Prepare Docker Images
```bash
# Build images (on development machine)
cd /path/to/lcbp3/backend
docker build -t lcbp3-backend:1.0.0 .
docker tag lcbp3-backend:1.0.0 lcbp3-backend:latest
cd /path/to/lcbp3/frontend
docker build -t lcbp3-frontend:1.0.0 .
docker tag lcbp3-frontend:1.0.0 lcbp3-frontend:latest
# Save images to tar files
docker save lcbp3-backend:latest | gzip > lcbp3-backend-latest.tar.gz
docker save lcbp3-frontend:latest | gzip > lcbp3-frontend-latest.tar.gz
# Transfer to QNAP
scp lcbp3-backend-latest.tar.gz admin@qnap-ip:/volume1/lcbp3/
scp lcbp3-frontend-latest.tar.gz admin@qnap-ip:/volume1/lcbp3/
# Load images on QNAP
ssh admin@qnap-ip
cd /volume1/lcbp3
docker load < lcbp3-backend-latest.tar.gz
docker load < lcbp3-frontend-latest.tar.gz
```
### Step 2: Initialize Database
```bash
# Start MariaDB only
cd /volume1/lcbp3/blue
docker-compose up -d mariadb
# Wait for MariaDB to be ready
docker exec lcbp3-mariadb mysqladmin ping -h localhost
# Run migrations
docker-compose up -d backend
docker exec lcbp3-blue-backend npm run migration:run
# Seed initial data (if needed)
docker exec lcbp3-blue-backend npm run seed
```
### Step 3: Start Blue Environment
```bash
cd /volume1/lcbp3/blue
# Start all services
docker-compose up -d
# Check status
docker-compose ps
# View logs
docker-compose logs -f
# Wait for health checks
sleep 30
# Test health endpoint
curl http://localhost:3000/health
```
### Step 4: Start NGINX Proxy
```bash
cd /volume1/lcbp3/nginx-proxy
# Create networks (if not exist)
docker network create lcbp3-blue-network
docker network create lcbp3-green-network
# Start NGINX
docker-compose up -d
# Test NGINX configuration
docker exec lcbp3-nginx nginx -t
# Check NGINX logs
docker logs lcbp3-nginx
```
### Step 5: Set Current Environment
```bash
# Mark blue as current
echo "blue" > /volume1/lcbp3/current
```
### Step 6: Verify Deployment
```bash
# Test HTTPS endpoint
curl -k https://lcbp3-dms.example.com/health
# Test API
curl -k https://lcbp3-dms.example.com/api/health
# Check all containers
docker ps --filter "name=lcbp3"
# Check logs for errors
docker-compose -f /volume1/lcbp3/blue/docker-compose.yml logs --tail=100
```
---
## 🔄 Blue-Green Deployment Process
### Deployment Script
```bash
# File: /volume1/lcbp3/scripts/deploy.sh
#!/bin/bash
set -e # Exit on error
# Configuration
LCBP3_DIR="/volume1/lcbp3"
CURRENT=$(cat $LCBP3_DIR/current)
TARGET=$([[ "$CURRENT" == "blue" ]] && echo "green" || echo "blue")
echo "========================================="
echo "LCBP3-DMS Blue-Green Deployment"
echo "========================================="
echo "Current environment: $CURRENT"
echo "Target environment: $TARGET"
echo "========================================="
# Step 1: Backup database
echo "[1/9] Creating database backup..."
BACKUP_FILE="$LCBP3_DIR/shared/backups/db-backup-$(date +%Y%m%d-%H%M%S).sql"
docker exec lcbp3-mariadb mysqldump -u root -p${DB_PASSWORD} lcbp3_dms > $BACKUP_FILE
gzip $BACKUP_FILE
echo "✓ Backup created: $BACKUP_FILE.gz"
# Step 2: Pull latest images
echo "[2/9] Pulling latest Docker images..."
cd $LCBP3_DIR/$TARGET
docker-compose pull
echo "✓ Images pulled"
# Step 3: Update configuration
echo "[3/9] Updating configuration..."
# Copy .env if changed
if [ -f "$LCBP3_DIR/.env.production.new" ]; then
cp $LCBP3_DIR/.env.production.new $LCBP3_DIR/$TARGET/.env.production
echo "✓ Configuration updated"
fi
# Step 4: Start target environment
echo "[4/9] Starting $TARGET environment..."
docker-compose up -d
echo "$TARGET environment started"
# Step 5: Wait for services to be ready
echo "[5/9] Waiting for services to be healthy..."
sleep 10
# Check backend health
for i in {1..30}; do
if docker exec lcbp3-${TARGET}-backend curl -f http://localhost:3000/health > /dev/null 2>&1; then
echo "✓ Backend is healthy"
break
fi
if [ $i -eq 30 ]; then
echo "✗ Backend health check failed!"
docker-compose logs backend
exit 1
fi
sleep 2
done
# Step 6: Run database migrations
echo "[6/9] Running database migrations..."
docker exec lcbp3-${TARGET}-backend npm run migration:run
echo "✓ Migrations completed"
# Step 7: Switch NGINX to target environment
echo "[7/9] Switching NGINX to $TARGET..."
sed -i "s/lcbp3-${CURRENT}-backend/lcbp3-${TARGET}-backend/g" $LCBP3_DIR/nginx-proxy/nginx.conf
sed -i "s/lcbp3-${CURRENT}-frontend/lcbp3-${TARGET}-frontend/g" $LCBP3_DIR/nginx-proxy/nginx.conf
docker exec lcbp3-nginx nginx -t
docker exec lcbp3-nginx nginx -s reload
echo "✓ NGINX switched to $TARGET"
# Step 8: Verify new environment
echo "[8/9] Verifying new environment..."
sleep 5
if curl -f -k https://lcbp3-dms.example.com/health > /dev/null 2>&1; then
echo "✓ New environment is responding"
else
echo "✗ New environment verification failed!"
echo "Rolling back..."
./rollback.sh
exit 1
fi
# Step 9: Stop old environment
echo "[9/9] Stopping $CURRENT environment..."
cd $LCBP3_DIR/$CURRENT
docker-compose down
echo "$CURRENT environment stopped"
# Update current pointer
echo "$TARGET" > $LCBP3_DIR/current
echo "========================================="
echo "✓ Deployment completed successfully!"
echo "Active environment: $TARGET"
echo "========================================="
# Send notification (optional)
# /scripts/send-notification.sh "Deployment completed: $TARGET is now active"
```
### Rollback Script
```bash
# File: /volume1/lcbp3/scripts/rollback.sh
#!/bin/bash
set -e
LCBP3_DIR="/volume1/lcbp3"
CURRENT=$(cat $LCBP3_DIR/current)
PREVIOUS=$([[ "$CURRENT" == "blue" ]] && echo "green" || echo "blue")
echo "========================================="
echo "LCBP3-DMS Rollback"
echo "========================================="
echo "Current: $CURRENT"
echo "Rolling back to: $PREVIOUS"
echo "========================================="
# Switch NGINX back
echo "[1/3] Switching NGINX to $PREVIOUS..."
sed -i "s/lcbp3-${CURRENT}-backend/lcbp3-${PREVIOUS}-backend/g" $LCBP3_DIR/nginx-proxy/nginx.conf
sed -i "s/lcbp3-${CURRENT}-frontend/lcbp3-${PREVIOUS}-frontend/g" $LCBP3_DIR/nginx-proxy/nginx.conf
docker exec lcbp3-nginx nginx -s reload
echo "✓ NGINX switched"
# Start previous environment if stopped
echo "[2/3] Ensuring $PREVIOUS environment is running..."
cd $LCBP3_DIR/$PREVIOUS
docker-compose up -d
sleep 10
echo "$PREVIOUS environment is running"
# Verify
echo "[3/3] Verifying rollback..."
if curl -f -k https://lcbp3-dms.example.com/health > /dev/null 2>&1; then
echo "✓ Rollback successful"
echo "$PREVIOUS" > $LCBP3_DIR/current
else
echo "✗ Rollback verification failed!"
exit 1
fi
echo "========================================="
echo "✓ Rollback completed"
echo "Active environment: $PREVIOUS"
echo "========================================="
```
### Make Scripts Executable
```bash
chmod +x /volume1/lcbp3/scripts/deploy.sh
chmod +x /volume1/lcbp3/scripts/rollback.sh
```
---
## 📋 Deployment Checklist
### Pre-Deployment
- [ ] Backup current database
- [ ] Tag Docker images with version
- [ ] Update `.env.production` if needed
- [ ] Review migration scripts
- [ ] Notify stakeholders of deployment window
- [ ] Verify SSL certificate validity (> 30 days)
- [ ] Check disk space (> 20% free)
- [ ] Review recent error logs
### During Deployment
- [ ] Pull latest Docker images
- [ ] Start target environment (blue/green)
- [ ] Run database migrations
- [ ] Verify health checks pass
- [ ] Switch NGINX proxy
- [ ] Verify application responds correctly
- [ ] Check for errors in logs
- [ ] Monitor performance metrics
### Post-Deployment
- [ ] Monitor logs for 30 minutes
- [ ] Check performance metrics
- [ ] Verify all features working
- [ ] Test critical user flows
- [ ] Stop old environment
- [ ] Update deployment log
- [ ] Notify stakeholders of completion
- [ ] Archive old Docker images
---
## 🔍 Troubleshooting
### Common Issues
#### 1. Container Won't Start
```bash
# Check logs
docker logs lcbp3-blue-backend
# Check resource usage
docker stats
# Restart container
docker restart lcbp3-blue-backend
```
#### 2. Database Connection Failed
```bash
# Check MariaDB is running
docker ps | grep mariadb
# Test connection
docker exec lcbp3-mariadb mysql -u lcbp3_user -p -e "SELECT 1"
# Check environment variables
docker exec lcbp3-blue-backend env | grep DB_
```
#### 3. NGINX 502 Bad Gateway
```bash
# Check backend is running
curl http://localhost:3000/health
# Check NGINX configuration
docker exec lcbp3-nginx nginx -t
# Check NGINX logs
docker logs lcbp3-nginx
# Reload NGINX
docker exec lcbp3-nginx nginx -s reload
```
#### 4. Migration Failed
```bash
# Check migration status
docker exec lcbp3-blue-backend npm run migration:show
# Revert last migration
docker exec lcbp3-blue-backend npm run migration:revert
# Re-run migrations
docker exec lcbp3-blue-backend npm run migration:run
```
---
## 📊 Monitoring
### Health Checks
```bash
# Backend health
curl https://lcbp3-dms.example.com/health
# Database health
docker exec lcbp3-mariadb mysqladmin ping
# Redis health
docker exec lcbp3-redis redis-cli ping
# All containers status
docker ps --filter "name=lcbp3" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
```
### Performance Monitoring
```bash
# Container resource usage
docker stats --no-stream
# Disk usage
df -h /volume1/lcbp3
# Database size
docker exec lcbp3-mariadb mysql -u root -p -e "
SELECT table_schema AS 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'lcbp3_dms'
GROUP BY table_schema;"
```
---
## 🔐 Security Best Practices
1. **Change Default Passwords:** Update all passwords in `.env.production`
2. **SSL/TLS:** Always use HTTPS in production
3. **Firewall:** Only expose ports 80, 443, and 22 (SSH)
4. **Regular Updates:** Keep Docker images updated
5. **Backup Encryption:** Encrypt database backups
6. **Access Control:** Limit SSH access to specific IPs
7. **Secrets Management:** Never commit `.env` files to Git
8. **Log Monitoring:** Review logs daily for suspicious activity
---
## 📚 Related Documentation
- [Environment Setup Guide](04-02-environment-setup.md)
- [Backup & Recovery](04-04-backup-recovery.md)
- [Monitoring & Alerting](04-03-monitoring-alerting.md)
- [Maintenance Procedures](04-05-maintenance-procedures.md)
- [ADR-015: Deployment Infrastructure](../05-decisions/ADR-015-deployment-infrastructure.md)
---
**Version:** 1.8.0
**Last Updated:** 2025-12-02
**Next Review:** 2026-06-01

View File

@@ -0,0 +1,501 @@
# Maintenance Procedures
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Last Updated:** 2025-12-02
---
## 📋 Overview
This document outlines routine maintenance tasks, update procedures, and optimization guidelines for LCBP3-DMS.
---
## 📅 Maintenance Schedule
### Daily Tasks
- Monitor system health and backups
- Review error logs
- Check disk space
### Weekly Tasks
- Database optimization
- Log rotation and cleanup
- Security patch review
- Performance monitoring review
### Monthly Tasks
- SSL certificate check
- Dependency updates (Security patches)
- Database maintenance
- Backup restoration test
### Quarterly Tasks
- Full system update
- Capacity planning review
- Security audit
- Disaster recovery drill
---
## 🔄 Update Procedures
### Application Updates
#### Backend Update
```bash
#!/bin/bash
# File: /scripts/update-backend.sh
# Step 1: Backup database
/scripts/backup-database.sh
# Step 2: Pull latest code
cd /app/lcbp3/backend
git pull origin main
# Step 3: Install dependencies
docker exec lcbp3-backend npm install
# Step 4: Run migrations
docker exec lcbp3-backend npm run migration:run
# Step 5: Build application
docker exec lcbp3-backend npm run build
# Step 6: Restart backend
docker restart lcbp3-backend
# Step 7: Verify health
sleep 10
curl -f http://localhost:3000/health || {
echo "Health check failed! Rolling back..."
docker exec lcbp3-backend npm run migration:revert
docker restart lcbp3-backend
exit 1
}
echo "Backend updated successfully"
```
#### Frontend Update
```bash
#!/bin/bash
# File: /scripts/update-frontend.sh
# Step 1: Pull latest code
cd /app/lcbp3/frontend
git pull origin main
# Step 2: Install dependencies
docker exec lcbp3-frontend npm install
# Step 3: Build application
docker exec lcbp3-frontend npm run build
# Step 4: Restart frontend
docker restart lcbp3-frontend
# Step 5: Verify
sleep 10
curl -f http://localhost:3001 || {
echo "Frontend failed to start!"
exit 1
}
echo "Frontend updated successfully"
```
### Zero-Downtime Deployment
```bash
#!/bin/bash
# File: /scripts/zero-downtime-deploy.sh
# Using blue-green deployment strategy
# Step 1: Start new "green" backend
docker-compose -f docker-compose.green.yml up -d backend
# Step 2: Wait for health check
for i in {1..30}; do
curl -f http://localhost:3002/health && break
sleep 2
done
# Step 3: Switch NGINX to green
docker exec lcbp3-nginx nginx -s reload
# Step 4: Stop old "blue" backend
docker stop lcbp3-backend-blue
echo "Deployment completed with zero downtime"
```
---
## 🗄️ Database Maintenance
### Weekly Database Optimization
```sql
-- File: /scripts/optimize-database.sql
-- Optimize tables
OPTIMIZE TABLE correspondences;
OPTIMIZE TABLE rfas;
OPTIMIZE TABLE workflow_instances;
OPTIMIZE TABLE attachments;
-- Analyze tables for query optimization
ANALYZE TABLE correspondences;
ANALYZE TABLE rfas;
-- Check for table corruption
CHECK TABLE correspondences;
CHECK TABLE rfas;
-- Rebuild indexes if fragmented
ALTER TABLE correspondences ENGINE=InnoDB;
```
```bash
#!/bin/bash
# File: /scripts/weekly-db-maintenance.sh
docker exec lcbp3-mariadb mysql -u root -p lcbp3_dms < /scripts/optimize-database.sql
echo "Database optimization completed: $(date)"
```
### Monthly Database Cleanup
```sql
-- Archive old audit logs (older than 1 year)
INSERT INTO audit_logs_archive
SELECT * FROM audit_logs
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
DELETE FROM audit_logs
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
-- Clean up deleted notifications (older than 90 days)
DELETE FROM notifications
WHERE deleted_at IS NOT NULL
AND deleted_at < DATE_SUB(NOW(), INTERVAL 90 DAY);
-- Clean up expired temp uploads (older than 24h)
DELETE FROM temp_uploads
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 DAY);
-- Optimize after cleanup
OPTIMIZE TABLE audit_logs;
OPTIMIZE TABLE notifications;
OPTIMIZE TABLE temp_uploads;
```
---
## 📦 Dependency Updates
### Security Patch Updates (Monthly)
```bash
#!/bin/bash
# File: /scripts/update-dependencies.sh
cd /app/lcbp3/backend
# Check for security vulnerabilities
npm audit
# Update security patches only (no major versions)
npm audit fix
# Run tests
npm test
# If tests pass, commit and deploy
git add package*.json
git commit -m "chore: security patch updates"
git push origin main
```
### Major Version Updates (Quarterly)
```bash
# Check for outdated packages
npm outdated
# Update one major dependency at a time
npm install @nestjs/core@latest
# Test thoroughly
npm test
npm run test:e2e
# If successful, commit
git commit -am "chore: update @nestjs/core to vX.X.X"
```
---
## 🧹 Log Management
### Log Rotation Configuration
```bash
# File: /etc/logrotate.d/lcbp3-dms
/app/logs/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 node node
sharedscripts
postrotate
docker exec lcbp3-backend kill -USR1 1
endscript
}
```
### Manual Log Cleanup
```bash
#!/bin/bash
# File: /scripts/cleanup-logs.sh
# Delete logs older than 90 days
find /app/logs -name "*.log" -type f -mtime +90 -delete
# Compress logs older than 7 days
find /app/logs -name "*.log" -type f -mtime +7 -exec gzip {} \;
# Clean Docker logs
docker system prune -f --volumes --filter "until=720h"
echo "Log cleanup completed: $(date)"
```
---
## 🔐 SSL Certificate Renewal
### Check Certificate Expiry
```bash
#!/bin/bash
# File: /scripts/check-ssl-cert.sh
CERT_FILE="/app/nginx/ssl/cert.pem"
EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
echo "SSL certificate expires in $DAYS_LEFT days"
if [ $DAYS_LEFT -lt 30 ]; then
echo "WARNING: SSL certificate expires soon!"
# Send alert
/scripts/send-alert-email.sh "SSL Certificate Expiring" "Certificate expires in $DAYS_LEFT days"
fi
```
### Renew SSL Certificate (Let's Encrypt)
```bash
#!/bin/bash
# File: /scripts/renew-ssl.sh
# Renew certificate
certbot renew --webroot -w /app/nginx/html
# Copy new certificate
cp /etc/letsencrypt/live/lcbp3-dms.example.com/fullchain.pem /app/nginx/ssl/cert.pem
cp /etc/letsencrypt/live/lcbp3-dms.example.com/privkey.pem /app/nginx/ssl/key.pem
# Reload NGINX
docker exec lcbp3-nginx nginx -s reload
echo "SSL certificate renewed: $(date)"
```
---
## 🧪 Performance Optimization
### Database Query Optimization
```sql
-- Find slow queries
SELECT * FROM mysql.slow_log
ORDER BY query_time DESC
LIMIT 10;
-- Add indexes for frequently queried columns
CREATE INDEX idx_correspondences_status ON correspondences(status);
CREATE INDEX idx_rfas_workflow_status ON rfas(workflow_status);
CREATE INDEX idx_attachments_entity ON attachments(entity_type, entity_id);
-- Analyze query execution plan
EXPLAIN SELECT * FROM correspondences
WHERE status = 'PENDING'
AND created_at > DATE_SUB(NOW(), INTERVAL 30 DAY);
```
### Redis Cache Optimization
```bash
#!/bin/bash
# File: /scripts/optimize-redis.sh
# Check Redis memory usage
docker exec lcbp3-redis redis-cli INFO memory
# Set max memory policy
docker exec lcbp3-redis redis-cli CONFIG SET maxmemory 1gb
docker exec lcbp3-redis redis-cli CONFIG SET maxmemory-policy allkeys-lru
# Save configuration
docker exec lcbp3-redis redis-cli CONFIG REWRITE
# Clear stale cache (if needed)
docker exec lcbp3-redis redis-cli FLUSHDB
```
### Application Performance Tuning
```typescript
// Enable production optimizations in NestJS
// File: backend/src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger:
process.env.NODE_ENV === 'production'
? ['error', 'warn']
: ['log', 'error', 'warn', 'debug'],
});
// Enable compression
app.use(compression());
// Enable caching
app.useGlobalInterceptors(new CacheInterceptor());
// Set global timeout
app.use(timeout('30s'));
await app.listen(3000);
}
```
---
## 🔒 Security Maintenance
### Monthly Security Tasks
```bash
#!/bin/bash
# File: /scripts/security-maintenance.sh
# Update system packages
apt-get update && apt-get upgrade -y
# Update ClamAV virus definitions
docker exec lcbp3-clamav freshclam
# Scan for rootkits
rkhunter --check --skip-keypress
# Check for unauthorized users
awk -F: '($3 >= 1000) {print $1}' /etc/passwd
# Review sudo access
cat /etc/sudoers
# Check firewall rules
iptables -L -n -v
echo "Security maintenance completed: $(date)"
```
---
## ✅ Maintenance Checklist
### Pre-Maintenance
- [ ] Announce maintenance window to users
- [ ] Backup database and files
- [ ] Document current system state
- [ ] Prepare rollback plan
### During Maintenance
- [ ] Put system in maintenance mode (if needed)
- [ ] Perform updates/changes
- [ ] Run smoke tests
- [ ] Monitor system health
### Post-Maintenance
- [ ] Verify all services running
- [ ] Run full test suite
- [ ] Monitor performance metrics
- [ ] Communicate completion to users
- [ ] Document changes made
---
## 🔧 Emergency Maintenance
### Unplanned Maintenance Procedures
1. **Assess Urgency**
- Can it wait for scheduled maintenance?
- Is it causing active issues?
2. **Communicate Impact**
- Notify stakeholders immediately
- Estimate downtime
- Provide updates every 30 minutes
3. **Execute Carefully**
- Always backup first
- Have rollback plan ready
- Test in staging if possible
4. **Post-Maintenance Review**
- Document what happened
- Identify preventive measures
- Update runbooks
---
## 📚 Related Documents
- [Deployment Guide](04-01-deployment-guide.md)
- [Backup & Recovery](04-04-backup-recovery.md)
- [Monitoring & Alerting](04-03-monitoring-alerting.md)
---
**Version:** 1.8.0
**Last Review:** 2025-12-01
**Next Review:** 2026-03-01

View File

@@ -0,0 +1,444 @@
# Security Operations
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Last Updated:** 2025-12-02
---
## 📋 Overview
This document outlines security monitoring, access control management, vulnerability management, and security incident response for LCBP3-DMS.
---
## 🔒 Access Control Management
### User Access Review
**Monthly Tasks:**
```bash
#!/bin/bash
# File: /scripts/audit-user-access.sh
# Export active users
docker exec lcbp3-mariadb mysql -u root -p -e "
SELECT user_id, username, email, primary_organization_id, is_active, last_login_at
FROM lcbp3_dms.users
WHERE is_active = 1
ORDER BY last_login_at DESC;
" > /reports/active-users-$(date +%Y%m%d).csv
# Find dormant accounts (no login > 90 days)
docker exec lcbp3-mariadb mysql -u root -p -e "
SELECT user_id, username, email, last_login_at,
DATEDIFF(NOW(), last_login_at) AS days_inactive
FROM lcbp3_dms.users
WHERE is_active = 1
AND (last_login_at IS NULL OR last_login_at < DATE_SUB(NOW(), INTERVAL 90 DAY));
"
echo "User access audit completed: $(date)"
```
### Role & Permission Audit
```sql
-- Review users with elevated permissions
SELECT u.username, u.email, r.role_name, r.scope
FROM users u
JOIN user_assignments ua ON u.user_id = ua.user_id
JOIN roles r ON ua.role_id = r.role_id
WHERE r.role_name IN ('Superadmin', 'Document Controller', 'Project Manager')
ORDER BY r.role_name, u.username;
-- Review Global scope roles (highest privilege)
SELECT u.username, r.role_name
FROM users u
JOIN user_assignments ua ON u.user_id = ua.user_id
JOIN roles r ON ua.role_id = r.role_id
WHERE r.scope = 'Global';
```
---
## 🛡️ Security Monitoring
### Log Monitoring for Security Events
```bash
#!/bin/bash
# File: /scripts/monitor-security-events.sh
# Check for failed login attempts
docker logs lcbp3-backend | grep "Failed login" | tail -20
# Check for unauthorized access attempts (403)
docker logs lcbp3-backend | grep "403" | tail -20
# Check for unusual activity patterns
docker logs lcbp3-backend | grep -E "DELETE|DROP|TRUNCATE" | tail -20
# Check for SQL injection attempts
docker logs lcbp3-backend | grep -i "SELECT.*FROM.*WHERE" | grep -v "legitimate" | tail -20
```
### Failed Login Monitoring
```sql
-- Find accounts with multiple failed login attempts
SELECT username, failed_attempts, locked_until
FROM users
WHERE failed_attempts >= 3
ORDER BY failed_attempts DESC;
-- Unlock user account after verification
UPDATE users
SET failed_attempts = 0, locked_until = NULL
WHERE user_id = ?;
```
---
## 🔐 Secrets & Credentials Management
### Password Rotation Schedule
| Credential | Rotation Frequency | Owner |
| ---------------------- | ------------------------ | ------------ |
| Database Root Password | Every 90 days | DBA |
| Database App Password | Every 90 days | DevOps |
| JWT Secret | Every 180 days | Backend Team |
| Redis Password | Every 90 days | DevOps |
| SMTP Password | When provider requires | Operations |
| SSL Private Key | With certificate renewal | Operations |
### Password Rotation Procedure
```bash
#!/bin/bash
# File: /scripts/rotate-db-password.sh
# Generate new password
NEW_PASSWORD=$(openssl rand -base64 32)
# Update database user password
docker exec lcbp3-mariadb mysql -u root -p -e "
ALTER USER 'lcbp3_user'@'%' IDENTIFIED BY '$NEW_PASSWORD';
FLUSH PRIVILEGES;
"
# Update application .env file
sed -i "s/^DB_PASS=.*/DB_PASS=$NEW_PASSWORD/" /app/backend/.env
# Restart backend to apply new password
docker restart lcbp3-backend
# Verify connection
sleep 10
curl -f http://localhost:3000/health || {
echo "FAILED: Backend cannot connect with new password"
# Rollback procedure...
exit 1
}
echo "Database password rotated successfully: $(date)"
# Store password securely (e.g., password manager)
```
---
## 🚨 Vulnerability Management
### Dependency Vulnerability Scanning
```bash
#!/bin/bash
# File: /scripts/scan-vulnerabilities.sh
# Backend dependencies
cd /app/backend
npm audit --production
# Critical/High vulnerabilities
VULNERABILITIES=$(npm audit --production --json | jq '.metadata.vulnerabilities.high + .metadata.vulnerabilities.critical')
if [ "$VULNERABILITIES" -gt 0 ]; then
echo "WARNING: $VULNERABILITIES critical/high vulnerabilities found!"
npm audit --production > /reports/security-audit-$(date +%Y%m%d).txt
# Send alert
/scripts/send-alert-email.sh "Security Vulnerabilities Detected" "Found $VULNERABILITIES critical/high vulnerabilities"
fi
# Frontend dependencies
cd /app/frontend
npm audit --production
```
### Container Image Scanning
```bash
#!/bin/bash
# File: /scripts/scan-images.sh
# Install Trivy (if not installed)
# wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add -
# echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | tee -a /etc/apt/sources.list.d/trivy.list
# apt-get update && apt-get install trivy
# Scan Docker images
trivy image --severity HIGH,CRITICAL lcbp3-backend:latest
trivy image --severity HIGH,CRITICAL lcbp3-frontend:latest
trivy image --severity HIGH,CRITICAL mariadb:11.8
trivy image --severity HIGH,CRITICAL redis:7.2-alpine
```
---
## 🔍 Security Hardening
### Server Hardening Checklist
- [ ] Disable root SSH login
- [ ] Use SSH key authentication only
- [ ] Configure firewall (allow only necessary ports)
- [ ] Enable automatic security updates
- [ ] Remove unnecessary services
- [ ] Configure fail2ban for brute-force protection
- [ ] Enable SELinux/AppArmor
- [ ] Regular security patch updates
### Docker Security
```yaml
# docker-compose.yml - Security best practices
services:
backend:
# Run as non-root user
user: 'node:node'
# Read-only root filesystem
read_only: true
# No new privileges
security_opt:
- no-new-privileges:true
# Limit capabilities
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
# Resource limits
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
memory: 512M
```
### Database Security
```sql
-- Remove anonymous users
DELETE FROM mysql.user WHERE User='';
-- Remove test database
DROP DATABASE IF EXISTS test;
-- Remove remote root login
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1');
-- Create dedicated backup user with minimal privileges
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD';
GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON lcbp3_dms.* TO 'backup_user'@'localhost';
-- Enable SSL for database connections
-- GRANT USAGE ON *.* TO 'lcbp3_user'@'%' REQUIRE SSL;
FLUSH PRIVILEGES;
```
---
## 🚨 Security Incident Response
### Incident Classification
| Type | Examples | Response Time |
| ----------------------- | ---------------------------- | ---------------- |
| **Data Breach** | Unauthorized data access | Immediate (< 1h) |
| **Account Compromise** | Stolen credentials | Immediate (< 1h) |
| **DDoS Attack** | Service unavailable | Immediate (< 1h) |
| **Malware/Ransomware** | Infected systems | Immediate (< 1h) |
| **Unauthorized Access** | Failed authentication spikes | High (< 4h) |
| **Suspicious Activity** | Unusual patterns | Medium (< 24h) |
### Data Breach Response
**Immediate Actions:**
1. **Contain the breach**
```bash
# Block suspicious IPs at firewall level
iptables -A INPUT -s <SUSPICIOUS_IP> -j DROP
# Disable compromised user accounts
docker exec lcbp3-mariadb mysql -u root -p -e "
UPDATE lcbp3_dms.users
SET is_active = 0
WHERE user_id = <COMPROMISED_USER_ID>;
"
```
2. **Assess impact**
```sql
-- Check audit logs for unauthorized access
SELECT * FROM audit_logs
WHERE user_id = <COMPROMISED_USER_ID>
AND created_at >= '<SUSPECTED_START_TIME>'
ORDER BY created_at DESC;
-- Check what documents were accessed
SELECT DISTINCT entity_id, entity_type, action
FROM audit_logs
WHERE user_id = <COMPROMISED_USER_ID>;
```
3. **Notify stakeholders**
- Security officer
- Management
- Affected users (if applicable)
- Legal team (if required by law)
4. **Document everything**
- Timeline of events
- Data accessed/compromised
- Actions taken
- Lessons learned
### Account Compromise Response
```bash
#!/bin/bash
# File: /scripts/respond-account-compromise.sh
USER_ID=$1
# 1. Immediately disable account
docker exec lcbp3-mariadb mysql -u root -p -e "
UPDATE lcbp3_dms.users
SET is_active = 0,
locked_until = DATE_ADD(NOW(), INTERVAL 24 HOUR)
WHERE user_id = $USER_ID;
"
# 2. Invalidate all sessions
docker exec lcbp3-redis redis-cli DEL "session:user:$USER_ID:*"
# 3. Generate audit report
docker exec lcbp3-mariadb mysql -u root -p -e "
SELECT * FROM lcbp3_dms.audit_logs
WHERE user_id = $USER_ID
AND created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
ORDER BY created_at DESC;
" > /reports/compromise-audit-user-$USER_ID-$(date +%Y%m%d).txt
# 4. Notify security team
/scripts/send-alert-email.sh "Account Compromise" "User ID $USER_ID has been compromised and disabled"
echo "Account compromise response completed for User ID: $USER_ID"
```
---
## 📊 Security Metrics & KPIs
### Monthly Security Report
| Metric | Target | Actual |
| --------------------------- | --------- | ------ |
| Failed Login Attempts | < 100/day | Track |
| Locked Accounts | < 5/month | Track |
| Critical Vulnerabilities | 0 | Track |
| High Vulnerabilities | < 5 | Track |
| Unpatched Systems | 0 | Track |
| Security Incidents | 0 | Track |
| Mean Time To Detect (MTTD) | < 1 hour | Track |
| Mean Time To Respond (MTTR) | < 4 hours | Track |
---
## 🔐 Compliance & Audit
### Audit Log Retention
- **Access Logs:** 1 year
- **Security Events:** 2 years
- **Admin Actions:** 3 years
- **Data Changes:** 7 years (as required)
### Compliance Checklist
- [ ] Regular security audits (quarterly)
- [ ] Penetration testing (annually)
- [ ] Access control reviews (monthly)
- [ ] Encryption at rest and in transit
- [ ] Secure password policies enforced
- [ ] Multi-factor authentication (if required)
- [ ] Data backup and recovery tested
- [ ] Incident response plan documented and tested
---
## ✅ Security Operations Checklist
### Daily
- [ ] Review security alerts and logs
- [ ] Monitor failed login attempts
- [ ] Check for unusual access patterns
- [ ] Verify backup completion
### Weekly
- [ ] Review user access logs
- [ ] Scan for vulnerabilities
- [ ] Update virus definitions
- [ ] Review firewall logs
### Monthly
- [ ] User access audit
- [ ] Role and permission review
- [ ] Security patch application
- [ ] Compliance review
### Quarterly
- [ ] Full security audit
- [ ] Penetration testing
- [ ] Disaster recovery drill
- [ ] Update security policies
---
## 🔗 Related Documents
- [Incident Response](04-07-incident-response.md)
- [Monitoring & Alerting](04-03-monitoring-alerting.md)
- [ADR-004: RBAC Implementation](../05-decisions/ADR-004-rbac-implementation.md)
---
**Version:** 1.8.0
**Last Review:** 2025-12-01
**Next Review:** 2026-03-01

View File

@@ -0,0 +1,483 @@
# Incident Response Procedures
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Last Updated:** 2025-12-02
---
## 📋 Overview
This document outlines incident classification, response procedures, and post-incident reviews for LCBP3-DMS.
---
## 🚨 Incident Classification
### Severity Levels
| Severity | Description | Response Time | Examples |
| ----------------- | ---------------------------- | ----------------- | ----------------------------------------------- |
| **P0 - Critical** | Complete system outage | 15 minutes | Database down, All services unavailable |
| **P1 - High** | Major functionality impaired | 1 hour | Authentication failing, Cannot create documents |
| **P2 - Medium** | Degraded performance | 4 hours | Slow response time, Some features broken |
| **P3 - Low** | Minor issues | Next business day | UI glitch, Non-critical bug |
---
## 📞 Incident Response Team
### Roles & Responsibilities
**Incident Commander (IC)**
- Coordinates response efforts
- Makes final decisions
- Communicates with stakeholders
**Technical Lead (TL)**
- Diagnoses technical issues
- Implements fixes
- Coordinates with engineers
**Communications Lead (CL)**
- Updates stakeholders
- Manages internal/external communications
- Documents incident timeline
**On-Call Engineer**
- First responder
- Initial triage and investigation
- Escalates to appropriate team
---
## 🔄 Incident Response Workflow
```mermaid
flowchart TD
Start([Incident Detected]) --> Acknowledge[Acknowledge Incident]
Acknowledge --> Assess[Assess Severity]
Assess --> P0{Severity?}
P0 -->|P0/P1| Alert[Page Incident Commander]
P0 -->|P2/P3| Assign[Assign to On-Call]
Alert --> Investigate[Investigate Root Cause]
Assign --> Investigate
Investigate --> Mitigate[Implement Mitigation]
Mitigate --> Verify[Verify Resolution]
Verify --> Resolved{Resolved?}
Resolved -->|No| Escalate[Escalate/Re-assess]
Escalate --> Investigate
Resolved -->|Yes| Communicate[Communicate Resolution]
Communicate --> PostMortem[Schedule Post-Mortem]
PostMortem --> End([Close Incident])
```
---
## 📋 Incident Response Playbooks
### P0: Database Down
**Symptoms:**
- Backend returns 500 errors
- Cannot connect to database
- Health check fails
**Immediate Actions:**
1. **Verify Issue**
```bash
docker ps | grep mariadb
docker logs lcbp3-mariadb --tail=50
```
2. **Attempt Restart**
```bash
docker restart lcbp3-mariadb
```
3. **Check Database Process**
```bash
docker exec lcbp3-mariadb ps aux | grep mysql
```
4. **If Restart Fails:**
```bash
# Check disk space
df -h
# Check database logs for corruption
docker exec lcbp3-mariadb cat /var/log/mysql/error.log
# If corrupted, restore from backup
# See backup-recovery.md
```
5. **Escalate to DBA** if not resolved in 30 minutes
---
### P0: Complete System Outage
**Symptoms:**
- All services return 502/503
- Health checks fail
- Users cannot access system
**Immediate Actions:**
1. **Check Container Status**
```bash
docker-compose ps
# Identify which containers are down
```
2. **Restart All Services**
```bash
docker-compose restart
```
3. **Check QNAP Server Resources**
```bash
top
df -h
free -h
```
4. **Check Network**
```bash
ping 8.8.8.8
netstat -tlnp
```
5. **If Server Issue:**
- Reboot QNAP server
- Contact QNAP support
---
### P1: Authentication System Failing
**Symptoms:**
- Users cannot log in
- JWT validation fails
- 401 errors
**Immediate Actions:**
1. **Check Redis (Session Store)**
```bash
docker exec lcbp3-redis redis-cli ping
# Should return PONG
```
2. **Check JWT Secret Configuration**
```bash
docker exec lcbp3-backend env | grep JWT_SECRET
# Verify not empty
```
3. **Check Backend Logs**
```bash
docker logs lcbp3-backend --tail=100 | grep "JWT\|Auth"
```
4. **Temporary Mitigation:**
```bash
# Restart backend to reload config
docker restart lcbp3-backend
```
---
### P1: File Upload Failing
**Symptoms:**
- Users cannot upload files
- 500 errors on file upload
- "Disk full" errors
**Immediate Actions:**
1. **Check Disk Space**
```bash
df -h /var/lib/docker/volumes/lcbp3_uploads
```
2. **If Disk Full:**
```bash
# Clean up temp uploads
find /var/lib/docker/volumes/lcbp3_uploads/_data/temp \
-type f -mtime +1 -delete
```
3. **Check ClamAV (Virus Scanner)**
```bash
docker logs lcbp3-clamav --tail=50
docker restart lcbp3-clamav
```
4. **Check File Permissions**
```bash
docker exec lcbp3-backend ls -la /app/uploads
```
---
### P2: Slow Performance
**Symptoms:**
- Pages load slowly
- API response time > 2s
- Users complain about slowness
**Actions:**
1. **Check System Resources**
```bash
docker stats
# Identify high CPU/memory containers
```
2. **Check Database Performance**
```sql
-- Show slow queries
SHOW PROCESSLIST;
-- Check connections
SHOW STATUS LIKE 'Threads_connected';
```
3. **Check Redis**
```bash
docker exec lcbp3-redis redis-cli --stat
```
4. **Check Application Logs**
```bash
docker logs lcbp3-backend | grep "Slow request"
```
5. **Temporary Mitigation:**
- Restart slow containers
- Clear Redis cache if needed
- Kill long-running queries
---
### P2: Email Notifications Not Sending
**Symptoms:**
- Users not receiving emails
- Email queue backing up
**Actions:**
1. **Check Email Queue**
```bash
# Access BullMQ dashboard or check Redis
docker exec lcbp3-redis redis-cli LLEN bull:email:waiting
```
2. **Check Email Processor Logs**
```bash
docker logs lcbp3-backend | grep "email\|SMTP"
```
3. **Test SMTP Connection**
```bash
docker exec lcbp3-backend node -e "
const nodemailer = require('nodemailer');
const transport = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
});
transport.verify().then(console.log).catch(console.error);
"
```
4. **Check SMTP Credentials**
- Verify not expired
- Check firewall/network access
---
## 📝 Incident Documentation
### Incident Report Template
```markdown
# Incident Report: [Brief Description]
**Incident ID:** INC-YYYYMMDD-001
**Severity:** P1
**Status:** Resolved
**Incident Commander:** [Name]
## Timeline
| Time | Event |
| ----- | --------------------------------------------------------- |
| 14:00 | Alert: High error rate detected |
| 14:05 | On-call engineer acknowledged |
| 14:10 | Identified root cause: Database connection pool exhausted |
| 14:15 | Implemented mitigation: Increased pool size |
| 14:20 | Verified resolution |
| 14:30 | Incident resolved |
## Impact
- **Duration:** 30 minutes
- **Affected Users:** ~50 users
- **Affected Services:** Document creation, Search
- **Data Loss:** None
## Root Cause
Database connection pool was exhausted due to slow queries not releasing connections.
## Resolution
1. Increased connection pool size from 10 to 20
2. Optimized slow queries
3. Added connection pool monitoring
## Action Items
- [ ] Add connection pool size alert (Owner: DevOps, Due: Next Sprint)
- [ ] Implement automatic query timeouts (Owner: Backend, Due: 2025-12-15)
- [ ] Review all queries for optimization (Owner: DBA, Due: 2025-12-31)
## Lessons Learned
- Connection pool monitoring was insufficient
- Need automated remediation for common issues
```
---
## 🔍 Post-Incident Review (PIR)
### PIR Meeting Agenda
1. **Timeline Review** (10 min)
- What happened and when?
- What was the impact?
2. **Root Cause Analysis** (15 min)
- Why did it happen?
- What were the contributing factors?
3. **What Went Well** (10 min)
- What did we do right?
- What helped us resolve quickly?
4. **What Went Wrong** (15 min)
- What could we have done better?
- What slowed us down?
5. **Action Items** (10 min)
- What changes will prevent this?
- Who owns each action?
- When will they be completed?
### PIR Best Practices
- **Blameless Culture:** Focus on systems, not individuals
- **Actionable Outcomes:** Every PIR should produce concrete actions
- **Follow Through:** Track action items to completion
- **Share Learnings:** Distribute PIR summary to entire team
---
## 📊 Incident Metrics
### Track & Review Monthly
- **MTTR (Mean Time To Resolution):** Average time to resolve incidents
- **MTBF (Mean Time Between Failures):** Average time between incidents
- **Incident Frequency:** Number of incidents per month
- **Severity Distribution:** Breakdown by P0/P1/P2/P3
- **Repeat Incidents:** Same root cause occurring multiple times
---
## ✅ Incident Response Checklist
### During Incident
- [ ] Acknowledge incident in tracking system
- [ ] Assess severity and assign IC
- [ ] Create incident channel (Slack/Teams)
- [ ] Begin documenting timeline
- [ ] Investigate and implement mitigation
- [ ] Communicate status updates every 30 min (P0/P1)
- [ ] Verify resolution
- [ ] Communicate resolution to stakeholders
### After Incident
- [ ] Create incident report
- [ ] Schedule PIR within 48 hours
- [ ] Identify action items
- [ ] Assign owners and deadlines
- [ ] Update runbooks/playbooks
- [ ] Share learnings with team
---
## 🔗 Related Documents
- [Monitoring & Alerting](04-03-monitoring-alerting.md)
- [Backup & Recovery](04-04-backup-recovery.md)
- [Security Operations](04-06-security-operations.md)
---
**Version:** 1.8.0
**Last Review:** 2025-12-01
**Next Review:** 2026-03-01

View File

@@ -0,0 +1,36 @@
# Infrastructure & Operations (OPS) Guide
**Project:** LCBP3-DMS
**Version:** 1.8.0
**Last Updated:** 2026-02-23
---
## 📋 Overview
This directory (`04-Infrastructure-OPS/`) serves as the single source of truth for all infrastructure setups, networking rules, Docker Compose configurations, backups, and site reliability operations for the LCBP3-DMS project.
It consolidates what was previously split across multiple operations and specification folders into a cohesive set of manuals for DevOps, System Administrators, and On-Call Engineers.
---
## 📂 Document Index
| File | Purpose | Key Contents |
| ------------------------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------- |
| **[04-01-docker-compose.md](./04-01-docker-compose.md)** | Core Environment Setup | `.env` configs, Blue/Green Docker Compose, MariaDB & Redis optimization |
| **[04-02-backup-recovery.md](./04-02-backup-recovery.md)** | Disaster Recovery | RTO/RPO strategies, QNAP to ASUSTOR backup scripts, Restic/Mysqldump config |
| **[04-03-monitoring.md](./04-03-monitoring.md)** | Observability | Prometheus metrics, AlertManager rules (inclusive of Document Numbering DB), Grafana alerts |
| **[04-04-deployment-guide.md](./04-04-deployment-guide.md)** | Production Rollout | Step-by-step Blue-Green deployment scripts, rollback playbooks, Nginx Reverse Proxy |
| **[04-05-maintenance-procedures.md](./04-05-maintenance-procedures.md)** | Routine Care | Log rotation, dependency zero-downtime updates, scheduled DB optimizations |
| **[04-06-security-operations.md](./04-06-security-operations.md)** | Hardening & Audit | User access review scripts, SSL renewals, vulnerability scanning procedures |
| **[04-07-incident-response.md](./04-07-incident-response.md)** | Escalation | P0-P3 classifications, incident commander roles, Post-Incident Review (PIR) |
---
## 🎯 Guiding Principles
1. **Zero Downtime Deployments**: Utilize the Blue/Green architecture outlined in `04-04` wherever possible.
2. **Infrastructure as Code**: No manual unscripted changes. Modify the `docker-compose.yml` specs and `.env.production` templates directly.
3. **Automated Backups**: Backups must be validated automatically using the ASUSTOR pulling mechanism in `04-02`.
4. **Actionable Alerts**: No noisy monitoring. Prometheus alerts in `04-03` should route to Slack/PagerDuty only when action is required.

View File

@@ -2,7 +2,7 @@
**สถานะ:** first-draft
**วันที่:** 2025-12-17
**อ้างอิง:** Requirements Specification v1.6.1
**อ้างอิง:** Requirements Specification v1.8.0
**Classification:** Internal Technical Documentation
## 🧠 **1. ปรัชญาทั่วไป (General Philosophy)**

View File

@@ -462,10 +462,10 @@ async approve(@Param('id') id: string, @CurrentUser() user: User) {
## 📚 เอกสารอ้างอิง
- [FullStack Guidelines](03-01-fullftack-js-v1.7.0.md)
- [Backend Plan v1.4.5](../../docs/2_Backend_Plan_V1_4_5.md)
- [Data Dictionary](../../docs/4_Data_Dictionary_V1_4_5.md)
- [Workflow Engine Plan](../../docs/2_Backend_Plan_V1_4_4.Phase6A.md)
- [FullStack Guidelines](05-01-fullstack-js-guidelines.md)
- [Backend Plan v1.4.5](../02-Architecture/02-02-software-architecture.md)
- [Data Dictionary](../03-Data-and-Storage/03-01-data-dictionary.md)
- [Workflow Engine Plan](../01-Requirements/01-03-modules/README.md)
---

View File

@@ -642,8 +642,8 @@ test.describe('Correspondence Workflow', () => {
## 📚 เอกสารอ้างอิง
- [FullStack Guidelines](03-01-fullftack-js-v1.7.0.md)
- [Frontend Plan v1.4.5](../../docs/3_Frontend_Plan_V1_4_5.md)
- [FullStack Guidelines](05-01-fullstack-js-guidelines.md)
- [Frontend Plan v1.4.5](../02-Architecture/02-02-software-architecture.md)
- [Next.js Documentation](https://nextjs.org/docs)
- [TanStack Query](https://tanstack.com/query)
- [shadcn/ui](https://ui.shadcn.com)

View File

@@ -3,7 +3,7 @@
---
title: 'Testing Strategy'
version: 1.5.0
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2025-11-30
@@ -1229,9 +1229,9 @@ describe('[ClassName/FeatureName]', () => {
## 🔗 Related Documentation
- [Backend Guidelines](03-02-backend-guidelines.md) - Backend development standards
- [Frontend Guidelines](03-03-frontend-guidelines.md) - Frontend development standards
- [System Architecture](../02-architecture/02-01-system-architecture.md) - System overview
- [Backend Guidelines](05-02-backend-guidelines.md) - Backend development standards
- [Frontend Guidelines](05-03-frontend-guidelines.md) - Frontend development standards
- [System Architecture](../02-Architecture/02-01-system-context.md) - System overview
- [API Design](../02-architecture/02-02-api-design.md) - API specifications
---

View File

@@ -43,7 +43,7 @@
## 📖 คู่มือการพัฒนา (Implementation Guides)
### 1. [FullStack JS Guidelines](./03-01-fullftack-js-v1.7.0.md)
### 1. [FullStack JS Guidelines](./05-01-fullstack-js-guidelines.md)
**แนวทางการพัฒนาภาพรวมทั้งระบบ (v1.7.0)**
- โครงสร้างโปรเจกต์ (Monorepo-like focus)
- Naming Conventions & Code Style
@@ -51,7 +51,7 @@
- Two-Phase File Storage Algorithm
- Double-Lock Mechanism for Numbering
### 2. [Backend Guidelines](./03-02-backend-guidelines.md)
### 2. [Backend Guidelines](./05-02-backend-guidelines.md)
**แนวทางการพัฒนา NestJS Backend**
- Modular Architecture Detail
- DTO Validation & Transformer
@@ -59,7 +59,7 @@
- JWT Authentication & CASL Authorization
- BullMQ for Background Jobs
### 3. [Frontend Guidelines](./03-03-frontend-guidelines.md)
### 3. [Frontend Guidelines](./05-03-frontend-guidelines.md)
**แนวทางการพัฒนา Next.js Frontend**
- App Router Patterns
- Shadcn/UI & Tailwind Styling
@@ -67,7 +67,7 @@
- React Hook Form + Zod for Client Validation
- API Client Interceptors (Auth & Idempotency)
### 4. [Document Numbering System](./03-04-document-numbering.md)
### 4. [Document Numbering System](./../01-Requirements/business-rules/01-02-02-doc-numbering-rules.md)
**รายละเอียดการนำระบบออกเลขที่เอกสารไปใช้งาน**
- Table Schema: Templates, Counters, Audit
- Double-Lock Strategy (Redis Redlock + Database VersionColumn)
@@ -78,7 +78,7 @@
## 🧪 Testing Strategy
รายละเอียดอยู่ในเอกสาร: **[Testing Strategy](./03-05-testing-strategy.md)**
รายละเอียดอยู่ในเอกสาร: **[Testing Strategy](./05-04-testing-strategy.md)**
- **Unit Testing:** NestJS (Jest), React (Vitest)
- **Integration Testing:** API Endpoints (Supertest)
@@ -103,7 +103,7 @@
- 📋 [Requirements Specification](../01-requirements/README.md)
- 🏗️ [Architecture Specification](../02-architecture/README.md)
- 🚀 [Operations Specification](../04-operations/README.md)
- 🚀 [Operations Specification](../04-Infrastructure-OPS/README.md)
- 🎯 [Active Tasks](../06-tasks/README.md)
---
@@ -112,7 +112,7 @@
**LCBP3-DMS Implementation Specification v1.7.0**
[FullStack](./03-01-fullftack-js-v1.7.0.md) • [Backend](./03-02-backend-guidelines.md) • [Frontend](./03-03-frontend-guidelines.md) • [Testing](./03-05-testing-strategy.md)
[FullStack](./05-01-fullstack-js-guidelines.md) • [Backend](./05-02-backend-guidelines.md) • [Frontend](./05-03-frontend-guidelines.md) • [Testing](./05-04-testing-strategy.md)
[Main README](../../README.md) • [Architecture](../02-architecture/README.md) • [Requirements](../01-requirements/README.md)

View File

@@ -0,0 +1,138 @@
# 02.2 Network Infrastructure & Security (โครงสร้างเครือข่ายและความปลอดภัย)
---
title: 'Network Infrastructure'
version: 1.8.0
status: first-draft
owner: Nattanin Peancharoen
last_updated: 2026-02-23
related:
- specs/02-Architecture/00-01-system-context.md
---
## 1. 🌐 Network Configuration Details
### 1.1 VLAN Networks
| VLAN ID | Name | Purpose | Gateway/Subnet | DHCP | IP Range | DNS | Lease Time | Notes |
| ------- | ------ | --------- | --------------- | ---- | ------------------ | ------- | ---------- | --------------- |
| 10 | SERVER | Interface | 192.168.10.1/24 | No | - | Custom | - | Static servers |
| 20 | MGMT | Interface | 192.168.20.1/24 | No | - | Custom | - | Management only |
| 30 | USER | Interface | 192.168.30.1/24 | Yes | 192.168.30.10-254 | Auto | 7 Days | User devices |
| 40 | CCTV | Interface | 192.168.40.1/24 | Yes | 192.168.40.100-150 | Auto | 7 Days | CCTV & NVR |
| 50 | VOICE | Interface | 192.168.50.1/24 | Yes | 192.168.50.201-250 | Auto | 7 Days | IP Phones |
| 60 | DMZ | Interface | 192.168.60.1/24 | No | - | 1.1.1.1 | - | Public services |
| 70 | GUEST | Interface | 192.168.70.1/24 | Yes | 192.168.70.200-250 | Auto | 1 Day | Guest |
### 1.2 Switch Profiles
| Profile Name | Native Network | Tagged Networks | Untagged Networks | Usage |
| ---------------- | -------------- | --------------------- | ----------------- | ----------------------- |
| 01_CORE_TRUNK | MGMT (20) | 10,30,40,50,60,70 | MGMT (20) | Router & switch uplinks |
| 02_MGMT_ONLY | MGMT (20) | MGMT (20) | - | Management only |
| 03_SERVER_ACCESS | SERVER (10) | MGMT (20) | SERVER (10) | QNAP / ASUSTOR |
| 04_CCTV_ACCESS | CCTV (40) | - | CCTV (40) | CCTV cameras |
| 05_USER_ACCESS | USER (30) | - | USER (30) | PC / Printer |
| 06_AP_TRUNK | MGMT (20) | USER (30), GUEST (70) | MGMT (20) | EAP610 Access Points |
| 07_VOICE_ACCESS | USER (30) | VOICE (50) | USER (30) | IP Phones |
### 1.3 NAS NIC Bonding Configuration
| Device | Bonding Mode | Member Ports | VLAN Mode | Tagged VLAN | IP Address | Gateway | Notes |
| ------- | ------------------- | ------------ | --------- | ----------- | --------------- | ------------ | ---------------------- |
| QNAP | IEEE 802.3ad (LACP) | Adapter 1, 2 | Untagged | 10 (SERVER) | 192.168.10.8/24 | 192.168.10.1 | Primary NAS for DMS |
| ASUSTOR | IEEE 802.3ad (LACP) | Port 1, 2 | Untagged | 10 (SERVER) | 192.168.10.9/24 | 192.168.10.1 | Backup / Secondary NAS |
> **หมายเหตุ**: NAS ทั้งสองตัวใช้ LACP bonding เพื่อเพิ่ม bandwidth และ redundancy โดยต้อง config ให้ตรงกับ Switch
## 2. 🛡️ Network ACLs & Firewall Rules
### 2.1 Gateway ACL (ER7206 Firewall Rules)
*Inter-VLAN Routing Policy*
| # | Name | Source | Destination | Service | Action | Log | Notes |
| --- | ----------------- | --------------- | ---------------- | -------------- | ------ | --- | --------------------------- |
| 1 | MGMT-to-ALL | VLAN20 (MGMT) | Any | Any | Allow | No | Admin full access |
| 2 | SERVER-to-ALL | VLAN10 (SERVER) | Any | Any | Allow | No | Servers outbound access |
| 3 | USER-to-SERVER | VLAN30 (USER) | VLAN10 (SERVER) | HTTP/HTTPS/SSH | Allow | No | Users access web apps |
| 4 | USER-to-DMZ | VLAN30 (USER) | VLAN60 (DMZ) | HTTP/HTTPS | Allow | No | Users access DMZ services |
| 5 | USER-to-MGMT | VLAN30 (USER) | VLAN20 (MGMT) | Any | Deny | Yes | Block users from management |
| 6 | USER-to-CCTV | VLAN30 (USER) | VLAN40 (CCTV) | Any | Deny | Yes | Isolate CCTV |
| 7 | USER-to-VOICE | VLAN30 (USER) | VLAN50 (VOICE) | Any | Deny | No | Isolate Voice |
| 8 | USER-to-GUEST | VLAN30 (USER) | VLAN70 (GUEST) | Any | Deny | No | Isolate Guest |
| 9 | CCTV-to-INTERNET | VLAN40 (CCTV) | WAN | HTTPS (443) | Allow | No | NVR cloud backup (optional) |
| 10 | CCTV-to-ALL | VLAN40 (CCTV) | Any (except WAN) | Any | Deny | Yes | CCTV isolated |
| 11 | DMZ-to-ALL | VLAN60 (DMZ) | Any (internal) | Any | Deny | Yes | DMZ cannot reach internal |
| 12 | GUEST-to-INTERNET | VLAN70 (GUEST) | WAN | HTTP/HTTPS/DNS | Allow | No | Guest internet only |
| 13 | GUEST-to-ALL | VLAN70 (GUEST) | Any (internal) | Any | Deny | Yes | Guest isolated |
| 99 | DEFAULT-DENY | Any | Any | Any | Deny | Yes | Catch-all deny |
*WAN Inbound Rules (Port Forwarding)*
| # | Name | WAN Port | Internal IP | Internal Port | Protocol | Notes |
| --- | --------- | -------- | ------------ | ------------- | -------- | ------------------- |
| 1 | HTTPS-NPM | 443 | 192.168.10.8 | 443 | TCP | Nginx Proxy Manager |
| 2 | HTTP-NPM | 80 | 192.168.10.8 | 80 | TCP | HTTP redirect |
### 2.2 Switch ACL (Layer 2 Rules)
*Port-Based Access Control*
| # | Name | Source Port | Source MAC/VLAN | Destination | Action | Notes |
| --- | --------------- | --------------- | --------------- | ------------------- | ------ | ------------------------ |
| 1 | CCTV-Isolation | Port 25 (CCTV) | VLAN 40 | VLAN 10,20,30 | Deny | CCTV cannot reach others |
| 2 | Guest-Isolation | Port 5-20 (APs) | VLAN 70 | VLAN 10,20,30,40,50 | Deny | Guest isolation |
### 2.3 EAP ACL (Wireless Rules)
*SSID: PSLCBP3 (Staff WiFi)*
| # | Name | Source | Destination | Service | Action | Notes |
| --- | ------------------- | ---------- | ---------------- | -------- | ------ | ----------------- |
| 1 | Allow-DNS | Any Client | 8.8.8.8, 1.1.1.1 | DNS (53) | Allow | DNS resolution |
| 2 | Allow-Server | Any Client | 192.168.10.0/24 | Any | Allow | Access to servers |
| 3 | Allow-Printer | Any Client | 192.168.30.222 | 9100,631 | Allow | Print services |
| 4 | Allow-Internet | Any Client | WAN | Any | Allow | Internet access |
| 5 | Block-MGMT | Any Client | 192.168.20.0/24 | Any | Deny | No management |
| 6 | Block-CCTV | Any Client | 192.168.40.0/24 | Any | Deny | No CCTV access |
| 8 | Block-Client2Client | Any Client | Any Client | Any | Deny | Client isolation |
*SSID: GUEST (Guest WiFi)*
| # | Name | Source | Destination | Service | Action | Notes |
| --- | ------------------- | ---------- | ---------------- | ---------- | ------ | ------------------ |
| 1 | Allow-DNS | Any Client | 8.8.8.8, 1.1.1.1 | DNS (53) | Allow | DNS resolution |
| 2 | Allow-HTTP | Any Client | WAN | HTTP/HTTPS | Allow | Web browsing |
| 3 | Block-RFC1918 | Any Client | 10.0.0.0/8 | Any | Deny | No private IPs |
| 4 | Block-RFC1918-2 | Any Client | 172.16.0.0/12 | Any | Deny | No private IPs |
| 5 | Block-RFC1918-3 | Any Client | 192.168.0.0/16 | Any | Deny | No internal access |
| 6 | Block-Client2Client | Any Client | Any Client | Any | Deny | Client isolation |
## 3. 📈 Network Topology Diagram
```mermaid
graph TB
subgraph Internet
WAN[("🌐 Internet<br/>WAN")]
end
subgraph Router["ER7206 Router"]
R[("🔲 ER7206<br/>192.168.20.1")]
end
subgraph CoreSwitch["SG2428P Core Switch"]
CS[("🔲 SG2428P<br/>192.168.20.2")]
end
subgraph ServerSwitch["AMPCOM 2.5G Switch"]
SS[("🔲 AMPCOM<br/>192.168.20.3")]
end
subgraph Servers["VLAN 10 - Servers"]
QNAP[("💾 QNAP<br/>192.168.10.8")]
ASUSTOR[("💾 ASUSTOR<br/>192.168.10.9")]
end
subgraph AccessPoints["EAP610 x16"]
AP[("📶 WiFi APs")]
end
WAN --> R
R -->|Port 3| CS
CS -->|LAG Port 3-4| SS
SS -->|Port 3-4 LACP| QNAP
SS -->|Port 5-6 LACP| ASUSTOR
CS -->|Port 5-20| AP
```

View File

@@ -0,0 +1,46 @@
specs/
├── 00-Overview/ # ภาพรวมระบบ
│ ├── 00-01-system-context.md # บริบทของระบบ (On-Prem, Segmented Network)
│ ├── 00-02-glossary.md # คำศัพท์และตัวย่อในระบบ DMS
│ └── 00-03-quick-start.md # คู่มือเริ่มต้นสำหรับนักพัฒนา
├── 01-Requirements/ # Business Rules & Document Control (Core)
│ ├── modules/ # สเปคของแต่ละระบบย่อย
│ │ ├── 01-rfa.md
│ │ ├── 02-drawings.md # Contract & Shop Drawings
│ │ ├── 03-correspondence.md
│ │ └── 04-transmittals-circulation.md
│ └── business-rules/ # กฎเหล็กของ DMS (ห้ามละเมิด)
│ ├── doc-numbering-rules.md # กฎการรันเลขเอกสาร & Conflict Detection
│ ├── revision-control.md # กฎการทำ Revision (Superseded, ข้อมูลอ้างอิง)
│ └── rbac-matrix.md # สิทธิ์การเข้าถึงข้อมูลและการอนุมัติ
├── 02-Architecture/ # สถาปัตยกรรมระบบ (System & Network)
│ ├── 02-01-api-design.md
│ ├── 02-02-security-layer.md # Application Security, App/Dev Separation
│ └── 02-03-network-design.md # Network Segmentation (VLAN, VPN, QNAP/ASUSTOR)
├── 03-Data-and-Storage/ # โครงสร้างฐานข้อมูลและการจัดการไฟล์
│ ├── 03-01-data-dictionary.md
│ ├── 03-02-db-indexing.md # Index recommendations, Soft-delete strategy
│ └── 03-03-file-storage.md # Secure File Handling (Outside webroot, QNAP Mounts)
├── 04-Infrastructure-OPS/ # โครงสร้างพื้นฐานและการปฏิบัติการ (Merge 04 & 08 เดิม)
│ ├── 04-01-docker-compose.md # DEV/PROD Docker configuration
│ ├── 04-02-nginx-proxy.md # Nginx Reverse Proxy & SSL Setup
│ ├── 04-03-monitoring.md # KPI, Audit Logging, Grafana/Prometheus
│ └── 04-04-backup-recovery.md # Disaster Recovery & DB Backup
├── 05-Engineering-Guidelines/ # มาตรฐานการพัฒนา
│ ├── 05-01-backend.md # Node.js/PHP Guidelines, Error Handling
│ ├── 05-02-frontend.md # UI/UX & Form Validation Strategy
│ └── 05-03-testing.md # Unit/E2E Testing Strategy
├── 06-Decision-Records/ # Architecture Decision Records (05-decisions เดิม)
│ ├── ADR-001-unified-workflow.md
│ └── ADR-002-doc-numbering.md
└── 99-archives/ # ประวัติการทำงานและ Tasks (แยกออกมาจาก Specs หลัก)
├── history/ # 09-history เดิม
├── tasks/ # 06-tasks เดิม
└── obsolete-specs/ # เอกสารสเปคเวอร์ชันเก่า (V1.4.2 ฯลฯ)