260223:1415 20260223 nextJS & nestJS Best pratices
All checks were successful
Build and Deploy / deploy (push) Successful in 4m44s
All checks were successful
Build and Deploy / deploy (push) Successful in 4m44s
This commit is contained in:
@@ -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: -
|
||||
|
||||
---
|
||||
|
||||
@@ -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).
|
||||
@@ -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 UTF‑8** (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';
|
||||
```
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
43
specs/01-requirements/01-03-modules/01-03-00-index.md
Normal file
43
specs/01-requirements/01-03-modules/01-03-00-index.md
Normal 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)
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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. การอ้างอิงและจัดกลุ่ม:
|
||||
|
||||
@@ -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. การอ้างอิงและจัดกลุ่ม:
|
||||
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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:
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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 ได้โดยไม่ต้องแก้โค้ด
|
||||
@@ -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
|
||||
|
||||
95
specs/02-architecture/02-01-system-context.md
Normal file
95
specs/02-architecture/02-01-system-context.md
Normal 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 ชัดเจน
|
||||
125
specs/02-architecture/02-02-software-architecture.md
Normal file
125
specs/02-architecture/02-02-software-architecture.md
Normal 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 หลัก
|
||||
188
specs/02-architecture/02-03-network-design.md
Normal file
188
specs/02-architecture/02-03-network-design.md
Normal 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**
|
||||
339
specs/02-architecture/02-04-api-design.md
Normal file
339
specs/02-architecture/02-04-api-design.md
Normal 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**
|
||||
1389
specs/04-Infrastructure-OPS/04-01-docker-compose.md
Normal file
1389
specs/04-Infrastructure-OPS/04-01-docker-compose.md
Normal file
File diff suppressed because it is too large
Load Diff
856
specs/04-Infrastructure-OPS/04-02-backup-recovery.md
Normal file
856
specs/04-Infrastructure-OPS/04-02-backup-recovery.md
Normal 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**
|
||||
1556
specs/04-Infrastructure-OPS/04-03-monitoring.md
Normal file
1556
specs/04-Infrastructure-OPS/04-03-monitoring.md
Normal file
File diff suppressed because it is too large
Load Diff
937
specs/04-Infrastructure-OPS/04-04-deployment-guide.md
Normal file
937
specs/04-Infrastructure-OPS/04-04-deployment-guide.md
Normal 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
|
||||
501
specs/04-Infrastructure-OPS/04-05-maintenance-procedures.md
Normal file
501
specs/04-Infrastructure-OPS/04-05-maintenance-procedures.md
Normal 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
|
||||
444
specs/04-Infrastructure-OPS/04-06-security-operations.md
Normal file
444
specs/04-Infrastructure-OPS/04-06-security-operations.md
Normal 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
|
||||
483
specs/04-Infrastructure-OPS/04-07-incident-response.md
Normal file
483
specs/04-Infrastructure-OPS/04-07-incident-response.md
Normal 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
|
||||
36
specs/04-Infrastructure-OPS/README.md
Normal file
36
specs/04-Infrastructure-OPS/README.md
Normal 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.
|
||||
@@ -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)**
|
||||
@@ -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)
|
||||
|
||||
---
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
---
|
||||
@@ -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)
|
||||
|
||||
138
specs/99-archives/02-02-network-infrastructure.md
Normal file
138
specs/99-archives/02-02-network-infrastructure.md
Normal 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
|
||||
```
|
||||
@@ -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 ฯลฯ)
|
||||
|
||||
Reference in New Issue
Block a user