# 3.11 Document Numbering Management (การจัดการเลขที่เอกสาร) --- title: 'Functional Requirements: Document Numbering Management' version: 1.5.0 status: first-draft owner: Nattanin Peancharoen last_updated: 2025-12-02 related: - specs/01-requirements/01-objectives.md - specs/01-requirements/02-architecture.md - specs/01-requirements/03-functional-requirements.md - specs/04-data-dictionary/4_Data_Dictionary_V1_4_4.md --- ## 3.11.1. วัตถุประสงค์ - ระบบต้องสามารถสร้างเลขที่เอกสาร (Running Number) ได้โดยอัตโนมัติและยืดหยุ่นสูง - ระบบต้องสามารถกำหนดรูปแบบ (template) เลขที่เอกสารได้ สำหรับแต่ละโครงการ, ชนิดเอกสาร, ประเภทเอกสาร - ระบบต้องรับประกัน Uniqueness ของเลขที่เอกสารในทุกสถานการณ์ - ระบบต้องรองรับการทำงานแบบ concurrent ได้อย่างปลอดภัย ## 3.11.2. Logic การนับเลข (Counter Logic) การนับเลขจะแยกตาม **Counter Key** ที่ประกอบด้วย: - `project_id` - รหัสโครงการ - `doc_type_id` - ชนิดเอกสาร (Correspondence, RFA, Transmittal, Drawing) - `sub_type_id` - ประเภทย่อยของเอกสาร (nullable) - `discipline_id` - สาขาวิชา/งาน (nullable) - `year` - ปี พ.ศ. หรือ ค.ศ. ตามที่กำหนดใน template ### ตัวอย่าง Counter Key ```text Correspondence: project_id + doc_type_id + sub_type_id + year RFA: project_id + doc_type_id + discipline_id + year Transmittal: project_id + doc_type_id + recipient_type + year Drawing: project_id + doc_type_id + discipline_id + year ``` ### Fallback สำหรับค่า NULL - กรณีที่ `discipline_id` หรือ `sub_type_id` เป็น NULL ให้ใช้ค่า Default `0` ในการจัดกลุ่ม Counter - ป้องกัน Error และรับประกันความถูกต้องของ Running Number (Uniqueness Guarantee) ## 3.11.3. Format Templates by Document Type ระบบรองรับการกำหนดรูปแบบด้วย **Token Replacement** ### 3.11.3.1. Correspondence (หนังสือราชการ) #### Letter Type (TYPE = 03) - **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}` - **Example**: `คคง.-สคฉ.3-0985-2568` - **Counter Key**: `project_id + doc_type_id + sub_type_id + year` #### Other Correspondence Types - **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}` - **Example**: `คคง.-สคฉ.3-STR-0001-2568` - **Counter Key**: `project_id + doc_type_id + sub_type_id + year` ### 3.11.3.2. Transmittal #### Transmittal to Owner - **Template**: `{ORG}-{ORG}-{TYPE}-{SUB_TYPE}-{SEQ:4}-{YEAR:B.E.}` - **Example**: `คคง.-สคฉ.3-03-21-0117-2568` - **Counter Key**: `project_id + doc_type_id + recipient_type + year` - **Note**: `recipient_type = 'OWNER'` #### Transmittal to Contractor/Others - **Template**: `{ORG}-{ORG}-{TYPE}-{SEQ:4}-{YEAR:B.E.}` - **Example**: `ผรม.2-คคง.-0117-2568` - **Counter Key**: `project_id + doc_type_id + recipient_type + year` - **Note**: `recipient_type = 'CONTRACTOR' | 'CONSULTANT' | 'OTHER'` #### Alternative Project-based Format - **Template**: `{PROJECT}-{ORG}-{TYPE}-{DISCIPLINE}-{SEQ:4}-{REV}` - **Example**: `LCBP3-TR-STR-0001-A` - **Counter Key**: `project_id + doc_type_id + discipline_id + year` ### 3.11.3.3. RFA (Request for Approval) - **Template**: `{PROJECT}-{ORG}-{TYPE}-{DISCIPLINE}-{SEQ:4}-{REV}` - **Example**: `LCBP3-C2-RFI-ROW-0029-A` - **Counter Key**: `project_id + doc_type_id + discipline_id + year` - **Note**: `{REV}` คือ revision code (A, B, C, ..., AA, AB, ...) ### 3.11.3.4. Drawing - **Template**: `{PROJECT}-{DISCIPLINE}-{CATEGORY}-{SEQ:4}-{REV}` - **Example**: `LCBP3-STR-DRW-0001-A` - **Counter Key**: `project_id + doc_type_id + discipline_id + category + year` ## 3.11.4. Supported Token Types | Token | Description | Example | |-------|-------------|---------| | `{PROJECT}` | รหัสโครงการ | `LCBP3` | | `{ORG}` | รหัสหน่วยงาน | `คคง.`, `สคฉ.3` | | `{TYPE}` | รหัสชนิดเอกสาร | `RFI`, `03` | | `{SUB_TYPE}` | รหัสประเภทย่อย | `21` | | `{DISCIPLINE}` | รหัสสาขาวิชา | `STR`, `ROW` | | `{CATEGORY}` | หมวดหมู่ | `DRW` | | `{SEQ:n}` | Running number (n = จำนวนหลัก) | `0001`, `0029` | | `{YEAR:B.E.}` | ปี พ.ศ. | `2568` | | `{YEAR:A.D.}` | ปี ค.ศ. | `2025` | | `{REV}` | Revision Code | `A`, `B`, `AA` | ## 3.11.5. Transmittal Special Logic - Transmittal มีเงื่อนไขพิเศษที่เลขอาจเปลี่ยนตามผู้รับ: - **To Owner**: ใช้ format พิเศษที่มี sub_type รหัสโครงการ - **To Contractor/Others**: ใช้ format ทั่วไป - Counter Key จะแยกตาม `recipient_type` เพื่อให้แต่ละประเภทมี running number อิสระ ## 3.11.6. กลไกความปลอดภัย (Concurrency Control) ### 3.11.6.1. Redis Distributed Lock - ใช้ Redis Distributed Lock เพื่อป้องกัน race condition - Lock key format: `lock:docnum:{project_id}:{doc_type_id}:{...counter_key_parts}` - Lock TTL: 5 วินาที (auto-release เมื่อ timeout) - Lock acquisition timeout: 10 วินาที ### 3.11.6.2. Optimistic Locking - ใช้ `version` column ในตาราง `document_number_configs` - ตรวจสอบ version ก่อน update counter - หาก version conflict เกิดขึ้น → retry transaction ### 3.11.6.3. Database Constraints - Unique constraint บน `document_number` column - Foreign key constraints เพื่อความสัมพันธ์ข้อมูล - Check constraints สำหรับ business rules ## 3.11.7. Retry Mechanism & Error Handling ### 3.11.7.1. Scenario 1: Redis Unavailable - **Fallback**: ใช้ database-only locking (pessimistic lock) - **Action**: - ใช้ `SELECT ... FOR UPDATE` แทน Redis lock - Log warning พร้อม alert ops team - ระบบยังใช้งานได้แต่ performance ลดลง ### 3.11.7.2. Scenario 2: Lock Acquisition Timeout - **Retry**: 5 ครั้งด้วย exponential backoff - Attempt 1: wait 1s - Attempt 2: wait 2s - Attempt 3: wait 4s - Attempt 4: wait 8s - Attempt 5: wait 16s (รวม ~31 วินาที) - **Failure**: Return HTTP 503 "Service Temporarily Unavailable" - **Frontend**: แสดงข้อความ "ระบบกำลังยุ่ง กรุณาลองใหม่ภายหลัง" ### 3.11.7.3. Scenario 3: Version Conflict After Lock - **Retry**: 2 ครั้ง (reload counter + retry transaction) - **Failure**: Log error พร้อม context และ return HTTP 409 Conflict - **Frontend**: แสดงข้อความ "เลขที่เอกสารถูกเปลี่ยน กรุณาลองใหม่" ### 3.11.7.4. Scenario 4: Database Connection Error - **Retry**: 3 ครั้งด้วย exponential backoff (1s, 2s, 4s) - **Failure**: Return HTTP 500 "Internal Server Error" - **Frontend**: แสดงข้อความ "เกิดข้อผิดพลาดในระบบ กรุณาติดต่อผู้ดูแลระบบ" ## 3.11.8. Configuration Management ### 3.11.8.1. Admin Panel Configuration - Project Admin สามารถกำหนด/แก้ไข template ผ่าน Admin Panel - การเปลี่ยนแปลง template จะไม่ส่งผลต่อเอกสารที่สร้างไว้แล้ว - ต้องมีการ validate template ก่อนบันทึก (ตรวจสอบ token ที่ใช้ถูกต้อง) ### 3.11.8.2. Template Versioning - เก็บ history ของ template changes - บันทึก user, timestamp, และเหตุผลในการเปลี่ยนแปลง - สามารถ rollback ไปเวอร์ชันก่อนหน้าได้ ### 3.11.8.3. Counter Reset Policy - Counter reset ตามปี (yearly reset) - Counter reset ตาม project phase (optional) - Admin สามารถ manual reset counter ได้ (require approval + audit log) ## 3.11.9. Audit Trail ### 3.11.9.1. การบันทึก Audit Log บันทึกทุกการ generate เลขที่เอกสารใน `document_number_audit` table: - `document_id` - เอกสารที่ถูกสร้าง - `generated_number` - เลขที่ถูกสร้าง - `counter_key` - key ที่ใช้ในการนับ - `template_used` - template ที่ใช้ - `user_id` - ผู้ที่ request - `ip_address` - IP address ของผู้ request - `timestamp` - เวลาที่สร้าง - `retry_count` - จำนวนครั้งที่ retry (ถ้ามี) ### 3.11.9.2. Conflict & Error Logging - บันทึก version conflicts และ กลไก retry ที่ใช้ - บันทึก lock timeouts และ failure reasons - บันทึก fallback scenarios (เช่น Redis unavailable) ## 3.11.10. Performance Requirements ### 3.11.10.1. Response Time - Document number generation ต้องเสร็จภายใน **2 วินาที** (95th percentile) - Document number generation ต้องเสร็จภายใน **5 วินาที** (99th percentile) - ในกรณี normal operation (ไม่มี retry) ควรเสร็จภายใน **500ms** ### 3.11.10.2. Throughput - ระบบรองรับ concurrent requests อย่างน้อย **50 requests/second** - Peak load รองรับได้ถึง **100 requests/second** (ช่วงเวลาเร่งงาน) ### 3.11.10.3. Availability - Uptime ≥ 99.5% (exclude planned maintenance) - Maximum downtime ต่อเดือน ≤ 3.6 ชั่วโมง ## 3.11.11. Monitoring & Alerting ### 3.11.11.1. Metrics to Monitor - Lock acquisition time (p50, p95, p99) - Lock acquisition failure rate - Counter generation latency - Retry count distribution - Redis connection status - Database connection pool usage ### 3.11.11.2. Alert Conditions - 🔴 **Critical**: Redis unavailable > 1 minute - 🔴 **Critical**: Lock acquisition failures > 10% in 5 minutes - 🟡 **Warning**: Lock acquisition failures > 5% in 5 minutes - 🟡 **Warning**: Average lock wait time > 1 second - 🟡 **Warning**: Retry count > 100 per hour ### 3.11.11.3. Dashboard - Real-time lock acquisition success rate - Lock wait time percentiles (p50, p95, p99) - Counter generation rate (per minute) - Error rate breakdown (by error type) - Redis/Database health status ## 3.11.12. API Reference เอกสารนี้อ้างอิงถึง API endpoints ต่อไปนี้ (รายละเอียดใน `specs/02-architecture/api-design.md`): - `POST /api/v1/documents/{documentId}/generate-number` - สร้างเลขที่เอกสาร - `GET /api/v1/document-numbering/configs` - ดูการตั้งค่า template - `PUT /api/v1/document-numbering/configs/{configId}` - แก้ไข template (Admin only) - `POST /api/v1/document-numbering/configs/{configId}/reset-counter` - Reset counter (Admin only) ## 3.11.13. Database Schema Reference เอกสารนี้อ้างอิงถึง tables ต่อไปนี้ (รายละเอียดใน `specs/04-data-dictionary/4_Data_Dictionary_V1_4_4.md`): - `document_number_configs` - เก็บ template และ counter configuration - `document_number_counters` - เก็บ current counter value - `document_number_audit` - เก็บ audit trail - `documents` - เก็บ document number ที่ถูกสร้าง ## 3.11.14. Security Considerations ### 3.11.14.1. Authorization - เฉพาะ authenticated users เท่านั้นที่สามารถ request document number - เฉพาะ Project Admin เท่านั้นที่แก้ไข template ได้ - เฉพาะ Super Admin เท่านั้นที่ reset counter ได้ ### 3.11.14.2. Rate Limiting - Limit ต่อ user: **10 requests/minute** (prevent abuse) - Limit ต่อ IP: **50 requests/minute** ### 3.11.14.3. Audit & Compliance - บันทึกทุก API call ที่เกี่ยวข้องกับ document numbering - เก็บ audit log อย่างน้อย **7 ปี** (ตาม พ.ร.บ. ข้อมูลอิเล็กทรอนิกส์)