260324:1349 Refactor RFA #01
CI / CD Pipeline / build (push) Failing after 1m52s
CI / CD Pipeline / deploy (push) Has been skipped

This commit is contained in:
admin
2026-03-24 13:49:30 +07:00
parent a3e3206b06
commit 4cd0952482
29 changed files with 1700 additions and 306 deletions
@@ -3,22 +3,122 @@
---
title: "Functional Requirements: Project Management"
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## Details (รายละเอียด)
## 3.1.1. วัตถุประสงค์
- 3.1.1. โครงการ (Projects): ระบบต้องสามารถจัดการเอกสารภายในหลายโครงการได้ (ปัจจุบันมี 4 โครงการ และจะเพิ่มขึ้นในอนาคต)
- 3.1.2. สัญญา (Contracts): ระบบต้องสามารถจัดการเอกสารภายในแต่ละสัญญาได้ ในแต่ละโครงการ มีได้หลายสัญญา หรืออย่างน้อย 1 สัญญา
- 3.1.3. องค์กร (Organizations):
- มีหลายองค์กรในโครงการ องค์กรณ์ที่เป็น Owner, Designer และ Consultant สามารถอยู่ในหลายโครงการและหลายสัญญาได้
- Contractor จะถือ 1 สัญญา และอยู่ใน 1 โครงการเท่านั้น
จัดการโครงสร้างหลักของระบบ ได้แก่ **Project → Contract → Organization → Discipline** — ทุกเอกสารในระบบผูกอยู่กับ Project และ/หรือ Contract เสมอ
---
## 3.1.2. โครงสร้างข้อมูล (Database Tables)
| Table | บทบาท |
|---|---|
| `projects` | ข้อมูล Master โครงการ: code, name, is_active |
| `contracts` | สัญญา ผูกกับ Project (N:1) |
| `organizations` | ข้อมูล Master องค์กร: code, name, role |
| `organization_roles` | Master: ประเภทองค์กร (OWNER/DESIGNER/ฯลฯ) |
| `project_organizations` | M:N: Project ↔ Organization |
| `contract_organizations` | M:N: Contract ↔ Organization + role_in_contract |
| `disciplines` | สาขางาน ผูกกับ Contract (N:1) |
### Hierarchy
```
Project (1)
└── Contract (N)
├── Organization (M:N via contract_organizations)
└── Discipline (N)
Project ↔ Organization (M:N via project_organizations)
```
---
## 3.1.3. Projects
| Field | Type | หมายเหตุ |
|---|---|---|
| `project_code` | VARCHAR(50) UNIQUE | รหัสโครงการ |
| `project_name` | VARCHAR(255) | ชื่อโครงการ |
| `is_active` | TINYINT(1) | 1 = Active |
- ปัจจุบันมี **4 โครงการ** — รองรับการเพิ่มในอนาคต
- จัดการโดย Superadmin เท่านั้น
---
## 3.1.4. Contracts
| Field | Type | หมายเหตุ |
|---|---|---|
| `project_id` | INT FK | ผูกกับ Project |
| `contract_code` | VARCHAR(50) UNIQUE | รหัสสัญญา |
| `contract_name` | VARCHAR(255) | ชื่อสัญญา |
| `start_date` / `end_date` | DATE | ระยะเวลาสัญญา |
| `is_active` | BOOLEAN | สถานะ |
- 1 Project มีได้หลาย Contract (≥ 1)
- Document Number ผูกกับ Contract (ไม่ใช่ Project)
---
## 3.1.5. Organizations และ Organization Roles
### Organization Roles (organization_roles)
| role_name | ความหมาย | สามารถอยู่ใน |
|---|---|---|
| `OWNER` | เจ้าของโครงการ | หลาย Project / หลาย Contract |
| `DESIGNER` | ผู้ออกแบบ | หลาย Project / หลาย Contract |
| `CONSULTANT` | ที่ปรึกษา | หลาย Project / หลาย Contract |
| `CONTRACTOR` | ผู้รับเหมา | **1 Contract / 1 Project เท่านั้น** |
| `THIRD PARTY` | บุคคลที่สาม | หลาย Project / หลาย Contract |
### project_organizations (M:N)
- ผูก Organization เข้า Project — ไม่มี role_in_contract ระดับ Project
### contract_organizations (M:N)
- ผูก Organization เข้า Contract พร้อม `role_in_contract` (Owner/Designer/Consultant/Contractor)
- 1 Organization สามารถมีหลาย role ใน Contract เดียวกันได้
---
## 3.1.6. Disciplines (สาขางาน)
Discipline ผูกกับ **Contract** (ไม่ใช่ Project):
| Field | หมายเหตุ |
|---|---|
| `contract_id` | FK → contracts |
| `discipline_code` | VARCHAR(10) เช่น GEN, STR, MEP |
| `code_name_th` / `code_name_en` | ชื่อภาษาไทย/อังกฤษ |
| `is_active` | สถานะ |
- UNIQUE KEY `(contract_id, discipline_code)` — code ซ้ำได้ระหว่าง Contract
- ใช้กรอง RFA Type และ Correspondence ต่อ Contract
---
## 3.1.7. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | Scope |
|---|---|---|
| สร้าง / แก้ไข Project | Superadmin | Global |
| สร้าง / แก้ไข Contract | Superadmin, Org Admin | Project |
| สร้าง / แก้ไข Organization | Superadmin | Global |
| เพิ่ม Organization เข้า Project/Contract | Superadmin | Global |
| จัดการ Disciplines | Superadmin, Org Admin | Contract |
| ดู Project / Contract | ทุกคนที่มีสิทธิ์ใน Project | Project |
@@ -3,37 +3,168 @@
---
title: 'Functional Requirements: Correspondence Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-06-unified-workflow.md
- specs/01-requirements/01-03-modules/01-03-08-circulation-sheet.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-CORR-001 ถึง EC-CORR-003)
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.2.1. วัตถุประสงค์:
## 3.2.1. วัตถุประสงค์
- เอกสารโต้ตอบ (Correspondences) ระหว่างองค์กรณ์-องค์กรณ์ ภายใน โครงการ (Projects) และระหว่าง องค์กรณ์-องค์กรณ์ ภายนอก โครงการ (Projects), รองรับ To (ผู้รับหลัก) และ CC (ผู้รับสำเนา) หลายองค์กรณ์
เอกสารโต้ตอบ (Correspondence) คือ **โครงสร้างข้อมูลหลัก (Parent)** ของเอกสารทุกประเภทในระบบ — ทั้ง RFA, RFI, Transmittal, Letter ฯลฯ เป็นการสื่อสารระหว่างองค์กร-องค์กร ภายนโครงการ (Project) รองรับผู้รับหลัก (TO) และผู้รับสำเนา (CC) ได้หลายองค์กร
## 3.2.2. ประเภทเอกสาร:
---
- ระบบต้องรองรับเอกสารรูปแบบ ไฟล์ PDF, ZIP
- เอกสารโต้ตอบ (Correspondence) สามารถมีได้หลายประเภท (Types) เช่น จดหมาย (Letter), อีเมล์ (Email), Request for Information (RFI), รวมถึง เอกสารขออนุมัติ (RFA) แต่ละ revision และสามารถเพิ่มประเภทใหม่ได้ในภายหลัง
## 3.2.2. โครงสร้างข้อมูล (Database Tables)
## 3.2.3. การสร้างเอกสาร (Correspondence):
| Table | บทบาท |
|---|---|
| `correspondences` | ข้อมูล Master: เลขเอกสาร, type, project, originator — ไม่เปลี่ยนตาม revision |
| `correspondence_revisions` | ประวัติแต่ละ Revision: subject, body, status, due_date |
| `correspondence_recipients` | ผู้รับ TO/CC (M:N กับ organizations) |
| `correspondence_references` | การอ้างอิงข้ามเอกสาร (M:N) |
| `correspondence_tags` | Tags ที่ติดกับเอกสาร (M:N) |
| `correspondence_attachments` | ไฟล์แนบ (M:N กับ attachments) |
| `correspondence_types` | Master: ประเภทเอกสาร (Global) |
| `correspondence_status` | Master: สถานะเอกสาร (Global) |
- ผู้ใช้ที่มีสิทธิ์ (เช่น Document Control) สามารถสร้างเอกสารรอไว้ในสถานะ ฉบับร่าง" (Draft) ได้ ซึ่งผู้ใช้งานต่างองค์กรจะมองไม่เห็น
- เมื่อเอกสารเปลี่ยนสถานะเป็น "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
**ข้อสำคัญ:** `correspondence_number` ต้อง UNIQUE ภายใน Project เดียวกัน (`uq_corr_no_per_project`)
## 3.2.4. การอ้างอิงและจัดกลุ่ม:
---
- เอกสารสามารถอ้างถึง (Reference) เอกสารฉบับก่อนหน้าได้หลายฉบับ
- สามารถกำหนด Tag ได้หลาย Tag เพื่อจัดกลุ่มและใช้ในการค้นหาขั้นสูง
## 3.2.3. ประเภทเอกสาร (correspondence_types)
## 3.2.5. Workflow (Unified Workflow):
ประเภทเป็น Global Master — จัดการโดย Superadmin เท่านั้น:
- ระบบต้องรองรับ Workflow ที่เป็นแบบ Unified Workflow
| type_code | ชื่อ | มี Extension Table |
|---|---|---|
| `RFA` | Request for Approval | ✅ `rfas` + `rfa_revisions` |
| `RFI` | Request for Information | ❌ (ใช้ `details` JSON) |
| `TRANSMITTAL` | Transmittal | ❌ (ใช้ `details` JSON) |
| `EMAIL` | Email | ❌ |
| `INSTRUCTION` | Instruction | ❌ |
| `LETTER` | Letter | ❌ |
| `MEMO` | Memorandum | ❌ |
| `MOM` | Minutes of Meeting | ❌ |
| `NOTICE` | Notice | ❌ |
| `OTHER` | Other | ❌ |
ไฟล์แนบรองรับ **PDF, ZIP**
---
## 3.2.4. Fields ที่ต้องกรอกเมื่อสร้าง Correspondence
| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID |
| Correspondence Type | ✅ | INT id (Global) |
| Subject | ✅ | ขั้นต่ำ 5 ตัวอักษร — เก็บใน `correspondence_revisions` |
| To Organization | ✅ | UUID — `recipient_type = 'TO'` (≥ 1) |
| CC Organizations | ❌ | UUID[] — `recipient_type = 'CC'` |
| Discipline | ❌ | INT — กรองตาม Contract |
| Body | ❌ | เนื้อหา — เก็บใน `correspondence_revisions` |
| Description | ❌ | คำอธิบาย Revision |
| Remarks | ❌ | หมายเหตุ |
| Document Date | ❌ | วันที่ในเอกสาร |
| Due Date | ❌ | กำหนดส่งคืน |
| Tags | ❌ | UUID[] — จัดกลุ่มเพื่อค้นหาขั้นสูง |
| References | ❌ | UUID[] — อ้างอิงเอกสารฉบับก่อนหน้า |
| Attachments | ❌ | PDF/ZIP — ผ่าน ClamAV scan |
| Is Internal | ❌ | `is_internal_communication = 1` → ใช้ Circulation แทน |
### Document Number Preview
ระบบแสดง Preview เลขเอกสารแบบ Real-time ก่อน Submit เมื่อกรอกครบ: Project + Type + Discipline + To Organization โดยเรียก `POST /api/correspondences/preview-number`
---
## 3.2.5. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | หมายเหตุ |
|---|---|---|
| สร้าง Correspondence (Draft) | Document Control, Org Admin, Superadmin | ภายในองค์กรตัวเอง |
| Submit Correspondence | Document Control, Org Admin, Superadmin | เปลี่ยนสถานะ DRAFT → SUB* |
| แก้ไข/ถอนกลับ/ยกเลิก หลัง Submit | **Org Admin ขึ้นไปเท่านั้น** พร้อมระบุเหตุผล | — |
| ดู Correspondence ที่ Draft | เฉพาะคนในองค์กรเดียวกัน | องค์กรอื่นมองไม่เห็น |
| ดู Correspondence ที่ Submitted แล้ว | ทุกคนที่มีสิทธิ์ใน Project | รวม TO และ CC org |
| จัดการ Correspondence Types (Master) | Superadmin | Global |
---
## 3.2.6. Status Codes (correspondence_status)
สถานะแบ่งตามหมวดและ Actor:
| หมวด | status_code | ชื่อ |
|---|---|---|
| **Draft** | `DRAFT` | Draft — มองเห็นเฉพาะ Originator Org |
| **Submitted** | `SUBOWN` | Submitted to Owner |
| | `SUBDSN` | Submitted to Designer |
| | `SUBCSC` | Submitted to CSC |
| | `SUBCON` | Submitted to Contractor |
| | `SUBOTH` | Submitted to Others |
| **Reply** | `REPOWN` | Reply by Owner |
| | `REPDSN` | Reply by Designer |
| | `REPCSC` | Reply by CSC |
| | `REPCON` | Reply by Contractor |
| | `REPOTH` | Reply by Others |
| **Resubmitted** | `RSBOWN` | Resubmitted by Owner |
| | `RSBDSN` | Resubmitted by Designer |
| | `RSBCSC` | Resubmitted by CSC |
| | `RSBCON` | Resubmitted by Contractor |
| **Closed** | `CLBOWN` | Closed by Owner |
| | `CLBDSN` | Closed by Designer |
| | `CLBCSC` | Closed by CSC |
| | `CLBCON` | Closed by Contractor |
| **Canceled** | `CCBOWN` | Canceled by Owner |
| | `CCBDSN` | Canceled by Designer |
| | `CCBCSC` | Canceled by CSC |
| | `CCBCON` | Canceled by Contractor |
---
## 3.2.7. การอ้างอิงและ Tags
- **References** (`correspondence_references`): M:N — เอกสารหนึ่งอ้างถึงได้หลายฉบับ ทิศทางเดียว (src → tgt)
- **Tags** (`correspondence_tags` + `tags`): M:N — Tag ผูกกับ Project หรือ Global (project_id = NULL)
- ทั้งสองอย่างใช้ค้นหาขั้นสูงใน Elasticsearch Index
---
## 3.2.8. Revision Model
- 1 Correspondence Master → หลาย Revision (1:N)
- `is_current = TRUE` มีได้เพียง 1 แถวต่อ correspondence (UNIQUE constraint)
- `revision_label`: A, B, C, ... (หรือ 1.1, 1.2 แล้วแต่ type)
- `revision_number`: 0-based integer สำหรับ sorting
---
## 3.2.9. Workflow (Unified Workflow)
Correspondence ใช้ Unified Workflow Engine — ดูรายละเอียดที่ `01-03-06-unified-workflow.md`
เมื่อ Correspondence ถูก Submit → ผู้รับ (TO/CC) สามารถสร้าง **Circulation Sheet** เพื่อมอบหมายงานภายในองค์กร (ดู `01-03-08-circulation-sheet.md`)
---
## 3.2.10. Business Rules และ Edge Cases
| รหัส | กฎ | Severity |
|---|---|---|
| **EC-CORR-001** | Cancel Correspondence ที่มี Circulation เปิดอยู่ → ต้องยืนยันก่อน + Force Close Circulation ทั้งหมด + Audit Log | 🔴 Critical |
| **EC-CORR-002** | Reply ต่อ Correspondence ที่ถูก Cancel → ทำได้แต่ UI ต้องแสดง Warning | 🟡 Medium |
| **EC-CORR-003** | Originator และ Recipient เป็นองค์กรเดียวกัน → Block (ใช้ Circulation แทน) | 🟡 Medium |
ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 7: Correspondence Edge Cases"
@@ -1,44 +1,166 @@
# 3.3 RFA Management (การจัดการเอกสาขออนุมัติ)
# 3.3 RFA Management (การจัดการเอกสาขออนุมัติ)
---
title: 'Functional Requirements: RFA Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-02-correspondence.md
- specs/01-requirements/01-03-modules/01-03-06-unified-workflow.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-RFA-001 ถึง EC-RFA-004)
- specs/03-Data-and-Storage/03-01-data-dictionary.md (§4.14.6)
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.3.1. วัตถุประสงค์:
## 3.3.1. วัตถุประสงค์
- เอกสารขออนุมัติ (RFA) ภายใน โครงการ (Projects)
เอกสารขออนุมัติ (RFA — Request For Approval) ใช้สำหรับส่งเอกสารหรือสิ่งของเพื่อขออนุมัติจากผู้ว่าจ้างหรือที่ปรึกษา ภายในโครงการ (Project)**ไม่ได้จำกัดแค่แบบก่อสร้าง** ประเภทของ RFA (RFA Type) เป็นตัวกำหนดว่าต้องแนบ Drawing Revision หรือไฟล์แนบ:
## 3.3.2. ประเภทเอกสาร:
- **ประเภทที่อ้างอิง Drawing** (DDW, SDW, ADW): ผูก Drawing Revision ได้หลายรายการผ่าน `rfa_items`
- **ประเภทอื่น** (DOC, MAT, ฯลฯ): แนบได้เพียง 1 ไฟล์ผ่าน `correspondence_attachments`
- ระบบต้องรองรับเอกสารรูปแบบ ไฟล์ PDF
- เอกสารขออนุมัติ (RFA) สามารถมีได้หลาย revision
- มีประถทของเอกสาร ได้หลายประเภท (RFA Types) และสามารถเพิ่มประเภทใหม่ได้ในภายหลัง
---
## 3.3.3. การสร้างเอกสาร:
## 3.3.2. โครงสร้างข้อมูล (Database Tables)
- ผู้ใช้ที่มีสิทธิ์ (เช่น Document Control) สามารถสร้างเอกสารขออนุมัติ (RFA) รอไว้ในสถานะ ฉบับร่าง" (Draft) ได้ ซึ่งผู้ใช้งานต่างองค์กรจะมองไม่เห็น
- เมื่อเอกสารเปลี่ยนสถานะเป็น "Submitted" แล้ว การแก้ไข, ถอนเอกสารกลับไปสถานะ Draft, หรือยกเลิก (Cancel) จะต้องทำโดยผู้ใช้ระดับ Admin ขึ้นไป พร้อมระบุเหตุผล
RFA ใช้ pattern **Correspondence + Extension**:
## 3.3.4. การอ้างอิงและจัดกลุ่ม:
| Table | บทบาท |
|---|---|
| `correspondences` | ข้อมูลหลัก: เลขเอกสาร, subject, project, originator, recipients |
| `rfas` | ข้อมูลเฉพาะ RFA: `rfa_type_id` (FK → `rfa_types`) |
| `rfa_revisions` | ประวัติแต่ละ Revision: status, approve code, details JSON |
| `rfa_items` | รายการ Drawing Revision ที่อ้างอิงใน Revision นั้น (เฉพาะ type DDW/SDW/ADW) |
| `rfa_types` | Master: ประเภท RFA (ผูกกับ Contract) |
| `rfa_status_codes` | Master: สถานะ RFA |
| `rfa_approve_codes` | Master: ผลการอนุมัติ |
- RFA สามารถอ้างถึง (Reference) แบบก่อสร้าง (Shop Drawing) ได้หลายฉบับ
- การสร้าง RFA ต้องสร้างเอกสารแม่ใน `correspondences` โดยใช้ `correspondence_types.type_code = 'RFA'`
- ประเภทย่อยของ RFA ต้องเก็บใน `rfas.rfa_type_id`
- ถ้า `rfa_types.type_code` เป็น `DDW` หรือ `SDW` ระบบต้องบังคับให้เลือกอย่างน้อย 1 `shop_drawing_revision`
- ถ้า `rfa_types.type_code` เป็น `ADW` ระบบต้องบังคับให้เลือกอย่างน้อย 1 `asbuilt_drawing_revision`
- 1 แถวใน `rfa_items` ต้องอ้างอิง Drawing Revision ได้เพียง 1 รายการเท่านั้น โดยเป็น `shop_drawing_revision` หรือ `asbuilt_drawing_revision` อย่างใดอย่างหนึ่ง
**ข้อสำคัญ:** `rfas.id` ใช้ FK ชี้ไปที่ `correspondences.id` (ไม่มี AUTO_INCREMENT ของตัวเอง)
## 3.3.5. Workflow (Unified Workflow):
---
- ระบบต้องรองรับ Workflow ที่เป็นแบบ Unified Workflow
## 3.3.3. ประเภทเอกสาร (RFA Types)
- `rfa_types` เป็น Master ที่ผูกกับ **Contract** (ไม่ใช่ Project) — `contract_id` FK
- แต่ละ Contract มี RFA Types ของตัวเอง สามารถเพิ่มใหม่ได้ในภายหลัง
- ไฟล์แนบรองรับรูปแบบ **PDF**
- RFA สามารถมีได้หลาย Revision (Rev.A, Rev.B, ...)
### type_code ที่กำหนด drawing requirement:
| type_code | ชื่อ | Attachment Mechanism | บังคับ |
|---|---|---|---|
| `DDW` | Drawing for Design | `rfa_items` → Shop Drawing Revision | ≥ 1 |
| `SDW` | Shop Drawing | `rfa_items` → Shop Drawing Revision | ≥ 1 |
| `ADW` | As-Built Drawing | `rfa_items` → As-Built Drawing Revision | ≥ 1 |
| อื่นๆ | เช่น DOC, MAT | `correspondence_attachments` (1 ไฟล์) | ไม่บังคับ |
---
## 3.3.4. Fields ที่ต้องกรอกเมื่อสร้าง RFA
| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID — กรองจาก Project ที่ผู้ใช้มีสิทธิ์ |
| Contract | ✅ | UUID — filter ตาม Project ที่เลือก |
| Discipline | ✅ | INT id — filter ตาม Contract ที่เลือก |
| RFA Type | ✅ | INT id — filter ตาม Contract ที่เลือก |
| To Organization | ✅ | UUID — ผู้รับหลัก (recipients type = 'TO') |
| Subject | ✅ | ขั้นต่ำ 5 ตัวอักษร |
| Body | ❌ | เนื้อหาเพิ่มเติม |
| Description | ❌ | คำอธิบายสั้น |
| Remarks | ❌ | หมายเหตุ |
| Due Date | ❌ | กำหนดส่งคืน |
| Shop Drawing Revisions | บังคับเมื่อ type = DDW/SDW | UUID[] |
| As-Built Drawing Revisions | บังคับเมื่อ type = ADW | UUID[] |
### Document Number Preview
ระบบแสดง Preview เลขเอกสารแบบ Real-time ก่อน Submit เมื่อกรอกครบ: Project + Correspondence Type + Discipline + To Organization โดยเรียก `POST /api/correspondences/preview-number`
---
## 3.3.5. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | หมายเหตุ |
|---|---|---|
| สร้าง RFA (Draft) | Document Control, Org Admin, Superadmin | ภายในองค์กรตัวเอง |
| Submit RFA | Document Control, Org Admin, Superadmin | เปลี่ยนสถานะ Draft → FAP/FRE |
| แก้ไข/ถอนกลับ/ยกเลิก หลัง Submit | **Org Admin ขึ้นไปเท่านั้น** พร้อมระบุเหตุผล | — |
| ดู RFA ที่ Draft | เฉพาะคนในองค์กรเดียวกัน | องค์กรอื่นมองไม่เห็น |
| ดู RFA ที่ Submitted แล้ว | ทุกคนที่มีสิทธิ์ใน Project | — |
| จัดการ RFA Types (Master) | Superadmin | Global |
---
## 3.3.6. การอ้างอิง Drawing Revisions (rfa_items)
- 1 RFA Revision สามารถอ้างอิง Drawing Revision ได้หลายรายการ
- 1 แถวใน `rfa_items` อ้างอิง Drawing Revision ได้ **เพียง 1 รายการเท่านั้น** โดยต้องเป็น `shop_drawing_revision` หรือ `asbuilt_drawing_revision` อย่างใดอย่างหนึ่ง (ไม่ใช่ทั้งคู่)
- `item_type` ENUM: `'SHOP'` | `'AS_BUILT'` — กำหนดว่า FK ไหนที่ต้อง NOT NULL
- 1 Drawing Revision สามารถถูกอ้างอิงโดยหลาย RFA ได้ (แต่ดู EC-RFA-001)
### Unique Constraint:
- `(rfa_revision_id, shop_drawing_revision_id)` — ห้าม Drawing เดิมซ้ำใน RFA เดียวกัน
- `(rfa_revision_id, asbuilt_drawing_revision_id)` — เช่นเดียวกัน
---
## 3.3.7. Status Codes (rfa_status_codes)
| status_code | ชื่อ | ความหมาย |
|---|---|---|
| `DFT` | Draft | ฉบับร่าง — มองเห็นเฉพาะ Originator Org |
| `FAP` | For Approve | ส่งเพื่อขออนุมัติ |
| `FRE` | For Review | ส่งเพื่อตรวจสอบ |
| `FCO` | For Construction | อนุมัติให้ก่อสร้างได้ |
| `ASB` | AS-Built | แบบก่อสร้างจริง |
| `OBS` | Obsolete | ไม่ใช้งานแล้ว |
| `CC` | Canceled | ยกเลิก |
---
## 3.3.8. Approve Codes (rfa_approve_codes)
ผลการอนุมัติบันทึกใน `rfa_revisions.rfa_approve_code_id`:
| approve_code | ชื่อ | ความหมาย |
|---|---|---|
| `1A` | Approved by Authority | อนุมัติโดยหน่วยงานที่มีอำนาจ |
| `1C` | Approved by CSC | อนุมัติโดย CSC |
| `1N` | Approved As Note | อนุมัติพร้อมบันทึก |
| `1R` | Approved with Remarks | อนุมัติพร้อมข้อสังเกต |
| `3C` | Consultant Comments | มีความเห็นจากที่ปรึกษา |
| `3R` | Revise and Resubmit | ขอให้แก้ไขและส่งใหม่ |
| `4X` | Reject | ปฏิเสธ |
| `5N` | No Further Action | ไม่ต้องดำเนินการเพิ่มเติม |
---
## 3.3.9. Workflow (Unified Workflow)
RFA ใช้ Unified Workflow Engine — ดูรายละเอียดที่ `01-03-06-unified-workflow.md`
สถานะการสร้าง Revision ใหม่:
- ห้ามมี 2 Active Revision พร้อมกัน (EC-RFA-002)
- สร้าง Rev.B ได้ก็ต่อเมื่อ Rev.A มีผลสุดท้ายแล้ว (`3R`, `4X`, หรือ Approved)
---
## 3.3.10. Business Rules และ Edge Cases
| รหัส | กฎ | Severity |
|---|---|---|
| **EC-RFA-001** | 1 Shop Drawing Revision มี Active RFA ได้สูงสุด 1 ฉบับ (ยกเว้นถูก REJECTED/CANCELLED แล้ว) | 🔴 Critical |
| **EC-RFA-002** | ห้ามสร้าง Revision ใหม่ถ้า Revision ก่อนหน้ายังไม่มีคำตอบสุดท้าย | 🟠 High |
| **EC-RFA-003** | Discipline ต้องเลือกก่อนเสมอ ไม่มี Auto-detection (AI Classification เป็น Phase 3) | 🟡 Medium |
| **EC-RFA-004** | Transmittal ที่มี RFA Submit ได้ก็ต่อเมื่อทุก RFA อยู่ในสถานะ READY (ไม่ใช่ DRAFT) | 🟠 High |
ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 4: RFA & Drawing Edge Cases"
@@ -3,30 +3,103 @@
---
title: 'Functional Requirements: Contract Drawing Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-05-shop-drawing.md
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.4.1. วัตถุประสงค์:
## 3.4.1. วัตถุประสงค์
- แบบคู่สัญญา (Contract Drawing) ใช้เพื่ออ้างอิงและใช้ในการตรวจสอบ
แบบคู่สัญญา (Contract Drawing) คือแบบที่ได้รับจากสัญญาก่อสร้าง ใช้เป็น **เอกสารอ้างอิงหลัก** สำหรับ Shop Drawing และ As-Built Drawing ภายในโครงการ ไม่มี Revision Model — แต่ละแบบเป็นเอกสาร Master คงที่
## 3.4.2. ประเภทเอกสาร:
> **หมายเหตุการพัฒนา:** ข้อมูล Contract Drawing มาจาก **Seed Data** (นำเข้าจากข้อมูลสัญญาที่มีอยู่แล้ว) ไม่ได้สร้างใหม่ผ่าน UI ระบบอัปโหลดไฟล์ PDF อยู่**ระหว่างการพัฒนา** — ปัจจุบัน record มีอยู่ในระบบแต่ไฟล์แนบยังไม่สมบูรณ์
- ไฟล์ PDF
---
## 3.4.3. การสร้างเอกสาร:
## 3.4.2. โครงสร้างข้อมูล (Database Tables)
- ผู้ใช้ที่มีสิทธิ์ สามารถสร้างและแก้ไขได้
| Table | บทบาท |
|---|---|
| `contract_drawings` | ข้อมูล Master แบบคู่สัญญา: เลขแบบ, ชื่อ, หมวดหมู่, เล่ม |
| `contract_drawing_attachments` | ไฟล์แนบ (M:N กับ `attachments`) รองรับหลายไฟล์ต่อแบบ |
| `contract_drawing_volumes` | Master: เล่มของแบบ (ผูกกับ Project) |
| `contract_drawing_cats` | Master: หมวดหมู่หลัก (ผูกกับ Project) |
| `contract_drawing_sub_cats` | Master: หมวดหมู่ย่อย (ผูกกับ Project) |
| `contract_drawing_subcat_cat_maps` | M:N ระหว่าง หมวดหมู่หลัก ↔ หมวดหมู่ย่อย (ผูกกับ Project) |
## 3.4.4. การอ้างอิงและจัดกลุ่ม:
**ข้อสำคัญ:** `condwg_no` ต้อง UNIQUE ภายใน Project เดียวกัน (`ux_condwg_no_project`)
- ใช้สำหรับอ้างอิง ใน Shop Drawings, มีการจัดหมวดหมู่ของ Contract Drawing
---
## 3.4.3. Fields ที่ต้องกรอกเมื่อสร้าง Contract Drawing
| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID — ผูกกับ `projects` |
| Drawing Number (`condwg_no`) | ✅ | VARCHAR(255) — unique per project |
| Title | ✅ | VARCHAR(255) |
| Category (`map_cat_id`) | ❌ | FK → `contract_drawing_subcat_cat_maps` |
| Volume (`volume_id`) | ❌ | FK → `contract_drawing_volumes` |
| Volume Page (`volume_page`) | ❌ | INT |
| Attachments | ❌ | PDF / DWG / SOURCE / OTHER — ผ่าน ClamAV scan (**อยู่ระหว่างพัฒนาระบบนำเข้า PDF**) |
---
## 3.4.4. ไฟล์แนบ (contract_drawing_attachments)
รองรับหลายไฟล์ต่อ 1 Contract Drawing:
| file_type | ความหมาย |
|---|---|
| `PDF` | ไฟล์ PDF แบบดิจิทัล |
| `DWG` | ไฟล์ AutoCAD |
| `SOURCE` | ไฟล์ต้นฉบับอื่นๆ |
| `OTHER` | ประเภทอื่น |
- `is_main_document = TRUE` ระบุไฟล์หลัก (แสดงเป็น Default สำหรับ Preview)
> **สถานะ:** ข้อมูล `contract_drawings` ถูก Seed เข้าระบบแล้ว แต่ `contract_drawing_attachments` ยังว่างอยู่ระหว่างรอระบบ PDF Import
---
## 3.4.5. โครงสร้างหมวดหมู่ (Category Structure)
หมวดหมู่ผูกกับ **Project** (ไม่ใช่ Global) — จัดการโดย Project Manager:
```
contract_drawing_volumes (เล่ม — Volume)
contract_drawing_cats (หมวดหมู่หลัก — Main Category)
contract_drawing_sub_cats (หมวดหมู่ย่อย — Sub Category)
contract_drawing_subcat_cat_maps (M:N: Sub Category ↔ Main Category)
```
- `contract_drawings.map_cat_id` FK → `contract_drawing_subcat_cat_maps`
- 1 Sub Category สามารถอยู่ใน Main Category ได้หลายหมวด (M:N)
---
## 3.4.6. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | Scope |
|---|---|---|
| สร้าง / แก้ไข Contract Drawing | Project Manager, Org Admin, Superadmin | Project |
| ลบ Contract Drawing | Org Admin, Superadmin | Project |
| จัดการ Volume / Category (Master) | Project Manager | Project |
| ดู Contract Drawing | ทุกคนที่มีสิทธิ์ใน Project | Project |
---
## 3.4.7. ความสัมพันธ์กับ Module อื่น
- **Shop Drawing** (`shop_drawings`) อ้างอิง `contract_drawing_id` → ใช้ Contract Drawing เป็นแบบต้นฉบับ
- Contract Drawing **ไม่มี Revision Model** — ต่างจาก Shop Drawing ที่มี `shop_drawing_revisions`
- ไม่มีความสัมพันธ์โดยตรงกับ RFA — RFA อ้างอิง `shop_drawing_revisions` ไม่ใช่ Contract Drawing
@@ -3,30 +3,132 @@
---
title: 'Functional Requirements: Shop Drawing Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-03-rfa.md
- specs/01-requirements/01-03-modules/01-03-04-contract-drawing.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-RFA-001, EC-RFA-003)
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.5.1. วัตถุประสงค์:
## 3.5.1. วัตถุประสงค์
- แบบก่อสร้าง (Shop Drawing) ใช้เในการตรวจสอบ โดยจัดส่งด้วย Request for Approval (RFA)
แบบก่อสร้าง (Shop Drawing) คือแบบที่ Contractor จัดทำขึ้นเพื่อขออนุมัติจากผู้ว่าจ้างหรือที่ปรึกษา โดยส่งผ่าน RFA (Request for Approval) — มี Revision Model (Rev.A, Rev.B, ...) และอ้างอิง Contract Drawing ที่เป็นต้นฉบับได้
## 3.5.2. ประเภทเอกสาร:
---
- ไฟล์ PDF, DWG, ZIP
## 3.5.2. โครงสร้างข้อมูล (Database Tables)
## 3.5.3. การสร้างเอกสาร:
| Table | บทบาท |
|---|---|
| `shop_drawings` | ข้อมูล Master: เลขแบบ, หมวดหมู่หลัก, หมวดหมู่ย่อย, project |
| `shop_drawing_revisions` | ประวัติแต่ละ Revision: title, revision_label, is_current, revision_date |
| `shop_drawing_revision_contract_refs` | M:N: Revision ↔ Contract Drawing ที่อ้างอิง |
| `shop_drawing_revision_attachments` | ไฟล์แนบต่อ Revision (M:N กับ `attachments`) |
| `shop_drawing_main_categories` | Master: หมวดหมู่หลัก (ผูกกับ Project) |
| `shop_drawing_sub_categories` | Master: หมวดหมู่ย่อย (ผูกกับ Project) |
- ผู้ใช้ที่มีสิทธิ์ สามารถสร้างและแก้ไขได้ โดยผู้ใช้ที่มีสิทธิ์ (เช่น Document Control) สามารถสร้างเอกสารรอไว้ในสถานะ ฉบับร่าง" (Draft) ได้ ซึ่งผู้ใช้งานต่างองค์กรจะมองไม่เห็น
**ข้อสำคัญ:**
- `drawing_number` ต้อง UNIQUE ภายใน Project (`ux_shop_dwg_no_project`)
- `is_current = TRUE` มีได้เพียง 1 แถวต่อ Shop Drawing (`uq_sd_current`)
## 3.5.4. การอ้างอิงและจัดกลุ่ม:
---
- ใช้สำหรับอ้างอิง ใน RFA, มีการจัดหมวดหมู่ของ Shop Drawings โดยทุก แบบก่อสร้าง (Shop Drawing) แต่ละ revision ต้องมี RFA ได้เพียง 1 ฉบับ
## 3.5.3. Fields ที่ต้องกรอกเมื่อสร้าง Shop Drawing
### Master (shop_drawings)
| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID |
| Drawing Number | ✅ | VARCHAR(100) — unique per project |
| Main Category | ✅ | INT id — FK → `shop_drawing_main_categories` |
| Sub Category | ✅ | INT id — FK → `shop_drawing_sub_categories` |
### Revision (shop_drawing_revisions)
| Field | Required | หมายเหตุ |
|---|---|---|
| Title | ✅ | VARCHAR(500) — ชื่อแบบใน Revision นี้ |
| Revision Label | ❌ | VARCHAR(10) เช่น A, B, 1.1 |
| Revision Date | ❌ | DATE |
| Description | ❌ | คำอธิบายการแก้ไข |
| Legacy Drawing Number | ❌ | VARCHAR(100) — เลขแบบเดิม (สำหรับข้อมูล Migration) |
| Contract Drawing Refs | ❌ | UUID[] — อ้างอิง Contract Drawing ต้นฉบับ |
| Attachments | ❌ | PDF / DWG / SOURCE / OTHER — ผ่าน ClamAV scan |
---
## 3.5.4. ไฟล์แนบ (shop_drawing_revision_attachments)
ไฟล์แนบผูกกับ **Revision** ไม่ใช่ Master — รองรับหลายไฟล์ต่อ 1 Revision:
| file_type | ความหมาย |
|---|---|
| `PDF` | ไฟล์ PDF แบบดิจิทัล |
| `DWG` | ไฟล์ AutoCAD |
| `SOURCE` | ไฟล์ต้นฉบับอื่นๆ |
| `OTHER` | ประเภทอื่น |
- `is_main_document = TRUE` ระบุไฟล์หลักของ Revision นั้น
---
## 3.5.5. โครงสร้างหมวดหมู่ (Category Structure)
หมวดหมู่ผูกกับ **Project** — จัดการโดย Project Manager:
```
shop_drawing_main_categories (หมวดหมู่หลัก เช่น ARCH, STR, MEP)
shop_drawing_sub_categories (หมวดหมู่ย่อย เช่น STR-COLUMN, STR-BEAM)
```
- ต่างจาก Contract Drawing ที่ Main ↔ Sub เป็น M:N — Shop Drawing เป็น **direct FK**: `shop_drawings.main_category_id` และ `shop_drawings.sub_category_id` (1 แบบ = 1 Main + 1 Sub)
---
## 3.5.6. Revision Model
- 1 Shop Drawing Master → หลาย Revision (1:N)
- `revision_number`: 0-based integer สำหรับ sorting
- `revision_label`: A, B, C, ... — แสดงใน UI
- `is_current = TRUE` มีได้เพียง 1 แถว (NULL สำหรับที่ไม่ใช่ปัจจุบัน — ต่างจาก BOOLEAN เพื่อให้ UNIQUE constraint ทำงาน)
---
## 3.5.7. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | Scope |
|---|---|---|
| สร้าง Shop Drawing + Revision | Document Control, Org Admin, Superadmin | Project |
| แก้ไข Shop Drawing | Document Control, Org Admin, Superadmin | Project |
| ลบ Shop Drawing | Org Admin, Superadmin | Project |
| จัดการ Main/Sub Category (Master) | Project Manager | Project |
| ดู Shop Drawing | ทุกคนที่มีสิทธิ์ใน Project | Project |
---
## 3.5.8. ความสัมพันธ์กับ Module อื่น
- **RFA** (`rfa_items`) อ้างอิง `shop_drawing_revision_id` → 1 Revision มี Active RFA ได้สูงสุด 1 ฉบับ (EC-RFA-001)
- **Contract Drawing** (`shop_drawing_revision_contract_refs`) — แต่ละ Revision สามารถอ้างอิง Contract Drawing ต้นฉบับได้หลายฉบับ (M:N)
- **As-Built Drawing** — ไม่มีความสัมพันธ์โดยตรง (คนละ module)
---
## 3.5.9. Business Rules และ Edge Cases
| รหัส | กฎ | Severity |
|---|---|---|
| **EC-RFA-001** | 1 Shop Drawing Revision มี Active RFA ได้สูงสุด 1 ฉบับ (ยกเว้น REJECTED/CANCELLED แล้ว) | 🔴 Critical |
| **EC-RFA-003** | Discipline และ Category ต้องเลือกก่อน Upload — ไม่มี Auto-detection (Phase 3) | 🟡 Medium |
ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 4: RFA & Drawing Edge Cases"
@@ -3,41 +3,147 @@
---
title: 'Functional Requirements: Unified Workflow Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-02-correspondence.md
- specs/01-requirements/01-03-modules/01-03-03-rfa.md
- specs/01-requirements/01-03-modules/01-03-08-circulation-sheet.md
- specs/06-Decision-Records/ADR-001-unified-workflow-engine.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.6.1 Workflow Definition:
## 3.6.1. วัตถุประสงค์
- Admin ต้องสามารถกำหนดและสร้าง/แก้ไข Workflow Rule ได้ (DSL)
- รองรับการกำหนด State, Transition, Required Role, Condition (JS Expression)
Unified Workflow Engine คือ **Engine กลาง** สำหรับจัดการสถานะ (State) และการเปลี่ยนสถานะ (Transition) ของเอกสารทุกประเภทในระบบ ใช้ **JSON-based DSL** เก็บ Workflow Definition ไว้ใน Database ไม่ต้อง Deploy ใหม่เมื่อแก้ Workflow
## 3.6.2 Workflow Execution:
ดูการตัดสินใจเลือก Architecture ได้ที่ `ADR-001-unified-workflow-engine.md`
- ระบบต้องรองรับการสร้าง Instance ของ Workflow ผูกกับเอกสาร (Polymorphic)
- รองรับการเปลี่ยนสถานะ (Action) เช่น Approve, Reject, Comment, Return
- Auto-Action: รองรับการเปลี่ยนสถานะอัตโนมัติเมื่อครบเงื่อนไข (เช่น Review ครบทุกคน)
---
## 3.6.3 Flexibility:
## 3.6.2. โครงสร้างข้อมูล (Database Tables)
- รองรับ Parallel Review (ส่งให้หลายคนตรวจพร้อมกัน)
- รองรับ Conditional Flow (เช่น ถ้ายอดเงิน > X ให้เพิ่มผู้อนุมัติ)
| Table | บทบาท |
|---|---|
| `workflow_definitions` | นิยาม Workflow (DSL + compiled) — versioned per `workflow_code` |
| `workflow_instances` | Instance ผูกกับเอกสาร — เก็บ `current_state` + `context` JSON |
| `workflow_histories` | Audit Trail: ทุก transition บันทึก from/to state, action, user, comment |
## 3.6.4 Workflow การอนุมัติ:
### workflow_instances.entity_type ที่รองรับ
- รองรับกระบวนการอนุมัติที่ซับซ้อนและเป็นลำดับ เช่น ส่งจาก Originator -> Organization 1 -> Organization 2 -> Organization 3 แล้วส่งผลกลับตามลำดับเดิม (โดยถ้า องกรณ์ใดใน Workflow ให้ส่งกลับ ก็สามารถส่งผลกลับตามลำดับเดิมโดยไม่ต้องรอให้ถึง องกรณืในลำดับถัดไป)
| entity_type | Module |
|---|---|
| `rfa_revision` | RFA Revision |
| `correspondence_revision` | Correspondence Revision |
| `circulation` | Circulation Sheet |
## 3.6.5 การจัดการ:
### workflow_instances.status
- สามารถกำหนดวันแล้วเสร็จ (Deadline) สำหรับผู้รับผิดชอบของ องกรณ์ ที่อยู่ใน Workflow ได้
- มีระบบแจ้งเตือน ให้ผู้รับผิดชอบของ องกรณ์ ที่อยู่ใน Workflow ทราบ เมื่อมี RFA ใหม่ หรือมีการเปลี่ยนสถานะ
- สามารถข้ามขั้นตอนได้ในกรณีพิเศษ (โดยผู้มีสิทธิ์)
- สามารถส่งกลับขั้นตอนก่อนหน้าได้
| status | ความหมาย |
|---|---|
| `ACTIVE` | กำลังดำเนินการ |
| `COMPLETED` | เสร็จสมบูรณ์ (ถึง terminal state) |
| `CANCELLED` | ยกเลิกโดยผู้ใช้ |
| `TERMINATED` | ถูกยุติโดยระบบ |
---
## 3.6.3. Workflow Definition (DSL)
Workflow Definition เก็บ 2 ฟอร์แมตใน DB:
- `dsl` — JSON ต้นฉบับที่ Admin กำหนด
- `compiled` — Execution Tree ที่ Engine Compile แล้ว (optimize สำหรับ runtime)
### DSL Structure (ตัวอย่าง)
```json
{
"workflow": "CORRESPONDENCE_ROUTING",
"version": 1,
"states": [
{
"name": "DRAFT",
"initial": true,
"on": {
"SUBMIT": {
"to": "SUBMITTED",
"require": { "role": ["Document Control", "Org Admin"] },
"condition": "context.hasRecipient === true",
"events": [{ "type": "notify", "target": "recipients" }]
}
}
},
{ "name": "SUBMITTED", "on": { "RETURN": { "to": "DRAFT" }, "CLOSE": { "to": "CLOSED" } } },
{ "name": "CLOSED", "terminal": true }
]
}
```
### DSL Elements
| Element | ความหมาย |
|---|---|
| `states[].initial` | State เริ่มต้นเมื่อสร้าง Instance |
| `states[].terminal` | State สุดท้าย — Instance จะ COMPLETED |
| `on.<ACTION>.to` | State ปลายทางหลัง transition |
| `on.<ACTION>.require.role` | Role ที่ต้องมีจึงจะ trigger action ได้ |
| `on.<ACTION>.condition` | JS Expression ประเมินจาก `context` JSON |
| `on.<ACTION>.events` | Events ที่ fire หลัง transition (notify, etc.) |
---
## 3.6.4. Workflow Execution
1. **สร้าง Instance** — เมื่อเอกสารถูกสร้าง → `WorkflowEngineService.createInstance(workflowCode, entityType, entityId)`
2. **Transition**`processTransition(instanceId, action, userId, comment)` → validate role + condition → update `current_state` → write `workflow_histories`
3. **Auto-Action** — เมื่อ condition ครบ (เช่น Review ครบทุกคน) Engine trigger transition อัตโนมัติ
4. **Terminal State**`instance.status = COMPLETED` เมื่อถึง terminal state
### Versioning
- แก้ Workflow ได้โดยเพิ่ม `version` ใหม่ — In-progress instances ยังคงใช้ version เดิม
- `UNIQUE KEY (workflow_code, version)` — ป้องกัน version ซ้ำ
---
## 3.6.5. Flexibility
- **Sequential Approval:** Originator → Org1 → Org2 → Org3 → ส่งผลกลับตามลำดับเดิม — องค์กรใด Reject ได้ทันทีโดยไม่รอลำดับถัดไป
- **Parallel Review:** ส่งให้หลายคนตรวจพร้อมกัน — รอผลครบก่อน transition
- **Conditional Flow:** `condition` expression ประเมิน `context` — เช่น เพิ่ม Approver เมื่อยอดเกิน threshold
- **Skip Step:** ผู้มีสิทธิ์ข้ามขั้นตอนได้ (force transition)
- **Return:** ส่งกลับ state ก่อนหน้าได้ พร้อม comment บังคับ
---
## 3.6.6. Notifications & Deadline
- **Event:** `"type": "notify"` ใน DSL → fire ผ่าน Notification Module (BullMQ)
- **Deadline:** กำหนดได้ต่อ Org ใน Workflow Step
- **แจ้งเตือน:** เมื่อมีเอกสารใหม่ หรือสถานะเปลี่ยน → Email / LINE Notify / In-App
---
## 3.6.7. RBAC
| การกระทำ | Role ที่อนุญาต |
|---|---|
| จัดการ Workflow Definition (สร้าง/แก้ไข DSL) | Superadmin |
| Trigger Workflow Action (Submit, Approve, Reject, ฯลฯ) | ขึ้นอยู่กับ `require.role` ใน DSL |
| ดู Workflow History | ทุกคนที่มีสิทธิ์ใน Document นั้น |
---
## 3.6.8. Audit Trail (workflow_histories)
ทุก transition บันทึก:
- `from_state` / `to_state` / `action`
- `action_by_user_id` — ผู้กระทำ
- `comment` — ความเห็น (บังคับสำหรับ Return/Reject)
- `metadata` JSON — Snapshot ข้อมูล ณ ขณะนั้น
@@ -3,30 +3,96 @@
---
title: 'Functional Requirements: Transmittals Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-02-correspondence.md
- specs/01-requirements/01-03-modules/01-03-03-rfa.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-RFA-004)
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.7.1. วัตถุประสงค์:
## 3.7.1. วัตถุประสงค์
- เอกสารนำส่ง ใช้สำหรับ นำส่ง Request for Approval (RFAS) หลายฉบับ ไปยังองค์กรอื่น
เอกสารนำส่ง (Transmittal) ใช้สำหรับรวบรวมเอกสารหลายฉบับ (เช่น RFA) แล้วส่งเป็นชุดไปยังองค์กรอื่นในคราวเดียว เป็น **Correspondence ประเภทหนึ่ง** (`type_code = 'TRANSMITTAL'`) — ใช้ pattern **Correspondence + Extension** เช่นเดียวกับ RFA
## 3.7.2. ประเภทเอกสาร:
---
- ไฟล์ PDF
## 3.7.2. โครงสร้างข้อมูล (Database Tables)
## 3.7.3. การสร้างเอกสาร:
| Table | บทบาท |
|---|---|
| `correspondences` | ข้อมูลหลัก: เลขเอกสาร, subject, project, originator, recipients |
| `transmittals` | ข้อมูลเฉพาะ Transmittal: `purpose`, `remarks` — FK = `correspondences.id` |
| `transmittal_items` | รายการเอกสารที่นำส่งใน Transmittal นั้น (M:N กับ `correspondences`) |
- ผู้ใช้ที่มีสิทธิ์ สามารถสร้างและแก้ไขได้
**ข้อสำคัญ:** `transmittals.correspondence_id` คือ PK และ FK ชี้ไปที่ `correspondences.id` (ไม่มี AUTO_INCREMENT ของตัวเอง)
## 3.7.4. การอ้างอิงและจัดกลุ่ม:
---
- เอกสารนำส่ง เป็นส่วนหนึ่งใน Correspondence
## 3.7.3. Fields ที่ต้องกรอกเมื่อสร้าง Transmittal
| Field | Required | หมายเหตุ |
|---|---|---|
| Project | ✅ | UUID — เหมือน Correspondence ทั่วไป |
| Correspondence Type | ✅ | ต้องเป็น `TRANSMITTAL` |
| Subject | ✅ | ขั้นต่ำ 5 ตัวอักษร |
| To Organization | ✅ | UUID — `recipient_type = 'TO'` |
| Purpose | ❌ | ENUM — วัตถุประสงค์การนำส่ง |
| Remarks | ❌ | หมายเหตุ |
| Items (เอกสารที่นำส่ง) | ❌ | UUID[] — รายการ Correspondence ที่แนบ |
### Purpose ENUM (transmittals.purpose)
| purpose | ความหมาย |
|---|---|
| `FOR_APPROVAL` | นำส่งเพื่อขออนุมัติ |
| `FOR_INFORMATION` | นำส่งเพื่อทราบ |
| `FOR_REVIEW` | นำส่งเพื่อตรวจสอบ |
| `OTHER` | วัตถุประสงค์อื่น |
---
## 3.7.4. transmittal_items
รายการเอกสารที่แนบใน Transmittal:
| Field | หมายเหตุ |
|---|---|
| `transmittal_id` | FK → `transmittals.correspondence_id` |
| `item_correspondence_id` | FK → `correspondences.id` — เอกสารที่นำส่ง (เช่น RFA) |
| `quantity` | จำนวน (default = 1) |
| `remarks` | หมายเหตุสำหรับรายการนี้ |
- UNIQUE KEY `(transmittal_id, item_correspondence_id)` — ป้องกันเอกสารซ้ำใน Transmittal เดียวกัน
- 1 Transmittal รวบรวมเอกสารได้หลายฉบับ
- เอกสารที่นำส่งได้ไม่จำกัดประเภท (RFA, Letter, ฯลฯ)
---
## 3.7.5. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | หมายเหตุ |
|---|---|---|
| สร้าง Transmittal (Draft) | Document Control, Org Admin, Superadmin | ภายในองค์กรตัวเอง |
| Submit Transmittal | Document Control, Org Admin, Superadmin | ต้องผ่าน EC-RFA-004 ก่อน |
| แก้ไข/ยกเลิก หลัง Submit | **Org Admin ขึ้นไปเท่านั้น** พร้อมระบุเหตุผล | — |
| ดู Transmittal ที่ Draft | เฉพาะคนในองค์กรเดียวกัน | — |
| ดู Transmittal ที่ Submitted | ทุกคนที่มีสิทธิ์ใน Project | — |
---
## 3.7.6. Business Rules และ Edge Cases
| รหัส | กฎ | Severity |
|---|---|---|
| **EC-RFA-004** | Transmittal Submit ได้เฉพาะเมื่อ **ทุกเอกสารใน Transmittal** อยู่ในสถานะ READY (ไม่ใช่ DRAFT) — ถ้ามี DRAFT → 422 "RFA [เลข] ยังอยู่ใน Draft กรุณา Submit ก่อน" | 🟠 High |
ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 4: RFA & Drawing Edge Cases"
@@ -3,39 +3,101 @@
---
title: 'Functional Requirements: Circulation Sheet Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-02-correspondence.md
- specs/01-requirements/01-03-modules/01-03-06-unified-workflow.md
- specs/01-requirements/01-06-edge-cases-and-rules.md (EC-CIRC-001 ถึง EC-CIRC-003, EC-CORR-001)
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
---
## 3.8.1. วัตถุประสงค์:
## 3.8.1. วัตถุประสงค์
- การสื่อสาร เอกสาร (Correspondence) ทุกฉบับ จะมีใบเวียนเอกสารเพื่อควบคุมและมอบหมายงานภายในองค์กร (สามารถดูและแก้ไขได้เฉพาะคนในองค์กร)
ใบเวียนเอกสาร (Circulation Sheet) ใช้สำหรับ **มอบหมายและติดตามงานภายในองค์กร** เมื่อได้รับ Correspondence จากภายนอก — **มองเห็นและแก้ไขได้เฉพาะคนในองค์กรเดียวกัน** เท่านั้น
## 3.8.2. ประเภทเอกสาร:
---
- ไฟล์ PDF
## 3.8.2. โครงสร้างข้อมูล (Database Tables)
## 3.8.3. การสร้างเอกสาร:
| Table | บทบาท |
|---|---|
| `circulations` | ข้อมูล Master: เลขใบเวียน, subject, status, organization — ผูก 1:1 กับ `correspondences` |
| `circulation_attachments` | ไฟล์แนบเพิ่มเติม (M:N กับ `attachments`) |
| `circulation_status_codes` | Master: สถานะใบเวียน |
- ผู้ใช้ที่มีสิทธิ์ในองค์กรนั้น สามารถสร้างและแก้ไขได้
**ข้อสำคัญ:**
- `circulations.correspondence_id` UNIQUE — 1 Correspondence มีใบเวียนได้ **1 ฉบับต่อองค์กร**
- ใบเวียนผูกกับ `organization_id` — มองเห็นเฉพาะคนในองค์กรนั้น
## 3.8.4. การอ้างอิงและจัดกลุ่ม:
---
- การระบุผู้รับผิดชอบ:
- ผู้รับผิดชอบหลัก (Main): มีได้หลายคน
- ผู้ร่วมปฏิบัติงาน (Action): มีได้หลายคน
- ผู้ที่ต้องรับทราบ (Information): มีได้หลายคน
## 3.8.3. Fields ที่ต้องกรอกเมื่อสร้าง Circulation
## 3.8.5. การติดตามงาน:
| Field | Required | หมายเหตุ |
|---|---|---|
| Correspondence | ✅ | UUID — เอกสารที่ต้องการเวียน |
| Organization | ✅ | UUID — องค์กรเจ้าของใบเวียน (auto จาก current user org) |
| Subject (`circulation_subject`) | ✅ | VARCHAR(500) |
| Assignees | ✅ | UUID[] — ผู้รับมอบหมาย (จัดการผ่าน Workflow context) |
| Deadline | ❌ | สำหรับผู้รับผิดชอบประเภท Main และ Action |
| Attachments | ❌ | ไฟล์แนบเพิ่มเติม — ผ่าน ClamAV scan |
- สามารถกำหนดวันแล้วเสร็จ (Deadline) สำหรับผู้รับผิดชอบประเภท Main และ Action ได้
- มีระบบแจ้งเตือนเมื่อมี Circulation ใหม่ และแจ้งเตือนล่วงหน้าก่อนถึงวันแล้วเสร็จ
- สามารถปิด Circulation ได้เมื่อดำเนินการตอบกลับไปยังองค์กรผู้ส่ง (Originator) แล้ว หรือ รับทราบแล้ว (For Information)
### ประเภทผู้รับมอบหมาย (Assignee Types)
| ประเภท | ความหมาย | Deadline |
|---|---|---|
| **Main** | ผู้รับผิดชอบหลัก (มีได้หลายคน) | ✅ บังคับ |
| **Action** | ผู้ร่วมปฏิบัติงาน (มีได้หลายคน) | ✅ บังคับ |
| **Information** | ผู้ที่ต้องรับทราบ (มีได้หลายคน) | ❌ |
---
## 3.8.4. Status Codes (circulation_status_codes)
| status_code | ความหมาย |
|---|---|
| `OPEN` | เปิดใบเวียนแล้ว — รอดำเนินการ |
| `IN_REVIEW` | กำลังพิจารณา |
| `COMPLETED` | ดำเนินการเสร็จสมบูรณ์ |
| `CANCELLED` | ยกเลิก / ถอนกลับ |
---
## 3.8.5. การสร้างและสิทธิ์ (RBAC)
| การกระทำ | Role ที่อนุญาต | Scope |
|---|---|---|
| สร้าง Circulation | Document Control, Org Admin, Superadmin | ภายในองค์กรตัวเอง |
| แก้ไข / Re-assign | Document Control, Org Admin | ภายในองค์กรตัวเอง |
| Force Close | Document Control, Org Admin | พร้อมระบุเหตุผล (EC-CIRC-002) |
| ปิด Circulation (ปกติ) | ผู้ที่ถูก Assign (Main/Action) | เมื่อดำเนินการเสร็จ |
| ดู Circulation | เฉพาะคนในองค์กรเดียวกัน | องค์กรอื่นมองไม่เห็น |
---
## 3.8.6. Workflow และ Notifications
- Circulation ใช้ Unified Workflow Engine (`entity_type = 'circulation'`) — ดู `01-03-06-unified-workflow.md`
- **แจ้งเตือน:** เมื่อถูก Assign ใหม่, เมื่อใกล้ถึง Deadline, เมื่อ Overdue → Email / LINE Notify / In-App (BullMQ)
- **Deadline Rule:** หมดเขตเมื่อ `deadline_date 23:59:59` — Overdue Badge ขึ้นเมื่อ `NOW() > deadline_date + 1 day` (EC-CIRC-003)
---
## 3.8.7. Business Rules และ Edge Cases
| รหัส | กฎ | Severity |
|---|---|---|
| **EC-CORR-001** | Cancel Correspondence ที่มี Circulation เปิดอยู่ → Force Close Circulation ทั้งหมด + Audit Log | 🔴 Critical |
| **EC-CIRC-001** | Assignee ถูก Deactivate ก่อน Respond → Document Control สามารถ Re-assign ได้ | 🟠 High |
| **EC-CIRC-002** | Multi-Assignee — บางคนยังไม่ Respond → Document Control Force Close ได้ พร้อมระบุเหตุผล | 🟡 Medium |
| **EC-CIRC-003** | Deadline = Today → หมดเขต 23:59:59, Reminder 08:00, Overdue Badge วันถัดไป | 🟡 Medium |
ดูรายละเอียดครบที่ `01-06-edge-cases-and-rules.md` หมวด "Module 8: Circulation Edge Cases"
@@ -1,21 +1,116 @@
# 3.9 Logs Management (ประวัติการแก้ไข)
# 3.9 Logs Management (ประวัติการแก้ไข / Audit Log)
---
title: 'Functional Requirements: Logs Management'
version: 1.8.0
status: first-draft
title: 'Functional Requirements: Audit Log Management'
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-06-edge-cases-and-rules.md
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md
- specs/06-Decision-Records/ADR-010-logging-monitoring.md
---
## 3.9.1. วัตถุประสงค์:
## 3.9.1. วัตถุประสงค์
- เพื่อ บันทึกการกระทำ CRUD ของเอกสารทั้งหมด รวมถึงการ เข้าใช้งาน ของ users
- admin สามารถดูประวัติการแก้ไขของเอกสารทั้งหมด พร้อม จัดทำรายงายตามข้อกำหนดที่ ต้องการได้
Audit Log บันทึก **ทุก action สำคัญ** ในระบบ — ทั้ง CRUD เอกสาร, การ Login/Logout, เหตุการณ์ Security — เพื่อ Traceability, Compliance และการ Debug ในระบบ Production
---
## 3.9.2. โครงสร้างข้อมูล (Database Table)
ใช้ตารางเดียว `audit_logs` ออกแบบสำหรับ **High-Volume Append-Only Write**:
| Column | Type | หมายเหตุ |
|---|---|---|
| `audit_id` | BIGINT AUTO_INCREMENT | Primary Key (ร่วมกับ `created_at` เพื่อ Partition) |
| `request_id` | VARCHAR(100) | Trace ID เชื่อมกับ Application Log (Distributed Tracing) |
| `user_id` | INT | ผู้กระทำ (ไม่มี FK — ป้องกัน Partition constraint) |
| `action` | VARCHAR(100) | รหัส action เช่น `rfa.create`, `login.success` |
| `severity` | ENUM | `INFO` / `WARN` / `ERROR` / `CRITICAL` |
| `entity_type` | VARCHAR(50) | Module/ตาราง เช่น `rfa`, `correspondence` |
| `entity_id` | VARCHAR(50) | Primary ID ของ record ที่ได้รับผลกระทบ |
| `details_json` | JSON | ข้อมูล Context เพิ่มเติม |
| `ip_address` | VARCHAR(45) | IP Address ของผู้กระทำ |
| `user_agent` | VARCHAR(255) | Browser/Client ของผู้กระทำ |
| `created_at` | DATETIME | เวลาที่กระทำ |
**Primary Key:** `(audit_id, created_at)` — รวม `created_at` เพื่อรองรับ **Partition Table**
**ไม่มี FK** — ใช้ INDEX แทน เพื่อให้ Partition ทำงานได้ (MariaDB constraint)
---
## 3.9.3. Action Format
รูปแบบ: `<module>.<action>` — เช่น:
| action | ความหมาย |
|---|---|
| `login.success` / `login.failed` | เข้าสู่ระบบ |
| `rfa.create` / `rfa.update` / `rfa.delete` | CRUD RFA |
| `correspondence.create` / `correspondence.submit` | สร้าง / Submit Correspondence |
| `circulation.create` / `circulation.close` / `circulation.force_close` | Circulation |
| `drawing.upload` / `drawing.delete` | อัปโหลด / ลบ Drawing |
| `file.virus_detected` | ClamAV พบ Virus |
| `file.mime_mismatch` | MIME Type ไม่ตรง |
| `user.deactivate` / `user.reactivate` | เปลี่ยนสถานะ User |
---
## 3.9.4. Severity
| severity | ใช้เมื่อ |
|---|---|
| `INFO` | ทุก CRUD ปกติ, Login สำเร็จ |
| `WARN` | Login ล้มเหลว, Re-assign Circulation |
| `ERROR` | ระบบ Error, Failed Transaction |
| `CRITICAL` | File Virus Detected, Force Close Circulation, Security Event |
---
## 3.9.5. Partitioning (Performance)
`audit_logs` ใช้ **RANGE Partition by YEAR(created_at)**:
```
p_old → ก่อน 2024
p2024 → 2024
p2025 → 2025
...
p2030 → 2030
p_future → หลัง 2030
```
- Query เฉพาะ Partition ที่เกี่ยวข้อง → ลด I/O อย่างมีนัยสำคัญ
- Drop Partition เพื่อ Archive ข้อมูลเก่าได้โดยไม่กระทบ Production
---
## 3.9.6. RBAC
| การกระทำ | Role ที่อนุญาต |
|---|---|
| ดู Audit Log ทั้งหมด | Superadmin, Org Admin (เฉพาะ org ตัวเอง) |
| Export / Report | Superadmin |
| ลบ Audit Log | **ห้ามลบ** — Append-Only เสมอ |
---
## 3.9.7. กรณีที่บันทึก Audit Log บังคับ
| กรณี | severity | ระบุใน Edge Case |
|---|---|---|
| Cancel Correspondence ที่มี Circulation เปิด | `CRITICAL` | EC-CORR-001 |
| Force Close Circulation + reason | `CRITICAL` | EC-CIRC-001, EC-CIRC-002 |
| Re-assign Circulation (Assignee deactivated) | `WARN` | EC-CIRC-001 |
| File Virus Detected (ClamAV) | `CRITICAL` | EC-FILE-001 |
| File MIME Type Mismatch | `WARN` | EC-FILE-002 |
| ทุก Login / Logout | `INFO` / `WARN` | — |
| ทุก CRUD บน Document ทุกประเภท | `INFO` | — |
@@ -1,97 +1,107 @@
# 3.12 JSON Details Management (การจัดการ JSON Details)
# 3.10 JSON Details Management (การจัดการ JSON Details)
---
title: 'Functional Requirements: JSON Details Management'
version: 1.8.0
status: first-draft
version: 1.8.1
status: updated
owner: Nattanin Peancharoen
last_updated: 2026-02-23
last_updated: 2026-03-24
related:
- specs/01-requirements/01-01-objectives.md
- specs/02-architecture/README.md
- specs/01-requirements/01-03-modules/01-03-00-index.md
- specs/01-requirements/01-03-modules/01-03-02-correspondence.md
- specs/01-requirements/01-03-modules/01-03-03-rfa.md
- specs/01-requirements/01-03-modules/01-03-06-unified-workflow.md
- specs/03-Data-and-Storage/03-01-data-dictionary.md
- specs/06-Decision-Records/ADR-009-db-strategy.md
---
## 3.12.1 วัตถุประสงค์
## 3.10.1. วัตถุประสงค์
- จัดเก็บข้อมูลแบบไดนามิกที่เฉพาะเจาะจงกับแต่ละประเภทของเอกสาร
- รองรับการขยายตัวของระบบโดยไม่ต้องเปลี่ยนแปลง database schema
- จัดการ metadata และข้อมูลประกอบสำหรับ correspondence, routing, และ workflows
ระบบใช้ `JSON` column สำหรับข้อมูลที่มีโครงสร้างแตกต่างกันตามประเภทเอกสาร โดยไม่ต้องเพิ่ม column ใหม่ใน Schema รองรับการขยายตัวโดยไม่กระทบ ADR-009 (No-migration policy)
## 3.12.2 โครงสร้าง JSON Schema
---
- ระบบต้องมี predefined JSON schemas สำหรับประเภทเอกสารต่างๆ:
- 3.12.2.1 Correspondence Types
- GENERIC: ข้อมูลพื้นฐานสำหรับเอกสารทั่วไป
- RFI: รายละเอียดคำถามและข้อมูลทางเทคนิค
- RFA: ข้อมูลการขออนุมัติแบบและวัสดุ
- TRANSMITTAL: รายการเอกสารที่ส่งต่อ
- LETTER: ข้อมูลจดหมายทางการ
- EMAIL: ข้อมูลอีเมล
- 3.12.2.2 Rworkflow Types
- workflow_definitions: กฎและเงื่อนไขการส่งต่อ
- workflow_histories: สถานะและประวัติการส่งต่อ
- workflow_instances: การดำเนินการในแต่ละขั้นตอน
- 3.12.2.3 Audit Types
- AUDIT_LOG: ข้อมูลการตรวจสอบ
- SECURITY_SCAN: ผลการตรวจสอบความปลอดภัย
## 3.10.2. JSON Columns ในระบบ (ครบทุกตาราง)
## 3.12.3 Virtual Columns (ปรับปรุง)
| ตาราง | Column | วัตถุประสงค์ |
|---|---|---|
| `correspondence_revisions` | `details` | ข้อมูลเฉพาะตามประเภทเอกสาร (Letter, RFI ฯลฯ) |
| `rfa_revisions` | `details` | ข้อมูลเฉพาะ RFA (เช่น drawingCount) |
| `workflow_definitions` | `dsl` | นิยาม Workflow ต้นฉบับ (JSON DSL) |
| `workflow_definitions` | `compiled` | Execution Tree ที่ Compile แล้ว |
| `workflow_instances` | `context` | ตัวแปร Context สำหรับตัดสินใจ Transition |
| `workflow_histories` | `metadata` | Snapshot ข้อมูล ณ ขณะ Transition |
| `audit_logs` | `details_json` | ข้อมูล Context เพิ่มเติมของ Event |
| `document_numbers` | `counter_key` | Counter key (8 fields) สำหรับ Document Numbering |
| `document_numbers` | `metadata` | Additional context ของการออกเลข |
| `document_number_errors` | `context_data` | Context ของ request ที่เกิด error |
| `json_schemas` | `schema_definition` | JSON Schema (AJV Standard) |
| `json_schemas` | `ui_schema` | UI Schema สำหรับ Frontend render |
| `json_schemas` | `virtual_columns` | Config สำหรับสร้าง Virtual Columns |
| `json_schemas` | `migration_script` | Script แปลงข้อมูลระหว่าง versions |
- สำหรับ Field ใน JSON ที่ต้องใช้ในการค้นหา (Search) หรือจัดเรียง (Sort) บ่อยๆ ต้องสร้าง Generated Column (Virtual Column) ใน Database และทำ Index ไว้ เพื่อประสิทธิภาพสูงสุด
- Schema Consistency: Field ที่ถูกกำหนดเป็น Virtual Column ห้าม เปลี่ยนแปลง Key Name หรือ Data Type ใน JSON Schema Version ถัดไป หากจำเป็นต้องเปลี่ยน ต้องมีแผนการ Re-index หรือ Migration ข้อมูลเดิมที่ชัดเจน
---
## 3.12.4 Validation Rules
## 3.10.3. JSON Schema Registry (json_schemas)
- ต้องมี JSON schema validation สำหรับแต่ละประเภท
- ต้องรองรับ versioning ของ schema
- ต้องมี default values สำหรับ field ที่ไม่บังคับ
- ต้องตรวจสอบ data types และ format ให้ถูกต้อง
ระบบมีตาราง `json_schemas` เป็น **Centralized Registry** สำหรับ validate และ manage โครงสร้าง JSON:
## 3.12.5 Performance Requirements
| Field | หมายเหตุ |
|---|---|
| `schema_code` | รหัส Schema เช่น `RFA_DWG`, `CORRESPONDENCE_LETTER` |
| `version` | Version ของ Schema (UNIQUE ร่วมกับ `schema_code`) |
| `table_name` | ตารางเป้าหมาย เช่น `rfa_revisions` |
| `schema_definition` | โครงสร้าง AJV JSON Schema สำหรับ validation |
| `ui_schema` | โครงสร้าง UI Schema สำหรับ Frontend render dynamic form |
| `virtual_columns` | Config สำหรับสร้าง Generated Columns |
| `migration_script` | Script แปลงข้อมูลจาก version ก่อนหน้า |
- JSON field ต้องมีขนาดไม่เกิน 50KB
- ต้องรองรับ indexing สำหรับ field ที่ใช้ค้นหาบ่อย
- ต้องมี compression สำหรับ JSON ขนาดใหญ่
---
## 3.12.6 Security Requirements
## 3.10.4. Virtual Columns (Generated Columns)
- ต้อง sanitize JSON input เพื่อป้องกัน injection attacks
- ต้อง validate JSON structure ก่อนบันทึก
- ต้อง encrypt sensitive data ใน JSON fields
JSON field ที่ต้องใช้ใน Query / Search สร้างเป็น **Generated Virtual Column** + Index:
## 3.12.7 JSON Schema Migration Strategy (เพิ่มเติม)
| ตาราง | Virtual Column | JSON Path | ใช้สำหรับ |
|---|---|---|---|
| `correspondence_revisions` | `v_ref_project_id` | `$.projectId` | Filter by Project |
| `correspondence_revisions` | `v_doc_subtype` | `$.subType` | Filter by Sub-type |
| `rfa_revisions` | `v_ref_drawing_count` | `$.drawingCount` | Count / Sort |
- สำหรับ Schema Breaking Changes:
- Phase 1 - Add New Column
ALTER TABLE correspondence_revisions
ADD COLUMN ref_project_id_v2 INT GENERATED ALWAYS AS
(JSON_UNQUOTE(JSON_EXTRACT(details, '$.newProjectIdPath'))) VIRTUAL;
**กฎสำคัญ:** Field ที่เป็น Virtual Column **ห้ามเปลี่ยน JSON key หรือ data type** ใน version ถัดไป — ต้องมีแผน Re-index / Migration ก่อน
- Phase 2 - Backfill Old Records
- ใช้ background job แปลง JSON format เก่าเป็นใหม่
- Update `details` JSON ทีละ batch (1000 records)
- Phase 3 - Switch Application Code
- Deploy code ที่ใช้ path ใหม่
- Phase 4 - Remove Old Column
- หลังจาก verify แล้วว่าไม่มี error
- Drop old virtual column
---
- สำหรับ Non-Breaking Changes
- เพิ่ม optional field ใน schema
- Old records ที่ไม่มี field = ใช้ default value
## 3.10.5. Validation Rules
## 3.13. ข้อกำหนดพิเศษ
- Backend validate ด้วย `json_schemas.schema_definition` (AJV Standard) ก่อน save ทุกครั้ง
- แต่ละ record มี `schema_version` — ใช้เลือก schema ที่ถูกต้องสำหรับ validate
- Field ไม่บังคับ → ใช้ `default` value ตามที่กำหนดใน schema
- Sanitize JSON input เพื่อป้องกัน injection ก่อน validate
- ผู้ใช้งานที่มีสิทธิ์ระดับสูง (Global) หรือผู้ได้รับอนุญาตเป็นกรณีพิเศษ
- สามารถเลือก สร้างในนามองค์กร (Create on behalf of) ได้ เพื่อให้สามารถออกเลขที่เอกสาร (Running Number) ขององค์กรอื่นได้โดยไม่ต้องล็อกอินใหม่
- สามารถทำงานแทนผู้ใช้งานอื่นได้ Routing & Workflow ของ Correspondence, RFA, Circulation Sheet
---
## 3.14. การจัดการข้อมูลหลักขั้นสูง (Master Data Management)
## 3.10.6. JSON Schema Migration Strategy
- 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: ระบบต้องรองรับการตั้งค่า Format Template ของแต่ละ Project/Type ได้โดยไม่ต้องแก้โค้ด
### Breaking Changes (เปลี่ยน key / type)
1. **Phase 1 — Add New Virtual Column** ด้วย path ใหม่
2. **Phase 2 — Backfill Old Records** ด้วย background job (batch 1,000 records)
3. **Phase 3 — Deploy Application Code** ที่ใช้ path ใหม่
4. **Phase 4 — Drop Old Column** หลัง verify ไม่มี error
### Non-Breaking Changes (เพิ่ม optional field)
- เพิ่ม field ใน schema definition — old records ที่ไม่มี field ใช้ `default` value อัตโนมัติ
- ไม่ต้อง backfill
---
> **หมายเหตุ:** เนื้อหาเดิม §3.13 (Impersonation) และ §3.14 (Master Data Management) ได้ถูกย้ายไปยัง spec ที่เกี่ยวข้องแล้ว:
> - Impersonation → `01-02-01-rbac-matrix.md`
> - Disciplines Management → `01-03-01-project-management.md` (§3.1.6)
> - Numbering Format → Document Numbering spec
@@ -3,8 +3,8 @@
---
**Project:** LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)
**Version:** 1.8.0
**Last Updated:** 2025-12-02
**Version:** 1.8.4
**Last Updated:** 2026-03-24
**Owner:** Operations Team
**Status:** Active
@@ -12,15 +12,15 @@
## 📋 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.
This guide provides step-by-step instructions for deploying the LCBP3-DMS system on QNAP Container Station using Docker Compose.
### 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
- **Deployment Method:** Direct deploy with `--force-recreate` (replaces previous blue-green approach)
- **Automation:** Gitea Actions → `appleboy/ssh-action``scripts/deploy.sh`
- **Rollback:** Re-trigger previous commit via Gitea Actions
---
@@ -67,17 +67,14 @@ Create the following directory structure on QNAP:
# SSH into QNAP
ssh admin@qnap-ip
# Create base directory
mkdir -p /volume1/lcbp3
# Create base directories
mkdir -p /share/np-dms/app/logs
mkdir -p /share/np-dms/app/uploads
# 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
# Clone source repository (first time only)
mkdir -p /share/np-dms/app/source
cd /share/np-dms/app/source
git clone https://git.np-dms.work/np-dms/lcbp3.git
# Create persistent volumes
mkdir -p /volume1/lcbp3/volumes/mariadb-data
@@ -92,43 +89,23 @@ chmod -R 755 /volume1/lcbp3
chown -R admin:administrators /volume1/lcbp3
```
**Final Structure:**
**Directory Structure:**
```
/volume1/lcbp3/
├── blue/ # Blue environment
── docker-compose.yml
├── .env.production
└── nginx.conf
/share/np-dms/app/
├── source/
── lcbp3/ # Git repository (auto-synced by CI)
├── backend/
├── frontend/
│ ├── scripts/
│ │ ├── deploy.sh # Deployment script v2.0
│ │ └── rollback.sh
│ └── specs/04-Infrastructure-OPS/04-00-docker-compose/
│ └── docker-compose-app.yml # Compose file used for deployment
├── 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"
├── .env # Single environment config file
├── logs/ # Deployment logs
└── uploads/ # Persistent file uploads
```
### 2. SSL Certificate Setup
@@ -160,10 +137,10 @@ cp /etc/letsencrypt/live/lcbp3-dms.example.com/privkey.pem \
### 1. Environment Variables (.env.production)
Create `.env.production` in both `blue/` and `green/` directories:
Create `.env` at `/share/np-dms/app/.env`:
```bash
# File: /volume1/lcbp3/blue/.env.production
# File: /share/np-dms/app/.env
# DO NOT commit this file to Git!
# Application