Files
lcbp3/specs/06-Decision-Records/ADR-001-unified-workflow-engine.md
T
admin c95e0f537e
CI / CD Pipeline / build (push) Successful in 4m34s
CI / CD Pipeline / deploy (push) Successful in 7m33s
690404:1139 Modify ADR
2026-04-04 11:39:56 +07:00

447 lines
18 KiB
Markdown

# ADR-001: Unified Workflow Engine
**Status:** Accepted
**Date:** 2026-02-24
**Decision Makers:** Development Team, System Architect
**Related Documents:**
- [Software Architecture](../02-Architecture/02-02-software-architecture.md)
- [Unified Workflow Requirements](../01-Requirements/01-03-modules/01-03-06-unified-workflow.md)
---
## 🎯 Gap Analysis & Purpose
### ปิด Gap จากเอกสาร:
- **Unified Workflow Requirements** - Section 2.1: "LCBP3-DMS ต้องรองรับเอกสารหลายประเภทพร้อม Workflow ที่แตกต่างกัน"
- เหตุผล: ระบบเดิมไม่มีกลไกส่วนกลางสำหรับจัดการ Workflow ทำให้เกิด Code Duplication
- **Software Architecture** - Section 3.2: "ระบบต้องมีความยืดหยุ่นในการเพิ่ม Document Type ใหม่"
- เหตุผล: การ Hard-code Workflow ทำให้การเพิ่มประเภทเอกสารใหม่ทำได้ยาก
### แก้ไขความขัดแย้ง:
- **Correspondence Requirements** vs **RFA Requirements**: ทั้งสอง Module ต้องการ State Management แต่ใช้วิธีต่างกัน
- การตัดสินใจนี้ช่วยแก้ไขโดย: สร้าง Unified Engine ที่รองรับทุก Document Type
---
## Context and Problem Statement
LCBP3-DMS ต้องจัดการเอกสารหลายประเภท (Correspondences, RFAs, Circulations) โดยแต่ละประเภทมี Workflow การเดินเอกสารที่แตกต่างกัน:
- **Correspondence Routing:** ส่งเอกสารระหว่างองค์กร มีการ Forward, Reply
- **RFA Approval Workflow:** ส่งขออนุมัติ มีขั้นตอน Review → Approve → Respond
- **Circulation Workflow:** เวียนเอกสารภายในองค์กร มีการ Assign ผู้รับเพื่อพิจารณา
### Key Problems
1. **Code Duplication:** หากสร้างตาราง Routing แยกกันสำหรับแต่ละประเภทเอกสาร จะมี Logic ซ้ำซ้อน
2. **Complexity:** การ Maintain หลาย Workflow Systems ทำให้ซับซ้อน
3. **Inconsistency:** State Management และ History Tracking อาจไม่สอดคล้องกัน
4. **Scalability:** เมื่อเพิ่มประเภทเอกสารใหม่ ต้องสร้าง Workflow System ใหม่
5. **Versioning:** การแก้ไข Workflow กระทบเอกสารที่กำลังดำเนินการอยู่
---
## Decision Drivers
- **DRY Principle:** Don't Repeat Yourself - ลดการเขียน Code ซ้ำ
- **Maintainability:** ง่ายต่อการ Maintain และ Debug
- **Flexibility:** รองรับการเปลี่ยนแปลง Workflow ในอนาคต
- **Traceability:** ติดตามประวัติการเปลี่ยนสถานะได้ชัดเจน
- **Performance:** ประมวลผล Workflow ได้เร็วและมีประสิทธิภาพ
---
## Considered Options
### Option 1: Hard-coded Workflow per Document Type
**แนวทาง:** สร้างตาราง `correspondence_routings`, `rfa_approvals`, `circulation_routings` แยกกัน
**Pros:**
- ✅ เข้าใจง่าย straightforward
- ✅ Query performance ดี (table-specific indexes)
- ✅ Schema ชัดเจนสำหรับแต่ละ type
**Cons:**
- ❌ Code duplication มาก
- ❌ ยากต่อการเพิ่ม Document Type ใหม่
- ❌ Inconsistent state management
- ❌ ไม่มี Workflow versioning mechanism
- ❌ ยากต่อการ reuse common workflows
### Option 2: Generic Workflow Engine with Hard-coded State Machines
**แนวทาง:** สร้าง Workflow Engine แต่ Hard-code State Machine ไว้ใน Code
**Pros:**
- ✅ Centralized workflow logic
- ✅ Reusable workflow components
- ✅ Better maintainability
**Cons:**
- ❌ ต้อง Deploy ใหม่ทุกครั้งที่แก้ Workflow
- ❌ ไม่ยืดหยุ่นสำหรับ Business Users
- ❌ Versioning ยังซับซ้อน
### Option 3: **DSL-Based Unified Workflow Engine** ⭐ (Selected)
**แนวทาง:** สร้าง Workflow Engine ที่ใช้ JSON-based DSL (Domain Specific Language) เพื่อ Define Workflows
**Pros:**
-**Single Source of Truth:** Workflow logic อยู่ใน Database
-**Versioning Support:** เก็บ Workflow Definition versions ได้
-**Runtime Flexibility:** แก้ Workflow ได้โดยไม่ต้อง Deploy
-**Reusability:** Workflow templates สามารถใช้ซ้ำได้
-**Consistency:** State management เป็นมาตรฐานเดียวกัน
-**Audit Trail:** ประวัติครบถ้วนใน `workflow_histories`
-**Scalability:** เพิ่ม Document Type ใหม่ได้ง่าย
**Cons:**
- ❌ Initial development complexity สูง
- ❌ ต้องเขียน DSL Parser และ Validator
- ❌ Performance overhead เล็กน้อย (parse JSON)
- ❌ Learning curve สำหรับทีม
---
## Decision Outcome
**Chosen Option:** Option 3 - DSL-Based Unified Workflow Engine
### Rationale
เลือก Unified Workflow Engine เนื่องจาก:
1. **Long-term Maintainability:** แม้จะมี complexity ในการพัฒนา แต่ในระยะยาวจะลดภาระการ Maintain
2. **Business Flexibility:** Business Users สามารถปรับ Workflow ได้ (ผ่าน Admin UI ในอนาคต)
3. **Consistency:** สถานะและประวัติเป็นมาตรฐานเดียวกันทุก Document Type
4. **Scalability:** เตรียมพร้อมสำหรับ Document Types ใหม่ๆ ในอนาคต
5. **Versioning:** รองรับการแก้ไข Workflow โดยไม่กระทบ In-progress documents
---
## 🔍 Impact Analysis
### Affected Components (ส่วนประกอบที่ได้รับผลกระทบ)
| Component | Level | Impact Description | Required Action |
|-----------|-------|-------------------|-----------------|
| **Backend** | 🔴 High | ต้องสร้าง Workflow Engine Module ใหม่ และ Refactor ทุก Document Service | Implement WorkflowEngineService |
| **Database** | 🔴 High | เพิ่ม Tables: workflow_definitions, workflow_instances, workflow_histories | Create new schema |
| **Frontend** | 🟡 Medium | ต้อง Update UI สำหรับ Workflow Status และ Actions | Update components |
| **API** | 🔴 High | ต้องสร้าง Workflow API endpoints และ Update ทุก Document API | New endpoints + updates |
| **Testing** | 🟡 Medium | ต้องเขียน Tests สำหรับ Workflow Engine และ Integration Tests | New test suites |
### Required Changes (การเปลี่ยนแปลงที่ต้องดำเนินการ)
#### 🔴 Critical Changes (ต้องทำทันที)
- [ ] **Create Workflow Engine Module** - backend/src/modules/workflow-engine/: สร้าง Engine หลัก
- [ ] **Implement Database Schema** - specs/03-Data-and-Storage/: เพิ่ม workflow tables
- [ ] **Refactor Correspondence Service** - backend/src/modules/correspondence/: ใช้ Workflow Engine
- [ ] **Refactor RFA Service** - backend/src/modules/rfa/: ใช้ Workflow Engine
- [ ] **Refactor Circulation Service** - backend/src/modules/circulation/: ใช้ Workflow Engine
#### 🟡 Important Changes (ควรทำภายใน 2 สัปดาห์)
- [ ] **Update Frontend Workflow Components** - frontend/components/workflow/: UI สำหรับ Workflow
- [ ] **Create Workflow API Endpoints** - backend/src/modules/workflow-engine/controller.ts: REST API
- [ ] **Add Workflow DSL Validation** - backend/src/modules/workflow-engine/dsl-validator.ts: JSON Schema validation
- [ ] **Implement Workflow History Tracking** - backend/src/modules/workflow-engine/history.service.ts: Audit trail
#### 🟢 Nice-to-Have (ทำถ้ามีเวลา)
- [ ] **Create Admin UI for Workflow Design** - frontend/app/(admin)/admin/workflow/: Visual workflow builder
- [ ] **Add Workflow Performance Monitoring** - backend/src/modules/workflow-engine/monitoring.service.ts: Metrics
### Cross-Module Dependencies
```mermaid
graph TB
ADR[ADR-001 Workflow Engine] --> Corr[Correspondence Service]
ADR --> RFA[RFA Service]
ADR --> Circ[Circulation Service]
ADR --> DB[(Database Schema)]
ADR --> API[Workflow API]
Corr --> ADR002[ADR-002 Document Numbering]
RFA --> ADR002
Circ --> ADR002
API --> ADR006[ADR-006 Redis Caching]
DB --> ADR009[ADR-009 Migration Strategy]
```
---
## 📋 Version Dependency Matrix
| ADR | Version | Dependency Type | Affected Version(s) | Implementation Status |
|-----|---------|-----------------|---------------------|----------------------|
| **ADR-001** | 1.0 | Core | v1.8.0+ | ✅ Implemented |
| **ADR-002** | 1.0 | Required By | v1.8.0+ | ✅ Implemented |
| **ADR-006** | 1.0 | Uses | v1.8.0+ | ✅ Implemented |
| **ADR-009** | 1.0 | Database Changes | v1.8.0+ | ✅ Implemented |
### Version Compatibility Rules
- **Minimum Version:** v1.8.0 (ADR มีผลบังคับใช้)
- **Breaking Changes:** ไม่มี (Backward compatible API)
- **Deprecation Timeline:** ไม่มี (Core architecture)
---
## Implementation Details
### Database Schema
```sql
-- Workflow Definitions (Templates)
CREATE TABLE workflow_definitions (
id VARCHAR(36) PRIMARY KEY, -- UUID
workflow_code VARCHAR(50) NOT NULL,
version INT NOT NULL DEFAULT 1,
description TEXT NULL,
dsl JSON NOT NULL, -- Raw DSL from user
compiled JSON NOT NULL, -- Validated and optimized for Runtime
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY (workflow_code, version)
);
-- Workflow Instances (Running Workflows)
CREATE TABLE workflow_instances (
id VARCHAR(36) PRIMARY KEY, -- UUID
definition_id VARCHAR(36) NOT NULL,
entity_type VARCHAR(50) NOT NULL, -- e.g. "correspondence", "rfa"
entity_id VARCHAR(50) NOT NULL,
current_state VARCHAR(50) NOT NULL,
status ENUM('ACTIVE', 'COMPLETED', 'CANCELLED', 'TERMINATED') DEFAULT 'ACTIVE',
context JSON NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (definition_id) REFERENCES workflow_definitions(id)
);
-- Workflow History (Audit Trail)
CREATE TABLE workflow_histories (
id VARCHAR(36) PRIMARY KEY, -- UUID
instance_id VARCHAR(36) NOT NULL,
from_state VARCHAR(50) NOT NULL,
to_state VARCHAR(50) NOT NULL,
action VARCHAR(50) NOT NULL,
action_by_user_id INT NULL,
comment TEXT NULL,
metadata JSON NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (instance_id) REFERENCES workflow_instances(id) ON DELETE CASCADE
);
```
### DSL Example
```json
{
"workflow": "CORRESPONDENCE_ROUTING",
"version": 1,
"description": "Standard correspondence routing",
"states": [
{
"name": "DRAFT",
"initial": true,
"on": {
"SUBMIT": {
"to": "SUBMITTED",
"require": {
"role": ["Admin"],
"user": "123"
},
"condition": "context.requiresLegal > 0",
"events": [
{
"type": "notify",
"target": "originator",
"template": "correspondence_submitted"
}
]
}
}
},
{
"name": "SUBMITTED",
"on": {
"RECEIVE": {
"to": "RECEIVED"
},
"RETURN": {
"to": "DRAFT"
}
}
},
{
"name": "RECEIVED",
"on": {
"CLOSE": {
"to": "CLOSED"
}
}
},
{
"name": "CLOSED",
"terminal": true
}
]
}
```
### NestJS Module Structure
```typescript
// workflow-engine.module.ts
@Module({
imports: [TypeOrmModule.forFeature([WorkflowDefinition, WorkflowInstance, WorkflowHistory]), UserModule],
controllers: [WorkflowEngineController],
providers: [WorkflowEngineService, WorkflowDslService, WorkflowEventService],
exports: [WorkflowEngineService],
})
export class WorkflowEngineModule {}
// workflow-engine.service.ts
@Injectable()
export class WorkflowEngineService {
async createInstance(
workflowCode: string,
entityType: string,
entityId: string,
initialContext: Record<string, unknown> = {}
): Promise<WorkflowInstance> {
const definition = await this.workflowDefRepo.findOne({
where: { workflow_code: workflowCode, is_active: true },
order: { version: 'DESC' },
});
// Initial state directly from compiled DSL
const initialState = definition.compiled.initialState;
return this.instanceRepo.save({
definition_id: definition.id,
entityType,
entityId,
currentState: initialState,
status: WorkflowStatus.ACTIVE,
context: initialContext,
});
}
async processTransition(
instanceId: string,
action: string,
userId: number,
comment?: string,
payload: Record<string, unknown> = {}
) {
// Evaluation via WorkflowDslService
const evaluation = this.dslService.evaluate(compiled, instance.currentState, action, context);
// Update state to target State
instance.currentState = evaluation.nextState;
if (compiled.states[evaluation.nextState].terminal) {
instance.status = WorkflowStatus.COMPLETED;
}
// Process background events asynchronously
if (evaluation.events && evaluation.events.length > 0) {
this.eventService.dispatchEvents(instance.id, evaluation.events, context);
}
}
}
```
---
## Consequences
### Positive
1.**Unified State Management:** สถานะทุก Document Type จัดการโดย Engine เดียว
2.**No Code Changes for Workflow Updates:** แก้ Workflow ผ่าน JSON DSL
3.**Complete Audit Trail:** ประวัติครบถ้วนใน `workflow_histories`
4.**Versioning Support:** In-progress documents ใช้ Workflow Version เดิม
5.**Reusable Templates:** สามารถ Clone Workflow Template ได้
6.**Future-proof:** พร้อมสำหรับ Document Types ใหม่
### Negative
1.**Initial Complexity:** ต้องสร้าง DSL Parser, Validator, Executor
2.**Learning Curve:** ทีมต้องเรียนรู้ DSL Structure
3.**Performance:** เพิ่ม overhead เล็กน้อยจากการ parse JSON
4.**Debugging:** ยากกว่า Hard-coded logic เล็กน้อย
5.**Testing:** ต้อง Test ทั้ง Engine และ Workflow Definitions
### Mitigation Strategies
- **Complexity:** สร้าง UI Builder สำหรับ Workflow Design ในอนาคต
- **Learning Curve:** เขียน Documentation และ Examples ที่ชัดเจน
- **Performance:** ใช้ Redis Cache สำหรับ Workflow Definitions
- **Debugging:** สร้าง Workflow Visualization Tool
- **Testing:** เขียน Comprehensive Unit Tests สำหรับ Engine
---
## Compliance
เป็นไปตาม:
- [Backend Guidelines](../05-Engineering-Guidelines/05-02-backend-guidelines.md#workflow-engine-integration) - Unified Workflow Engine
- [Unified Workflow Requirements](../01-Requirements/01-03-modules/01-03-06-unified-workflow.md) - Unified Workflow Specification
---
## Notes
- Workflow DSL จะถูก Validate ด้วย JSON Schema ก่อน Save
- Admin UI สำหรับจัดการ Workflow จะพัฒนาใน Phase 2
- ต้องมี Migration Tool สำหรับ Workflow Definition Changes
- พิจารณาใช้ BPMN 2.0 Notation ในอนาคต (ถ้าต้องการ Visual Workflow Designer)
---
## 🔄 Review Cycle & Maintenance
### Review Schedule
- **Next Review:** 2026-08-24 (6 months from last review)
- **Review Type:** Scheduled (Core Principle Review)
- **Reviewers:** System Architect, Development Team Lead, Product Owner
### Review Checklist
- [ ] ยังคงเป็น Core Principle หรือไม่? (Workflow Engine เป็นหัวใจสำคัญของระบบ)
- [ ] มีการเปลี่ยนแปลง Technology ที่กระทบหรือไม่? (New Workflow Engine alternatives)
- [ ] มี Issue หรือ Bug ที่เกิดจาก ADR นี้หรือไม่? (Performance bottlenecks, State inconsistencies)
- [ ] ต้องการ Update หรือ Deprecate หรือไม่? (DSL evolution, New document types)
### Version History
| Version | Date | Changes | Status |
|---------|------|---------|--------|
| 1.0 | 2026-02-24 | Initial version - DSL-based Unified Workflow Engine | ✅ Active |
---
## Related ADRs
- [ADR-002: Document Numbering Strategy](./ADR-002-document-numbering-strategy.md) - ใช้ Workflow Engine trigger Document Number Generation
- [RBAC Matrix](../01-Requirements/01-02-business-rules/01-02-01-rbac-matrix.md) - Permission Guards ใน Workflow Transitions
---
## References
- [NestJS State Machine Example](https://docs.nestjs.com/techniques/queues)
- [Workflow Patterns](http://www.workflowpatterns.com/)
- [JSON Schema Specification](https://json-schema.org/)