260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
@@ -1,29 +1,32 @@
|
||||
# 3.11 Document Numbering Management (การจัดการเลขที่เอกสาร)
|
||||
|
||||
---
|
||||
|
||||
title: 'Functional Requirements: Document Numbering Management'
|
||||
version: 1.6.2
|
||||
status: draft
|
||||
owner: Nattanin Peancharoen
|
||||
last_updated: 2025-12-17
|
||||
related:
|
||||
- specs/01-requirements/01-01-objectives.md
|
||||
- specs/01-requirements/01-02-architecture.md
|
||||
- specs/01-requirements/01-03-functional-requirements.md
|
||||
- specs/01-requirements/01-03.11-document-numbering.md
|
||||
- specs/03-implementation/03-04-document-numbering.md
|
||||
- specs/04-operations/04-08-document-numbering-operations.md
|
||||
- specs/07-database/07-01-data-dictionary-v1.7.0.md
|
||||
- specs/05-decisions/ADR-002-document-numbering-strategy.md
|
||||
Clean Version v1.6.2 – Scope of Changes:
|
||||
- เลือกใช้ Single Numbering System (Option A)
|
||||
- แก้ Primary Key design ให้ implement ได้จริง
|
||||
- ปรับ Character Rule เป็น UTF‑8 printable
|
||||
- Bind Reset Policy ชัดเจน (Yearly reset, RFA no reset)
|
||||
- เพิ่ม Number State Machine
|
||||
- เพิ่ม Idempotency Key
|
||||
- Drawing ใช้ separate counter namespace
|
||||
- เพิ่ม Formal Token Validation Grammar
|
||||
|
||||
- specs/01-requirements/01-01-objectives.md
|
||||
- specs/01-requirements/01-02-architecture.md
|
||||
- specs/01-requirements/01-03-functional-requirements.md
|
||||
- specs/01-requirements/01-03.11-document-numbering.md
|
||||
- specs/03-implementation/03-04-document-numbering.md
|
||||
- specs/04-operations/04-08-document-numbering-operations.md
|
||||
- specs/07-database/07-01-data-dictionary-v1.7.0.md
|
||||
- specs/05-decisions/ADR-002-document-numbering-strategy.md
|
||||
Clean Version v1.6.2 – Scope of Changes:
|
||||
- เลือกใช้ Single Numbering System (Option A)
|
||||
- แก้ Primary Key design ให้ implement ได้จริง
|
||||
- ปรับ Character Rule เป็น UTF‑8 printable
|
||||
- Bind Reset Policy ชัดเจน (Yearly reset, RFA no reset)
|
||||
- เพิ่ม Number State Machine
|
||||
- เพิ่ม Idempotency Key
|
||||
- Drawing ใช้ separate counter namespace
|
||||
- เพิ่ม Formal Token Validation Grammar
|
||||
|
||||
---
|
||||
|
||||
> **📖 เอกสารที่เกี่ยวข้อง**
|
||||
@@ -72,27 +75,33 @@ Clean Version v1.6.2 – Scope of Changes:
|
||||
- Circulation Sheets (CIR)
|
||||
|
||||
### 3.11.1.5 Architectural Decision (Updated)
|
||||
|
||||
AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใช้ Option A:
|
||||
- document_number_counters เป็น Core / Authoritative Counter System
|
||||
- document_numbering_configs ใช้เฉพาะ:
|
||||
- Template format
|
||||
- Permission / policy
|
||||
- ยกเลิกการใช้ document_numbering_sequences เป็น counter จริง
|
||||
เหตุผล: ลดความซ้ำซ้อน, ป้องกัน counter mismatch, debug ง่าย, ops ชัดเจน
|
||||
|
||||
- document_number_counters เป็น Core / Authoritative Counter System
|
||||
- document_numbering_configs ใช้เฉพาะ:
|
||||
- Template format
|
||||
- Permission / policy
|
||||
- ยกเลิกการใช้ document_numbering_sequences เป็น counter จริง
|
||||
เหตุผล: ลดความซ้ำซ้อน, ป้องกัน counter mismatch, debug ง่าย, ops ชัดเจน
|
||||
|
||||
---
|
||||
|
||||
## 3.11.2 Counter Logic & Reset Policy
|
||||
|
||||
### 3.11.2 Counter Logic (Logic การนับเลข)
|
||||
|
||||
การนับเลขจะแยกตาม **Counter Key** ที่ประกอบด้วยหลายส่วน ขึ้นกับประเภทเอกสาร
|
||||
|
||||
| Document Type | Reset Policy |
|
||||
| ------------- | ------------ |
|
||||
| Correspondence (LETTER, MEMO, RFI, etc.) | Yearly reset |
|
||||
| Transmittal | Yearly reset |
|
||||
| RFA | No reset (continuous) |
|
||||
| Drawing | Separate namespace (see 3.11.8) |
|
||||
| Document Type | Reset Policy |
|
||||
| ---------------------------------------- | ------------------------------- |
|
||||
| Correspondence (LETTER, MEMO, RFI, etc.) | Yearly reset |
|
||||
| Transmittal | Yearly reset |
|
||||
| RFA | No reset (continuous) |
|
||||
| Drawing | Separate namespace (see 3.11.8) |
|
||||
|
||||
### 3.11.2.2 Counter Key Fields (Revised)
|
||||
|
||||
```
|
||||
(project_id,
|
||||
originator_organization_id,
|
||||
@@ -104,50 +113,55 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
reset_scope)
|
||||
```
|
||||
|
||||
* `reset_scope`:
|
||||
* `YEAR_2025`, `YEAR_2026`, ...
|
||||
* `NONE` (สำหรับ RFA)
|
||||
- `reset_scope`:
|
||||
- `YEAR_2025`, `YEAR_2026`, ...
|
||||
- `NONE` (สำหรับ RFA)
|
||||
|
||||
### 3.11.2.3 Counter Key Components
|
||||
|
||||
| Component | Required? | Description | Database Source | Default if NULL |
|
||||
| ---------------------------- | ---------------- | ------------------- | --------------------------------------------------------- | --------------- |
|
||||
| `project_id` | ✅ Yes | ID โครงการ | Derived from user context or organization | - |
|
||||
| `originator_organization_id` | ✅ Yes | ID องค์กรผู้ส่ง | `correspondences.originator_id` | - |
|
||||
| Component | Required? | Description | Database Source | Default if NULL |
|
||||
| ---------------------------- | ---------------- | ------------------------ | --------------------------------------------------------- | --------------- |
|
||||
| `project_id` | ✅ Yes | ID โครงการ | Derived from user context or organization | - |
|
||||
| `originator_organization_id` | ✅ Yes | ID องค์กรผู้ส่ง | `correspondences.originator_id` | - |
|
||||
| `recipient_organization_id` | Depends on type | ID องค์กรผู้รับหลัก (TO) | `correspondence_recipients` where `recipient_type = 'TO'` | 0 for RFA |
|
||||
| `correspondence_type_id` | ✅ Yes | ID ประเภทเอกสาร | `correspondence_types.id` | 0 |
|
||||
| `sub_type_id` | TRANSMITTAL only | ID ประเภทย่อย | `correspondence_sub_types.id` | 0 |
|
||||
| `rfa_type_id` | RFA only | ID ประเภท RFA | `rfa_types.id` | 0 |
|
||||
| `discipline_id` | RFA only | ID สาขางาน | `disciplines.id` | 0 |
|
||||
| `reset_scope` | ✅ Yes | ขอบเขต reset | System derived | - |
|
||||
| `correspondence_type_id` | ✅ Yes | ID ประเภทเอกสาร | `correspondence_types.id` | 0 |
|
||||
| `sub_type_id` | TRANSMITTAL only | ID ประเภทย่อย | `correspondence_sub_types.id` | 0 |
|
||||
| `rfa_type_id` | RFA only | ID ประเภท RFA | `rfa_types.id` | 0 |
|
||||
| `discipline_id` | RFA only | ID สาขางาน | `disciplines.id` | 0 |
|
||||
| `reset_scope` | ✅ Yes | ขอบเขต reset | System derived | - |
|
||||
|
||||
### 3.11.2.4 Counter Key by Document Type
|
||||
|
||||
#### **Global (LETTER / MEMO / RFI / EMAIL / INSTRUCTION / NOTICE / OTHER)**:
|
||||
|
||||
```
|
||||
(project_id, originator_organization_id, recipient_organization_id,
|
||||
correspondence_type_id, 0, 0, 0, 'YEAR_2025')
|
||||
```
|
||||
|
||||
**หมายเหตุ**:
|
||||
|
||||
- ไม่ใช้ `discipline_id`, `sub_type_id`, `rfa_type_id`
|
||||
- ถ้ามีการเพิ่ม correspondence type ใหม่ใน `correspondence_types` table จะใช้ Template นี้โดยอัตโนมัติ
|
||||
|
||||
#### **TRANSMITTAL**:
|
||||
|
||||
```
|
||||
(project_id, originator_organization_id, recipient_organization_id,
|
||||
correspondence_type_id, sub_type_id, 0, 0, 'YEAR_2025')
|
||||
```
|
||||
|
||||
*หมายเหตุ*: ใช้ `sub_type_id` เพิ่มเติม
|
||||
_หมายเหตุ_: ใช้ `sub_type_id` เพิ่มเติม
|
||||
|
||||
#### **RFA**:
|
||||
|
||||
```
|
||||
(project_id, originator_organization_id, 0,
|
||||
correspondence_type_id, 0, rfa_type_id, discipline_id, 'NONE')
|
||||
```
|
||||
|
||||
*หมายเหตุ*:
|
||||
_หมายเหตุ_:
|
||||
|
||||
- RFA ไม่ใช้ `recipient_organization_id` (ใช้ 0) เพราะเป็นเอกสารโครงการ (CONTRACTOR → CONSULTANT → OWNER)
|
||||
- ไม่มี yearly reset (`reset_scope = 'NONE'`)
|
||||
|
||||
@@ -181,6 +195,7 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
## 3.11.3 Format Templates by Correspondence Type
|
||||
|
||||
> **📝 หมายเหตุสำคัญ**
|
||||
>
|
||||
> - Templates ด้านล่างเป็น **ตัวอย่าง** สำหรับประเภทเอกสารหลัก
|
||||
> - ระบบรองรับ **ทุกประเภทเอกสาร** ที่อยู่ใน `correspondence_types` table
|
||||
> - หากมีการเพิ่มประเภทใหม่ในอนาคต สามารถใช้งานได้โดยอัตโนมัติ
|
||||
@@ -189,6 +204,7 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
### 3.11.3.1 Global (correspondence_type_id = defined)
|
||||
|
||||
**Template**:
|
||||
|
||||
```
|
||||
{ORIGINATOR}-{RECIPIENT}-{SEQ:4}-{YEAR:B.E.}
|
||||
```
|
||||
@@ -215,6 +231,7 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
### 3.11.3.2 Transmittal (TYPE = TRANSMITTAL)
|
||||
|
||||
**Template**:
|
||||
|
||||
```
|
||||
{ORIGINATOR}-{RECIPIENT}-{SUB_TYPE}-{SEQ:4}-{YEAR:B.E.}
|
||||
```
|
||||
@@ -256,10 +273,10 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
|
||||
---
|
||||
|
||||
|
||||
### 3.11.3.4 Drawing
|
||||
|
||||
#### 3.11.3.4.1 Shop Drawing
|
||||
|
||||
**Example**: `LCBP3-C2-SDW-SW-BST-002-1`
|
||||
|
||||
**Token Breakdown**:
|
||||
@@ -292,20 +309,20 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
|
||||
## 3.11.4 Supported Token Types
|
||||
|
||||
| Token | Description | Example | Database Source |
|
||||
| -------------- | ---------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- |
|
||||
| `{PROJECT}` | รหัสโครงการ | `LCBP3`, `LCBP3-C2` | `projects.project_code` |
|
||||
| `{ORIGINATOR}` | รหัสองค์กรผู้ส่ง | `คคง.`, `ผรม.1` | `organizations.organization_code` via `correspondences.originator_id` |
|
||||
| `{RECIPIENT}` | รหัสองค์กรผู้รับหลัก (TO) | `สคฉ.3`, `กทท.` | `organizations.organization_code` via `correspondence_recipients` where `recipient_type = 'TO'` |
|
||||
| `{CORR_TYPE}` | รหัสประเภทเอกสาร | `RFA`, `TRANSMITTAL`, `LETTER` | `correspondence_types.type_code` |
|
||||
| `{SUB_TYPE}` | หมายเลขประเภทย่อย | `11`, `12`, `21` | `correspondence_sub_types.sub_type_number` |
|
||||
| `{RFA_TYPE}` | รหัสประเภท RFA | `SDW`, `RPT`, `MAT` | `rfa_types.type_code` |
|
||||
| Token | Description | Example | Database Source |
|
||||
| -------------- | ------------------------------ | ------------------------------ | ----------------------------------------------------------------------------------------------- |
|
||||
| `{PROJECT}` | รหัสโครงการ | `LCBP3`, `LCBP3-C2` | `projects.project_code` |
|
||||
| `{ORIGINATOR}` | รหัสองค์กรผู้ส่ง | `คคง.`, `ผรม.1` | `organizations.organization_code` via `correspondences.originator_id` |
|
||||
| `{RECIPIENT}` | รหัสองค์กรผู้รับหลัก (TO) | `สคฉ.3`, `กทท.` | `organizations.organization_code` via `correspondence_recipients` where `recipient_type = 'TO'` |
|
||||
| `{CORR_TYPE}` | รหัสประเภทเอกสาร | `RFA`, `TRANSMITTAL`, `LETTER` | `correspondence_types.type_code` |
|
||||
| `{SUB_TYPE}` | หมายเลขประเภทย่อย | `11`, `12`, `21` | `correspondence_sub_types.sub_type_number` |
|
||||
| `{RFA_TYPE}` | รหัสประเภท RFA | `SDW`, `RPT`, `MAT` | `rfa_types.type_code` |
|
||||
| `{DISCIPLINE}` | รหัสสาขาวิชา | `STR`, `TER`, `GEO` | `disciplines.discipline_code` |
|
||||
| `{SEQ:n}` | Running number (n = จำนวนหลัก) | `0001`, `0029`, `0985` | Based on `document_number_counters.last_number + 1` |
|
||||
| `{YEAR:B.E.}` | ปี พ.ศ. | `2568` | `reset_scope` + 543 |
|
||||
| `{YEAR:A.D.}` | ปี ค.ศ. | `2025` | `reset_scope` |
|
||||
| `{REV}` | Revision Code | `A`, `B`, `AA` | `correspondence_revisions.revision_label` |
|
||||
| `{PREFIX}` | คำนำหน้าตามประเภทเอกสาร | `COR`, `RFA` | Configurable prefix |
|
||||
| `{YEAR:B.E.}` | ปี พ.ศ. | `2568` | `reset_scope` + 543 |
|
||||
| `{YEAR:A.D.}` | ปี ค.ศ. | `2025` | `reset_scope` |
|
||||
| `{REV}` | Revision Code | `A`, `B`, `AA` | `correspondence_revisions.revision_label` |
|
||||
| `{PREFIX}` | คำนำหน้าตามประเภทเอกสาร | `COR`, `RFA` | Configurable prefix |
|
||||
| `{YYYY}` | ปี 4 หลัก | `2025` | Current year |
|
||||
| `{YY}` | ปี 2 หลัก | `25` | Current year (short) |
|
||||
| `{MM}` | เดือน 2 หลัก | `01-12` | Current month |
|
||||
@@ -345,17 +362,18 @@ AD-DN-001: Single Source of Truth for Numbering ระบบ เลือกใ
|
||||
|
||||
### BR-DN-002 (Revised)
|
||||
|
||||
* Document number **must be printable UTF‑8**
|
||||
* Disallowed:
|
||||
* Control characters
|
||||
* Newlines / tabs
|
||||
* Allowed:
|
||||
* Thai
|
||||
* English
|
||||
* Numbers
|
||||
* `-`, `_`, `.`
|
||||
- Document number **must be printable UTF‑8**
|
||||
- Disallowed:
|
||||
- Control characters
|
||||
- Newlines / tabs
|
||||
- Allowed:
|
||||
- Thai
|
||||
- English
|
||||
- Numbers
|
||||
- `-`, `_`, `.`
|
||||
|
||||
### BR-DN-003: Number Format Rules
|
||||
|
||||
- Min length: 10 characters
|
||||
- Max length: 50 characters
|
||||
- Must include {SEQ:n} token exactly once
|
||||
@@ -373,14 +391,14 @@ RESERVED → CONFIRMED → VOID
|
||||
|
||||
### Rules
|
||||
|
||||
* **RESERVED**:
|
||||
* TTL 5 minutes
|
||||
* Auto-expire → CANCELLED
|
||||
* **CONFIRMED**:
|
||||
* Linked to document_id
|
||||
* **VOID**:
|
||||
* Only CONFIRMED numbers
|
||||
* Replacement creates new number
|
||||
- **RESERVED**:
|
||||
- TTL 5 minutes
|
||||
- Auto-expire → CANCELLED
|
||||
- **CONFIRMED**:
|
||||
- Linked to document_id
|
||||
- **VOID**:
|
||||
- Only CONFIRMED numbers
|
||||
- Replacement creates new number
|
||||
|
||||
---
|
||||
|
||||
@@ -388,7 +406,7 @@ RESERVED → CONFIRMED → VOID
|
||||
|
||||
### API Requirement
|
||||
|
||||
* All number generation APIs **must** support:
|
||||
- All number generation APIs **must** support:
|
||||
|
||||
```http
|
||||
Idempotency-Key: UUID
|
||||
@@ -396,21 +414,21 @@ Idempotency-Key: UUID
|
||||
|
||||
### Behavior
|
||||
|
||||
* Same key + same payload → return same number
|
||||
* Prevents double submit / retry duplication
|
||||
- Same key + same payload → return same number
|
||||
- Prevents double submit / retry duplication
|
||||
|
||||
---
|
||||
|
||||
## 3.11.8 Drawing Numbering (Clarified)
|
||||
|
||||
* Drawing numbering **does not use** this counter table
|
||||
* Uses **separate counter namespace**:
|
||||
- Drawing numbering **does not use** this counter table
|
||||
- Uses **separate counter namespace**:
|
||||
|
||||
```text
|
||||
DRAWING::<project>::<contract>
|
||||
```
|
||||
|
||||
* Prevents collision with correspondence/RFA
|
||||
- Prevents collision with correspondence/RFA
|
||||
|
||||
---
|
||||
|
||||
@@ -430,9 +448,9 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
|
||||
### Validation Rules
|
||||
|
||||
* Must include `{SEQ:n}` exactly once
|
||||
* Unknown tokens → validation error
|
||||
* Max template length: 50 chars
|
||||
- Must include `{SEQ:n}` exactly once
|
||||
- Unknown tokens → validation error
|
||||
- Max template length: 50 chars
|
||||
|
||||
---
|
||||
|
||||
@@ -441,12 +459,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
### 3.11.10.1 Auto Number Generation
|
||||
|
||||
#### FR-DN-001: Generate Sequential Number
|
||||
|
||||
**Priority**: CRITICAL | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องสามารถสร้างเลขที่เอกสารอัตโนมัติตามลำดับ (sequential) โดยไม่ซ้ำกัน
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- เลขที่เอกสารต้องเป็น unique ในscope ที่กำหนด
|
||||
- ต้องเพิ่มขึ้นทีละ 1 (increment by 1)
|
||||
- ต้องรองรับ concurrent requests โดยไม่มีเลขที่ซ้ำ
|
||||
@@ -455,12 +475,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-002: Configurable Number Format
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องรองรับการกำหนดรูปแบบเลขที่เอกสารที่หลากหลาย
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- รองรับ format tokens ที่ระบุ
|
||||
- Admin สามารถกำหนด format ผ่าน UI ได้
|
||||
- Validate format ก่อน save
|
||||
@@ -469,12 +491,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-003: Scope-based Sequences
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องรองรับการสร้าง sequence ที่แยกตาม scope ที่ต่างกัน
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- เลขที่ไม่ซ้ำภายใน scope เดียวกัน
|
||||
- Scope ที่ต่างกันสามารถมีเลขที่เดียวกันได้
|
||||
- Support multiple active scopes
|
||||
@@ -484,17 +508,20 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
### 3.11.10.2 Manual Override
|
||||
|
||||
#### FR-DN-004: Manual Number Assignment
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องรองรับการกำหนดเลขที่เอกสารด้วยตนเอง (manual override)
|
||||
|
||||
**Use Cases**:
|
||||
|
||||
1. Import เอกสารเก่าจากระบบเดิม
|
||||
2. External documents จาก client/consultant
|
||||
3. Correction หลังพบความผิดพลาด
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- ตรวจสอบ duplicate ก่อน save
|
||||
- Validate format ตามรูปแบบที่กำหนด
|
||||
- Auto-update sequence counter ถ้าเลขที่สูงกว่า current
|
||||
@@ -504,12 +531,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-005: Bulk Import Support
|
||||
|
||||
**Priority**: MEDIUM | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องรองรับการ import เอกสารหลายรายการพร้อมกัน
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- รองรับไฟล์ CSV/Excel
|
||||
- Validate ทุกรายการก่อน import
|
||||
- แสดง preview ก่อน confirm
|
||||
@@ -522,17 +551,20 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
### 3.11.10.3 Cancelled & Void Handling
|
||||
|
||||
#### FR-DN-006: Skip Cancelled Numbers
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
เลขที่เอกสารที่ถูกยกเลิกต้องไม่ถูก reuse
|
||||
|
||||
**Rationale**:
|
||||
|
||||
- รักษา audit trail ที่ชัดเจน
|
||||
- ป้องกันความสับสน
|
||||
- Legal compliance
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- Cancelled number ยังคงอยู่ในฐานข้อมูลพร้อม status
|
||||
- ระบบข้าม (skip) cancelled number เมื่อสร้างเลขที่ใหม่
|
||||
- บันทึกเหตุผลการยกเลิก
|
||||
@@ -541,12 +573,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-007: Void and Replace
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องรองรับการ void เอกสารและสร้างเอกสารใหม่แทน
|
||||
|
||||
**Workflow**:
|
||||
|
||||
1. User เลือกเอกสารที่ต้องการ void
|
||||
2. ระบุเหตุผล (required)
|
||||
3. ระบบเปลี่ยน status เอกสารเดิมเป็น VOID
|
||||
@@ -554,6 +588,7 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
5. Link เอกสารใหม่กับเดิม (voided_from_id)
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- เอกสารเดิม status = VOID (ไม่ลบ)
|
||||
- เอกสารใหม่ได้เลขที่ต่อเนื่องจาก sequence
|
||||
- มี reference link ระหว่างเอกสาร
|
||||
@@ -565,17 +600,20 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
### 3.11.10.4 Concurrency & Performance
|
||||
|
||||
#### FR-DN-008: Prevent Race Conditions
|
||||
|
||||
**Priority**: CRITICAL | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ระบบต้องป้องกันการสร้างเลขที่ซ้ำเมื่อมีการ request พร้อมกัน
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Distributed locking (Redlock)
|
||||
- Database pessimistic locking
|
||||
- Two-phase commit pattern
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- Zero duplicate numbers ภายใต้ concurrent load (1000 req/s)
|
||||
- Lock acquisition time < 50ms (avg)
|
||||
- Automatic retry on lock failure (max 3 times)
|
||||
@@ -584,36 +622,43 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-009: Two-Phase Commit
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
ใช้ Two-phase commit pattern เพื่อความสมบูรณ์ของข้อมูล
|
||||
|
||||
**Phase 1: Reserve**
|
||||
|
||||
- ล็อกเลขที่และ reserve ไว้ชั่วคราว
|
||||
- Set TTL 5 นาที
|
||||
- Return reservation token
|
||||
|
||||
**Phase2: Confirm or Cancel**
|
||||
|
||||
- Confirm: บันทึกลงฐานข้อมูลถาวร
|
||||
- Cancel: คืน lock และ reservation
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- Reservation ต้อง expire หลัง 5 นาที
|
||||
- Auto-cleanup expired reservations
|
||||
- Support explicit cancel
|
||||
- Idempotent confirmation
|
||||
|
||||
---
|
||||
|
||||
### 3.11.10.5 Monitoring & Audit
|
||||
|
||||
#### FR-DN-010: Complete Audit Trail
|
||||
|
||||
**Priority**: HIGH | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
บันทึกทุก operation ที่เกิดขึ้นกับเลขที่เอกสาร
|
||||
|
||||
**Events to Log**:
|
||||
|
||||
- Number reserved
|
||||
- Number confirmed
|
||||
- Number cancelled
|
||||
@@ -623,6 +668,7 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
- Format changed
|
||||
|
||||
**Acceptance Criteria**:
|
||||
|
||||
- Log ทุก operation
|
||||
- Searchable by user, date, type
|
||||
- Export to CSV
|
||||
@@ -631,12 +677,14 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
---
|
||||
|
||||
#### FR-DN-011: Metrics & Alerting
|
||||
|
||||
**Priority**: MEDIUM | **Status**: Required
|
||||
|
||||
**Description**:
|
||||
แสดงสถิติและส่ง alert เมื่อเกิดปัญหา
|
||||
|
||||
**Metrics**:
|
||||
|
||||
- Sequence utilization (% of max)
|
||||
- Average lock wait time
|
||||
- Failed lock attempts
|
||||
@@ -644,6 +692,7 @@ DIGIT := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
- Manual overrides per day
|
||||
|
||||
**Alerts**:
|
||||
|
||||
- Sequence >90% used (WARNING)
|
||||
- Sequence >95% used (CRITICAL)
|
||||
- Lock wait time >1s (WARNING)
|
||||
@@ -690,10 +739,10 @@ CREATE TABLE document_number_counters (
|
||||
|
||||
### Rules
|
||||
|
||||
* RFA → `recipient_organization_id = 0`
|
||||
* Reset:
|
||||
* Yearly: `reset_scope = 'YEAR_2025'`
|
||||
* No reset: `reset_scope = 'NONE'`
|
||||
- RFA → `recipient_organization_id = 0`
|
||||
- Reset:
|
||||
- Yearly: `reset_scope = 'YEAR_2025'`
|
||||
- No reset: `reset_scope = 'NONE'`
|
||||
|
||||
### 3.11.11.2 Index Requirements
|
||||
|
||||
@@ -781,6 +830,7 @@ CREATE TABLE document_number_audit (
|
||||
```
|
||||
|
||||
### 3.11.11.5 Reservation Table
|
||||
|
||||
```sql
|
||||
CREATE TABLE document_number_reservations (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -829,6 +879,7 @@ CREATE TABLE document_number_reservations (
|
||||
COMMENT='Document Number Reservations - Two-Phase Commit';
|
||||
|
||||
```
|
||||
|
||||
### 3.11.11.5 Error Log Table
|
||||
|
||||
```sql
|
||||
@@ -875,12 +926,14 @@ CREATE TABLE document_number_config_history (
|
||||
### 3.11.11.7 Important Notes
|
||||
|
||||
> **💡 Counter Key Design**
|
||||
>
|
||||
> - `recipient_organization_id` ใช้ `0` สำหรับ RFA (ไม่มี specific recipient)
|
||||
> - `version` column สำหรับ Optimistic Locking (ป้องกัน race condition)
|
||||
> - `last_number` เริ่มจาก 0 และเพิ่มขึ้นทีละ 1
|
||||
> - Counter reset ทุกปี (เมื่อ `reset_scope` เปลี่ยน)
|
||||
|
||||
> **⚠️ Migration Notes**
|
||||
>
|
||||
> - ไม่มีข้อมูลเก่า ไม่ต้องทำ backward compatibility
|
||||
> - สามารถสร้าง table ใหม่ได้เลยตาม schema ข้างต้น
|
||||
> - ต้องมี seed data สำหรับ `correspondence_types`, `rfa_types`, `disciplines` ก่อน
|
||||
@@ -953,6 +1006,7 @@ INSERT INTO document_number_counters (
|
||||
### 3.11.12.4 Rate Limiting
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Limit ต่อ user: **10 requests/minute** (prevent abuse)
|
||||
- Limit ต่อ IP: **50 requests/minute**
|
||||
|
||||
@@ -1049,14 +1103,14 @@ INSERT INTO document_number_counters (
|
||||
|
||||
**SLA Targets:**
|
||||
|
||||
| Metric | Target | Notes |
|
||||
| ----------------- | -------- | ------------------------ |
|
||||
| Metric | Target | Notes |
|
||||
| ----------------- | ---------- | ---------------------------- |
|
||||
| 95th percentile | ≤ 2 วินาที | ตั้งแต่ request ถึง response |
|
||||
| 99th percentile | ≤ 5 วินาที | รวม retry attempts |
|
||||
| Normal operation | ≤ 500ms | ไม่มี retry |
|
||||
| Number generation | < 100ms | (p95) |
|
||||
| Lock acquisition | < 50ms | (avg) |
|
||||
| Bulk import | < 5s | per 100 records |
|
||||
| 99th percentile | ≤ 5 วินาที | รวม retry attempts |
|
||||
| Normal operation | ≤ 500ms | ไม่มี retry |
|
||||
| Number generation | < 100ms | (p95) |
|
||||
| Lock acquisition | < 50ms | (avg) |
|
||||
| Bulk import | < 5s | per 100 records |
|
||||
|
||||
### 3.11.16.2 Throughput
|
||||
|
||||
@@ -1064,8 +1118,8 @@ INSERT INTO document_number_counters (
|
||||
|
||||
| Load Level | Target | Notes |
|
||||
| ----------- | ----------- | ------------------ |
|
||||
| Normal load | ≥ 50 req/s | ใช้งานปกติ |
|
||||
| Peak load | ≥ 100 req/s | ช่วงเร่งงาน |
|
||||
| Normal load | ≥ 50 req/s | ใช้งานปกติ |
|
||||
| Peak load | ≥ 100 req/s | ช่วงเร่งงาน |
|
||||
| Burst | ≥ 200 req/s | short duration |
|
||||
| Support | > 500 req/s | Scale horizontally |
|
||||
|
||||
@@ -1106,8 +1160,8 @@ INSERT INTO document_number_counters (
|
||||
|
||||
ระบบ**ต้อง**alert สำหรับ conditions ต่อไปนี้:
|
||||
|
||||
| Severity | Condition | Action |
|
||||
| ---------- | ---------------------------- | ----------------- |
|
||||
| Severity | Condition | Action |
|
||||
| ----------- | ---------------------------- | ----------------- |
|
||||
| 🔴 Critical | Redis unavailable > 1 minute | PagerDuty + Slack |
|
||||
| 🔴 Critical | Lock failures > 10% in 5 min | PagerDuty + Slack |
|
||||
| 🔴 Critical | Sequence >95% used | PagerDuty + Slack |
|
||||
@@ -1174,6 +1228,7 @@ POST /api/document-numbering/reserve
|
||||
```
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"document_type": "COR",
|
||||
@@ -1184,6 +1239,7 @@ POST /api/document-numbering/reserve
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "uuid-v4",
|
||||
@@ -1199,6 +1255,7 @@ POST /api/document-numbering/confirm
|
||||
```
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "uuid-v4"
|
||||
@@ -1206,6 +1263,7 @@ POST /api/document-numbering/confirm
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
|
||||
```json
|
||||
{
|
||||
"document_number": "COR-2025-00042",
|
||||
@@ -1221,6 +1279,7 @@ Authorization: Bearer <admin-token>
|
||||
```
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"document_type": "COR",
|
||||
@@ -1231,6 +1290,7 @@ Authorization: Bearer <admin-token>
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
|
||||
```json
|
||||
{
|
||||
"document_number": "COR-2024-99999",
|
||||
@@ -1264,12 +1324,14 @@ Reset counter (Super Admin only, requires approval)
|
||||
## 3.11.19 Testing Requirements
|
||||
|
||||
### 3.11.19.1 Unit Tests
|
||||
|
||||
- Format parsing and validation
|
||||
- Sequence increment logic
|
||||
- Manual override validation
|
||||
- Scope resolution
|
||||
|
||||
### 3.11.19.2 Integration Tests
|
||||
|
||||
- Redis locking mechanism
|
||||
- Database transactions
|
||||
- Two-phase commit flow
|
||||
@@ -1291,6 +1353,7 @@ expected_duplicates: 0
|
||||
- Database connection pool exhaustion
|
||||
|
||||
### 3.11.19.4 E2E Tests
|
||||
|
||||
- Complete document creation flow
|
||||
- Void and replace workflow
|
||||
- Bulk import with validation
|
||||
@@ -1300,14 +1363,15 @@ expected_duplicates: 0
|
||||
|
||||
## 3.11.20 Versioning Note
|
||||
|
||||
* Existing documents **not affected**
|
||||
* New rules apply to documents generated after upgrade to v1.6.2
|
||||
- Existing documents **not affected**
|
||||
- New rules apply to documents generated after upgrade to v1.6.2
|
||||
|
||||
---
|
||||
|
||||
## 3.11.21 Migration Plan
|
||||
|
||||
### 3.11.21.1 Legacy Data Import
|
||||
|
||||
1. Export existing document numbers from old system
|
||||
2. Validate format and detect duplicates
|
||||
3. Bulk import using manual override API
|
||||
@@ -1315,6 +1379,7 @@ expected_duplicates: 0
|
||||
5. Verify data integrity
|
||||
|
||||
### 3.11.21.2 Rollout Strategy
|
||||
|
||||
- Week 1-2: Deploy to staging, test with dummy data
|
||||
- Week 3: Deploy to production, enable for test project
|
||||
- Week 4: Enable for all projects
|
||||
@@ -1325,18 +1390,21 @@ expected_duplicates: 0
|
||||
## 3.11.22 Success Criteria
|
||||
|
||||
### 3.11.22.1 Functional Success
|
||||
|
||||
- ✅ All FRs implemented and tested
|
||||
- ✅ Zero duplicate numbers in production
|
||||
- ✅ Migration of 50,000+ legacy documents
|
||||
- ✅ UAT approved by stakeholders
|
||||
|
||||
### 3.11.22.2 Performance Success
|
||||
|
||||
- ✅ Response time <100ms (p95)
|
||||
- ✅ Throughput >500 req/s
|
||||
- ✅ Lock acquisition <50ms (avg)
|
||||
- ✅ Zero downtime during deployment
|
||||
|
||||
### 3.11.22.3 Business Success
|
||||
|
||||
- ✅ Document creation speed +30%
|
||||
- ✅ Manual numbering errors -80%
|
||||
- ✅ User satisfaction >4.5/5
|
||||
@@ -1359,6 +1427,7 @@ expected_duplicates: 0
|
||||
## 3.11.24 Appendix
|
||||
|
||||
### 3.11.24.1 Glossary
|
||||
|
||||
- **Sequence**: ลำดับตัวเลขที่เพิ่มขึ้นอัตโนมัติ
|
||||
- **Scope**: ขอบเขตที่ sequence แยกตาม (project, contract, etc.)
|
||||
- **Token**: Format placeholder (e.g., {YYYY}, {SEQ})
|
||||
@@ -1368,10 +1437,10 @@ expected_duplicates: 0
|
||||
|
||||
**Approval Sign-off**:
|
||||
|
||||
| Role | Name | Date | Signature |
|
||||
| ------------- | ----------- | ------- | --------- |
|
||||
| Product Owner | ___________ | _______ | _________ |
|
||||
| Tech Lead | ___________ | _______ | _________ |
|
||||
| QA Lead | ___________ | _______ | _________ |
|
||||
| Role | Name | Date | Signature |
|
||||
| ------------- | -------------- | ---------- | ---------- |
|
||||
| Product Owner | ****\_\_\_**** | **\_\_\_** | ****\_**** |
|
||||
| Tech Lead | ****\_\_\_**** | **\_\_\_** | ****\_**** |
|
||||
| QA Lead | ****\_\_\_**** | **\_\_\_** | ****\_**** |
|
||||
|
||||
**End of Document v1.6.2**
|
||||
|
||||
Reference in New Issue
Block a user