690417:1538 Refactor Work flow ADR-021

This commit is contained in:
2026-04-17 15:38:20 +07:00
parent 6d45bdaeb5
commit 3a5fc8d4af
23 changed files with 892 additions and 135 deletions
@@ -1,9 +1,9 @@
---
title: 'Data & Storage: Data Dictionary and Data Model Architecture'
version: 1.8.0
version: 1.8.7
status: released
owner: Nattanin Peancharoen
last_updated: 2026-02-28
last_updated: 2026-04-14
related:
- specs/01-requirements/02-architecture.md
- specs/01-requirements/03-functional-requirements.md
@@ -1714,24 +1714,33 @@ erDiagram
**Purpose**: เก็บสถานะของ Workflow ที่กำลังรันอยู่จริง (Runtime)
| Column Name | Data Type | Constraints | Description |
| :------------ | :---------- | :--------------- | :--------------------------------------------- |
| id | CHAR(36) | PK, UUID | Unique Instance ID |
| definition_id | CHAR(36) | FK, NOT NULL | อ้างอิง Definition ที่ใช้ |
| entity_type | VARCHAR(50) | NOT NULL | ประเภทเอกสาร (rfa_revision, correspondence...) |
| entity_id | VARCHAR(50) | NOT NULL | ID ของเอกสาร |
| current_state | VARCHAR(50) | NOT NULL | สถานะปัจจุบัน |
| status | ENUM | DEFAULT 'ACTIVE' | ACTIVE, COMPLETED, CANCELLED, TERMINATED |
| context | JSON | NULL | ตัวแปร Context สำหรับตัดสินใจ |
| created_at | TIMESTAMP | DEFAULT NOW | เวลาที่สร้าง |
| updated_at | TIMESTAMP | ON UPDATE | เวลาที่อัปเดตล่าสุด |
| Column Name | Data Type | Constraints | Description |
| :------------ | :---------- | :------------------------- | :---------------------------------------------------------------------------------------------- |
| id | CHAR(36) | PK, UUID | Unique Instance ID |
| definition_id | CHAR(36) | FK, NOT NULL | อ้างอิง Definition ที่ใช้ |
| **contract_id** | **INT** | **NULL, FK** | **[delta-07 / ADR-021 C3]** Contract ที่ Workflow นี้สังกัด (NULL = org-scoped เช่น Circulation) |
| entity_type | VARCHAR(50) | NOT NULL | ประเภทเอกสาร (rfa, correspondence, transmittal, circulation) |
| entity_id | VARCHAR(50) | NOT NULL | ID ของเอกสาร |
| current_state | VARCHAR(50) | NOT NULL | สถานะปัจจุบัน |
| status | ENUM | DEFAULT 'ACTIVE' | ACTIVE, COMPLETED, CANCELLED, TERMINATED |
| context | JSON | NULL | ตัวแปร Context สำหรับตัดสินใจ (รวม contractId, projectId, initiatorId เป็นต้น) |
| created_at | TIMESTAMP | DEFAULT NOW | เวลาที่สร้าง |
| updated_at | TIMESTAMP | ON UPDATE | เวลาที่อัปเดตล่าสุด |
**Business Rules**:
- `contract_id` = NOT NULL → contract-scoped workflow (RFA, Correspondence, Transmittal) — Guard Level 2.5 ตรวจ membership
- `contract_id` = NULL → org-scoped workflow (Circulation) — Guard Level 2 (org match only)
- `context.contractId` mirrors `contract_id` column — redundant by design (ฟิลเตอร์ได้ทั้งสองทาง)
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (definition_id) REFERENCES workflow_definitions(id) ON DELETE CASCADE
- **FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE SET NULL** [delta-07]
- INDEX (entity_type, entity_id)
- INDEX (current_state)
- **INDEX (contract_id, entity_type, status)** — `idx_wf_inst_contract` [delta-07]
---
@@ -1978,8 +1987,9 @@ PARTITION BY RANGE (YEAR(created_at)) (
| audit_logs | (module, action) | Action type analysis |
| notifications | (user_id, is_read) | Unread notifications query |
| document_number_counters | (project_id, correspondence_type_id, reset_scope) | Running number generation |
| workflow_instances | (entity_type, entity_id) | Workflow lookup by document ID |
| workflow_instances | (current_state) | Monitor active workflows |
| workflow_instances | (entity_type, entity_id) | Workflow lookup by document ID |
| workflow_instances | (current_state) | Monitor active workflows |
| workflow_instances | (contract_id, entity_type, status) | **[delta-07]** Guard contract-membership + dashboard filter |
### 13.2 Unique Constraints
@@ -0,0 +1,87 @@
-- ==========================================================
-- Delta 06: Add CIRCULATION_FLOW_V1 Workflow Definition
-- ==========================================================
-- Purpose : สร้าง Workflow Definition สำหรับใบเวียนภายใน (Circulation)
-- Required : ก่อน delta นี้ ตาราง workflow_definitions ต้องมีอยู่แล้ว (ADR-001)
-- Renamed : CIRCULATION_INTERNAL_V1 → CIRCULATION_FLOW_V1 (ตาม naming convention)
-- States :
-- DRAFT (initial) → START → ROUTING
-- ROUTING → COMPLETE → COMPLETED (terminal)
-- ROUTING → FORCE_CLOSE → CANCELLED (terminal)
-- ==========================================================
INSERT INTO `workflow_definitions` (
`id`,
`workflow_code`,
`version`,
`description`,
`dsl`,
`compiled`,
`is_active`,
`created_at`,
`updated_at`
)
VALUES (
UUID(),
'CIRCULATION_FLOW_V1',
1,
'Circulation Workflow — DRAFT → ROUTING → COMPLETED | CANCELLED',
JSON_OBJECT(
'workflow', 'CIRCULATION_FLOW_V1',
'version', 1,
'states', JSON_ARRAY(
JSON_OBJECT(
'name', 'DRAFT',
'initial', TRUE,
'on', JSON_OBJECT(
'START', JSON_OBJECT('to', 'ROUTING')
)
),
JSON_OBJECT(
'name', 'ROUTING',
'on', JSON_OBJECT(
'COMPLETE', JSON_OBJECT('to', 'COMPLETED'),
'FORCE_CLOSE', JSON_OBJECT('to', 'CANCELLED')
)
),
JSON_OBJECT('name', 'COMPLETED', 'terminal', TRUE),
JSON_OBJECT('name', 'CANCELLED', 'terminal', TRUE)
)
),
JSON_OBJECT(
'initialState', 'DRAFT',
'states', JSON_OBJECT(
'DRAFT', JSON_OBJECT(
'initial', TRUE,
'terminal', FALSE,
'transitions', JSON_OBJECT(
'START', JSON_OBJECT('to', 'ROUTING', 'events', JSON_ARRAY())
)
),
'ROUTING', JSON_OBJECT(
'initial', FALSE,
'terminal', FALSE,
'transitions', JSON_OBJECT(
'COMPLETE', JSON_OBJECT('to', 'COMPLETED', 'events', JSON_ARRAY()),
'FORCE_CLOSE', JSON_OBJECT('to', 'CANCELLED', 'events', JSON_ARRAY())
)
),
'COMPLETED', JSON_OBJECT(
'initial', FALSE,
'terminal', TRUE,
'transitions', JSON_OBJECT()
),
'CANCELLED', JSON_OBJECT(
'initial', FALSE,
'terminal', TRUE,
'transitions', JSON_OBJECT()
)
)
),
TRUE,
NOW(),
NOW()
);
-- Verify
-- SELECT workflow_code, version, is_active FROM workflow_definitions WHERE workflow_code = 'CIRCULATION_FLOW_V1';
@@ -0,0 +1,22 @@
-- ==========================================================
-- Delta 07: Add contract_id to workflow_instances (C3 Contract Scoping)
-- ==========================================================
-- Purpose : เพิ่ม contract_id FK ใน workflow_instances เพื่อให้ Workflow Engine
-- แยก scope ตาม Contract ได้ (C3 ตาม analysis ADR-021)
-- Why : RFA / Correspondence / Transmittal → contract-scoped (contractId ถูกตั้ง)
-- Circulation → organization-scoped (contractId = NULL, ใช้ Level 2 org check)
-- Guard Level 2.5 ตรวจ contract_organizations membership เฉพาะ contractId ≠ NULL
-- ADR : ADR-009 (no migrations — direct SQL only)
-- ==========================================================
ALTER TABLE workflow_instances
ADD COLUMN contract_id INT NULL COMMENT 'Contract ที่ Workflow นี้เป็นส่วนหนึ่ง (NULL = global/legacy)'
AFTER definition_id,
ADD CONSTRAINT fk_wf_inst_contract FOREIGN KEY (contract_id) REFERENCES contracts (id) ON DELETE
SET NULL;
-- Index สำหรับ Guard lookup: "Instances ทั้งหมดในสัญญา X"
CREATE INDEX idx_wf_inst_contract ON workflow_instances (contract_id, entity_type, STATUS);
-- Verify
-- DESCRIBE workflow_instances;
-- SHOW INDEX FROM workflow_instances WHERE Key_name = 'idx_wf_inst_contract';
@@ -1369,6 +1369,8 @@ CREATE INDEX idx_workflow_active ON workflow_definitions (workflow_code, is_acti
CREATE TABLE workflow_instances (
id CHAR(36) NOT NULL PRIMARY KEY COMMENT 'UUID ของ Instance',
definition_id CHAR(36) NOT NULL COMMENT 'อ้างอิง Definition ที่ใช้',
contract_id INT NULL COMMENT 'Contract ที่ Workflow นี้เป็นส่วนหนึ่ง (NULL = org-scoped หรือ legacy)',
-- [delta-07]
entity_type VARCHAR(50) NOT NULL COMMENT 'ประเภทเอกสาร (rfa_revision, correspondence_revision, circulation)',
entity_id VARCHAR(50) NOT NULL COMMENT 'ID ของเอกสาร (String/Int)',
current_state VARCHAR(50) NOT NULL COMMENT 'สถานะปัจจุบัน',
@@ -1381,11 +1383,15 @@ CREATE TABLE workflow_instances (
context JSON NULL COMMENT 'ตัวแปร Context สำหรับตัดสินใจ',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_wf_inst_def FOREIGN KEY (definition_id) REFERENCES workflow_definitions (id) ON DELETE CASCADE
CONSTRAINT fk_wf_inst_def FOREIGN KEY (definition_id) REFERENCES workflow_definitions (id) ON DELETE CASCADE,
CONSTRAINT fk_wf_inst_contract FOREIGN KEY (contract_id) REFERENCES contracts (id) ON DELETE
SET NULL -- [delta-07]
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตารางเก็บสถานะการเดินเรื่องของเอกสาร';
CREATE INDEX idx_wf_inst_entity ON workflow_instances (entity_type, entity_id);
CREATE INDEX idx_wf_inst_contract ON workflow_instances (contract_id, entity_type, STATUS);
CREATE INDEX idx_wf_inst_state ON workflow_instances (current_state);
-- 3. ตารางเก็บประวัติ (Audit Log / History)