Files
lcbp3/specs/01-requirements/01-03.11-document-numbering.md
admin 83704377f4
Some checks are pending
Spec Validation / validate-markdown (push) Waiting to run
Spec Validation / validate-diagrams (push) Waiting to run
Spec Validation / check-todos (push) Waiting to run
251218:1701 On going update to 1.7.0: Documnet Number rebuild
2025-12-18 17:01:42 +07:00

48 KiB
Raw Permalink Blame History

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 เป็น UTF8 printable
  • Bind Reset Policy ชัดเจน (Yearly reset, RFA no reset)
  • เพิ่ม Number State Machine
  • เพิ่ม Idempotency Key
  • Drawing ใช้ separate counter namespace
  • เพิ่ม Formal Token Validation Grammar

📖 เอกสารที่เกี่ยวข้อง


3.11.1 Overview & วัตถุประสงค์

3.11.1.1 Purpose

ระบบ Document Numbering สำหรับสร้างเลขที่เอกสารอัตโนมัติที่มีความเป็นเอกลักษณ์ (unique) และสามารถติดตามได้ (traceable) สำหรับเอกสารทุกประเภทในระบบ LCBP3-DMS

3.11.1.2 Requirements Summary

  • ระบบต้องสามารถสร้างเลขที่เอกสาร (Running Number) ได้โดยอัตโนมัติ, ที่มีความเป็นเอกลักษณ์ (unique) และยืดหยุ่นสูง
  • ระบบต้องสามารถกำหนดรูปแบบ (template) เลขที่เอกสารได้ สำหรับแต่ละโครงการ, ชนิดเอกสาร, ประเภทเอกสาร
  • ระบบต้องรับประกัน Uniqueness ของเลขที่เอกสารในทุกสถานการณ์
  • ระบบต้องรองรับการทำงานแบบ concurrent ได้อย่างปลอดภัย

3.11.1.3 Scope

  • Auto-generation ของเลขที่เอกสารตามรูปแบบที่กำหนด
  • Manual override สำหรับการ import เอกสารเก่า
  • Cancelled number handling (ไม่ reuse)
  • Void & Replace pattern สำหรับการแทนที่เอกสาร
  • Distributed locking เพื่อป้องกัน race condition
  • Complete audit trail สำหรับทุก operation

3.11.1.4 Document Types Supported

  • Request for Approvals (RFA)
  • Request for Information (RFI)
  • Transmittal (TRANSMITTAL)
  • Email (EMAIL)
  • Instruction (INSTRUCTION)
  • Letter (LETTER)
  • Memorandum (MEMO)
  • Minutes of Meeting (MOM)
  • Notice (NOTICE)
  • Other (OTHER)
  • Contract Drawings (COD)
  • Shop Drawings (SHD)
  • 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 ชัดเจน

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)

3.11.2.2 Counter Key Fields (Revised)

(project_id,
 originator_organization_id,
 recipient_organization_id,
 correspondence_type_id,
 sub_type_id,
 rfa_type_id,
 discipline_id,
 reset_scope)
  • 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 -
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 -

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 เพิ่มเติม

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')

3.11.2.5 วิธีการหา project_id

เนื่องจาก Template ของ LETTER/TRANSMITTAL ไม่มี {PROJECT} token ระบบจะหา project_id จาก:

  1. User Context (แนะนำ):

    • เมื่อ User สร้างเอกสาร UI จะให้เลือก Project/Contract ก่อน
    • ใช้ project_id จาก Context ที่เลือก
  2. จาก Organization:

    • Query project_organizations หรือ contract_organizations
    • ใช้ originator_organization_id หา project ที่เกี่ยวข้อง
    • ถ้ามีหลาย project ให้ User เลือก
  3. Validation:

    • ตรวจสอบว่า organization มีสิทธิ์ใน project นั้น
    • ตรวจสอบว่า project/contract เป็น active

3.11.2.6 Fallback สำหรับค่า NULL

  • correspondence_type_id: ใช้ 0 (ไม่ระบุประเภทเอกสาร)
  • discipline_id: ใช้ 0 (ไม่ระบุสาขางาน)
  • sub_type_id: ใช้ 0 (ไม่มีประเภทย่อย)
  • rfa_type_id: ใช้ 0 (ไม่ระบุประเภท RFA)
  • recipient_organization_id: ใช้ 0 สำหรับ RFA, Required สำหรับ LETTER/TRANSMITTAL

3.11.3 Format Templates by Correspondence Type

📝 หมายเหตุสำคัญ

  • Templates ด้านล่างเป็น ตัวอย่าง สำหรับประเภทเอกสารหลัก
  • ระบบรองรับ ทุกประเภทเอกสาร ที่อยู่ใน correspondence_types table
  • หากมีการเพิ่มประเภทใหม่ในอนาคต สามารถใช้งานได้โดยอัตโนมัติ
  • Admin สามารถกำหนด Template เฉพาะสำหรับแต่ละประเภทผ่าน Admin Panel

3.11.3.1 Global (correspondence_type_id = defined)

Template:

{ORIGINATOR}-{RECIPIENT}-{SEQ:4}-{YEAR:B.E.}

Example: คคง.-สคฉ.3-0001-2568

Token Breakdown:

  • คคง. = {ORIGINATOR} = รหัสองค์กรผู้ส่ง
  • สคฉ.3 = {RECIPIENT} = รหัสองค์กรผู้รับหลัก (TO)
  • 0001 = {SEQ:4} = Running number (เริ่ม 0001, 0002, ...)
  • 2568 = {YEAR:B.E.} = ปี พ.ศ.

⚠️ Template vs Counter Separation

  • {CORR_TYPE} ไม่แสดงใน template เพื่อความกระชับ
  • แต่ระบบยังใช้ correspondence_type_id ใน Counter Key เพื่อแยก counter
  • LETTER, MEMO, RFI มี counter แยกกัน แม้ template format เหมือนกัน

Counter Key: (project_id, originator_org_id, recipient_org_id, correspondence_type_id, 0, 0, 0, 'YEAR_2025')


3.11.3.2 Transmittal (TYPE = TRANSMITTAL)

Template:

{ORIGINATOR}-{RECIPIENT}-{SUB_TYPE}-{SEQ:4}-{YEAR:B.E.}

Example: คคง.-สคฉ.3-21-0117-2568

Token Breakdown:

  • คคง. = {ORIGINATOR}
  • สคฉ.3 = {RECIPIENT}
  • 21 = {SUB_TYPE} = หมายเลขประเภทย่อย (11=MAT, 12=SHP, 13=DWG, 14=MET, ...)
  • 0117 = {SEQ:4}
  • 2568 = {YEAR:B.E.}

Counter Key: (project_id, originator_org_id, recipient_org_id, correspondence_type_id, sub_type_id, 0, 0, 'YEAR_2025')


3.11.3.3 RFA (Request for Approval)

Example: LCBP3-C2-RFA-TER-RPT-0001-A

Token Breakdown:

  • LCBP3-C2 = {PROJECT} = รหัสโครงการ
  • RFA = {CORR_TYPE} = ประเภทเอกสาร (แสดงใน RFA template)
  • TER = {DISCIPLINE} = รหัสสาขางาน (TER=Terminal, STR=Structure, ...)
  • RPT = {RFA_TYPE} = ประเภท RFA (RPT=Report, SDW=Shop Drawing, ...)
  • 0001 = {SEQ:4}
  • A = {REV} = Revision code

📋 RFA Workflow

  • RFA เป็น เอกสารโครงการ (Project-level document)
  • Workflow: CONTRACTOR → CONSULTANT → OWNER
  • ไม่มี specific recipient_id เพราะเป็น workflow ที่กำหนดไว้แล้ว

Counter Key: (project_id, originator_org_id, 0, correspondence_type_id, 0, rfa_type_id, discipline_id, 'NONE')


3.11.3.4 Drawing

Status: 🚧 To Be Determined

Drawing Numbering ยังไม่ได้กำหนด Template เนื่องจาก:

  • มีความซับซ้อนสูง (Contract Drawing และ Shop Drawing มีกฎต่างกัน)
  • อาจต้องใช้ระบบ Numbering แยกต่างหาก
  • ต้องพิจารณาร่วมกับ RFA ที่เกี่ยวข้อง

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
{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
{YYYY} ปี 4 หลัก 2025 Current year
{YY} ปี 2 หลัก 25 Current year (short)
{MM} เดือน 2 หลัก 01-12 Current month
{CONTRACT} รหัสสัญญา C001 contracts.contract_code

Token Usage Notes

{SEQ:n}:

  • n = จำนวนหลักที่ต้องการ (typically 4-6)
  • Counter เริ่มจาก 0001 และเพิ่มทีละ 1 (0001, 0002, 0003, ...)
  • Padding ด้วย 0 ทางซ้าย
  • Reset ทุกปี (ตาม reset_scope ใน Counter Key)

{RECIPIENT}:

  • ใช้เฉพาะผู้รับที่มี recipient_type = 'TO' เท่านั้น
  • ถ้ามีหลาย TO ให้ใช้คนแรก (ตาม sort order)
  • ไม่ใช้สำหรับ RFA (RFA ไม่มี {RECIPIENT} ใน template)

{CORR_TYPE}:

  • รองรับทุกค่าจาก correspondence_types.type_code
  • ถ้ามีการเพิ่มประเภทใหม่ จะใช้งานได้ทันที
  • แสดงใน template: RFA only
  • ไม่แสดงแต่ใช้ใน counter: LETTER, TRANSMITTAL, และ Other types

Deprecated Tokens (ไม่ควรใช้):

  • {ORG} → ใช้ {ORIGINATOR} หรือ {RECIPIENT} แทน
  • {TYPE} → ใช้ {CORR_TYPE}, {SUB_TYPE}, หรือ {RFA_TYPE} แทน (ตามบริบท)
  • {CATEGORY} → ไม่ได้ใช้งานในระบบปัจจุบัน

3.11.5 Character & Format Rules (Updated)

BR-DN-002 (Revised)

  • Document number must be printable UTF8
  • 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

3.11.6 Number State Machine (New)

States

RESERVED → CONFIRMED → VOID
           ↘ CANCELLED

Rules

  • RESERVED:
    • TTL 5 minutes
    • Auto-expire → CANCELLED
  • CONFIRMED:
    • Linked to document_id
  • VOID:
    • Only CONFIRMED numbers
    • Replacement creates new number

3.11.7 Idempotency (New)

API Requirement

  • All number generation APIs must support:
Idempotency-Key: UUID

Behavior

  • 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::<project>::<contract>
  • Prevents collision with correspondence/RFA

3.11.9 Token Validation Grammar (New)

EBNF

TEMPLATE     := TOKEN ("-" TOKEN)*
TOKEN        := SIMPLE | PARAM
SIMPLE       := "{PROJECT}" | "{ORIGINATOR}" | "{RECIPIENT}" |
                "{CORR_TYPE}" | "{DISCIPLINE}" | "{RFA_TYPE}" |
                "{REV}" | "{YYYY}" | "{YY}" | "{MM}"
PARAM        := "{SEQ:" DIGIT+ "}"
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

3.11.10 Functional Requirements

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 โดยไม่มีเลขที่ซ้ำ
  • Response time < 100ms (p95)

FR-DN-002: Configurable Number Format

Priority: HIGH | Status: Required

Description: ระบบต้องรองรับการกำหนดรูปแบบเลขที่เอกสารที่หลากหลาย

Acceptance Criteria:

  • รองรับ format tokens ที่ระบุ
  • Admin สามารถกำหนด format ผ่าน UI ได้
  • Validate format ก่อน save
  • แสดง preview ของเลขที่ที่จะถูกสร้าง

FR-DN-003: Scope-based Sequences

Priority: HIGH | Status: Required

Description: ระบบต้องรองรับการสร้าง sequence ที่แยกตาม scope ที่ต่างกัน

Acceptance Criteria:

  • เลขที่ไม่ซ้ำภายใน scope เดียวกัน
  • Scope ที่ต่างกันสามารถมีเลขที่เดียวกันได้
  • Support multiple active scopes

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
  • บันทึก audit log ว่าเป็น manual override
  • ต้องมีสิทธิ์ Admin ขึ้นไปเท่านั้น

FR-DN-005: Bulk Import Support

Priority: MEDIUM | Status: Required

Description: ระบบต้องรองรับการ import เอกสารหลายรายการพร้อมกัน

Acceptance Criteria:

  • รองรับไฟล์ CSV/Excel
  • Validate ทุกรายการก่อน import
  • แสดง preview ก่อน confirm
  • Rollback ทั้งหมดถ้ามีรายการใดผิดพลาด (transactional)
  • Auto-update sequence counters หลัง import
  • Generate import report

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 เมื่อสร้างเลขที่ใหม่
  • บันทึกเหตุผลการยกเลิก
  • แสดง cancelled numbers ใน audit trail

FR-DN-007: Void and Replace

Priority: HIGH | Status: Required

Description: ระบบต้องรองรับการ void เอกสารและสร้างเอกสารใหม่แทน

Workflow:

  1. User เลือกเอกสารที่ต้องการ void
  2. ระบุเหตุผล (required)
  3. ระบบเปลี่ยน status เอกสารเดิมเป็น VOID
  4. สร้างเอกสารใหม่ด้วยเลขที่ใหม่
  5. Link เอกสารใหม่กับเดิม (voided_from_id)

Acceptance Criteria:

  • เอกสารเดิม status = VOID (ไม่ลบ)
  • เอกสารใหม่ได้เลขที่ต่อเนื่องจาก sequence
  • มี reference link ระหว่างเอกสาร
  • บันทึก void reason
  • แสดง void history chain (A→B→C)

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)
  • Timeout handling (30 seconds)

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
  • Manual override
  • Void document
  • Sequence adjusted
  • Format changed

Acceptance Criteria:

  • Log ทุก operation
  • Searchable by user, date, type
  • Export to CSV
  • Retain for 7 years

FR-DN-011: Metrics & Alerting

Priority: MEDIUM | Status: Required

Description: แสดงสถิติและส่ง alert เมื่อเกิดปัญหา

Metrics:

  • Sequence utilization (% of max)
  • Average lock wait time
  • Failed lock attempts
  • Numbers generated per day
  • Manual overrides per day

Alerts:

  • Sequence >90% used (WARNING)
  • Sequence >95% used (CRITICAL)
  • Lock wait time >1s (WARNING)
  • Redis unavailable (CRITICAL)
  • High error rate (WARNING)

3.11.11 Database Schema (Corrected)

3.11.11.1 document_number_counters

CREATE TABLE document_number_counters (
  project_id INT NOT NULL,
  correspondence_type_id INT NULL,-- NULL = default format for project
  originator_organization_id INT NOT NULL,
  recipient_organization_id INT NOT NULL DEFAULT 0, -- 0 = no recipient (RFA)
  sub_type_id INT DEFAULT 0,
  rfa_type_id INT DEFAULT 0,
  discipline_id INT DEFAULT 0,
  reset_scope VARCHAR(20) NOT NULL,
  last_number INT DEFAULT 0 NOT NULL,
  version INT DEFAULT 0 NOT NULL,
  created_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
  updated_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  PRIMARY KEY (
    project_id,
    originator_organization_id,
    recipient_organization_id,
    correspondence_type_id,
    sub_type_id,
    rfa_type_id,
    discipline_id,
    reset_scope
  ),

  FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
  FOREIGN KEY (originator_organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
  FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci
  COMMENT = 'ตารางเก็บ Running Number Counters';

Rules

  • RFA → recipient_organization_id = 0
  • Reset:
    • Yearly: reset_scope = 'YEAR_2025'
    • No reset: reset_scope = 'NONE'

3.11.11.2 Index Requirements

-- Index สำหรับ Performance
CREATE INDEX idx_counter_lookup
ON document_number_counters (
  project_id,
  correspondence_type_id,
  reset_scope
);

-- Index สำหรับ Originator lookup
CREATE INDEX idx_counter_org
ON document_number_counters (
  originator_organization_id,
  reset_scope
);

-- Index สำหรับ updated_at
CREATE INDEX idx_counter_updated
ON document_number_counters (
  updated_at
);

3.11.11.3 Numbering Configuration Table

CREATE TABLE document_numbering_configs (
  id INT PRIMARY KEY AUTO_INCREMENT,
  document_type VARCHAR(50) NOT NULL,
  format VARCHAR(200) NOT NULL,
  scope ENUM('GLOBAL','PROJECT','CONTRACT','YEARLY','MONTHLY'),
  allow_manual_override BOOLEAN DEFAULT FALSE,
  max_value INT DEFAULT 999999,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY (document_type, scope)
);

3.11.11.4 Audit Log Table

CREATE TABLE document_number_audit (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  document_id INT NOT NULL,
  document_type VARCHAR(50),
  document_number VARCHAR(100) NOT NULL,
  operation ENUM('RESERVE', 'CONFIRM', 'CANCEL', 'MANUAL_OVERRIDE', 'VOID', 'GENERATE') NOT NULL,
  status ENUM('RESERVED', 'CONFIRMED', 'CANCELLED', 'VOID', 'MANUAL'),
  counter_key JSON NOT NULL COMMENT 'Counter key used (JSON format)',
  reservation_token VARCHAR(36) NULL,
  originator_organization_id INT NULL,
  recipient_organization_id INT NULL,

  template_used VARCHAR(200) NOT NULL,
  old_value TEXT NULL,
  new_value TEXT NULL,

  user_id INT NOT NULL,
  ip_address VARCHAR(45),
  user_agent TEXT,
  is_success BOOLEAN DEFAULT TRUE,

  -- Performance & Error Tracking
  retry_count INT DEFAULT 0,
  lock_wait_ms INT COMMENT 'Lock acquisition time in milliseconds',
  total_duration_ms INT COMMENT 'Total generation time',
  fallback_used ENUM('NONE', 'DB_LOCK', 'RETRY') DEFAULT 'NONE',
  metadata JSON NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

  INDEX idx_document_id (document_id),
  INDEX idx_user_id (user_id),
  INDEX idx_status (status),
  INDEX idx_operation (operation),
  INDEX idx_document_number (document_number),
  INDEX idx_reservation_token (reservation_token);
  INDEX idx_created_at (created_at),
  FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB COMMENT='Document Number Generation Audit Trail';

3.11.11.5 Reservation Table

CREATE TABLE document_number_reservations (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,

  -- Reservation Details
  token VARCHAR(36) NOT NULL UNIQUE COMMENT 'UUID v4',
  document_number VARCHAR(100) NOT NULL UNIQUE,
  status ENUM('RESERVED', 'CONFIRMED', 'CANCELLED', 'VOID') NOT NULL DEFAULT 'RESERVED',

  -- Linkage
  document_id INT NULL COMMENT 'FK to documents (NULL until confirmed)',

  -- Context (for debugging)
  project_id INT NOT NULL,
  correspondence_type_id INT NOT NULL,
  originator_organization_id INT NOT NULL,
  recipient_organization_id INT DEFAULT 0,
  user_id INT NOT NULL,

  -- Timestamps
  reserved_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
  expires_at DATETIME(6) NOT NULL,
  confirmed_at DATETIME(6) NULL,
  cancelled_at DATETIME(6) NULL,

  -- Audit
  ip_address VARCHAR(45),
  user_agent TEXT,
  metadata JSON NULL COMMENT 'Additional context',

  -- Indexes
  INDEX idx_token (token),
  INDEX idx_status (status),
  INDEX idx_status_expires (status, expires_at),
  INDEX idx_document_id (document_id),
  INDEX idx_user_id (user_id),
  INDEX idx_reserved_at (reserved_at),

  -- Foreign Keys
  FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE SET NULL,
  FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
  FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
  COMMENT='Document Number Reservations - Two-Phase Commit';

3.11.11.5 Error Log Table

CREATE TABLE document_number_errors (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  error_type ENUM(
    'LOCK_TIMEOUT',
    'VERSION_CONFLICT',
    'DB_ERROR',
    'REDIS_ERROR',
    'VALIDATION_ERROR'
  ) NOT NULL,
  error_message TEXT,
  stack_trace TEXT,
  context_data JSON COMMENT 'Request context (user, project, etc.)',
  user_id INT,
  ip_address VARCHAR(45),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  resolved_at TIMESTAMP NULL,

  INDEX idx_error_type (error_type),
  INDEX idx_created_at (created_at),
  INDEX idx_user_id (user_id)
) ENGINE=InnoDB COMMENT='Document Numbering Error Log';

3.11.11.6 Config History Table

CREATE TABLE document_number_config_history (
  id INT AUTO_INCREMENT PRIMARY KEY,
  config_id INT NOT NULL,
  template_before TEXT,
  template_after TEXT NOT NULL,
  changed_by INT NOT NULL,
  changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  change_reason TEXT,

  FOREIGN KEY (config_id) REFERENCES document_number_configs(id),
  FOREIGN KEY (changed_by) REFERENCES users(id)
) ENGINE=InnoDB COMMENT='Template Change 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 ก่อน

3.11.11.8 Example Counter Records

-- Example: LETTER from คคง. to สคฉ.3 in LCBP3-C2 year 2025
INSERT INTO document_number_counters (
  project_id, originator_organization_id, recipient_organization_id,
  correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
  reset_scope, version, last_number
) VALUES (
  2,      -- LCBP3-C2
  22,     -- คคง.
  10,     -- สคฉ.3
  6,      -- LETTER
  0, 0, 0,
  'YEAR_2025', 0, 0
);

-- Example: RFA from ผรม.2 in LCBP3-C2, discipline TER, type RPT, year 2025
INSERT INTO document_number_counters (
  project_id, originator_organization_id, recipient_organization_id,
  correspondence_type_id, sub_type_id, rfa_type_id, discipline_id,
  reset_scope, version, last_number
) VALUES (
  2,      -- LCBP3-C2
  42,     -- ผรม.2
  0,      -- RFA ไม่มี specific recipient
  1,      -- RFA
  0,
  18,     -- RPT (Report)
  5,      -- TER (Terminal)
  'NONE', 0, 0  -- No yearly reset for RFA
);

3.11.12 Security & Data Integrity Requirements

3.11.12.1 Concurrency Control

Requirements:

  • ระบบต้องป้องกัน race condition เมื่อมีการสร้างเลขที่เอกสารพร้อมกัน
  • ระบบต้องรับประกัน uniqueness ของเลขที่เอกสารในทุกสถานการณ์
  • ระบบควรใช้ Distributed Lock (Redis) เป็นกลไก primary
  • ระบบต้องมี fallback mechanism เมื่อ Redis ไม่พร้อมใช้งาน

3.11.12.2 Data Integrity

Requirements:

  • ระบบต้องใช้ Optimistic Locking เพื่อตรวจจับ concurrent updates
  • ระบบต้องมี database constraints เพื่อป้องกันข้อมูลผิดพลาด:
    • Unique constraint บน document_number
    • Foreign key constraints ทุก relationship
    • Check constraints สำหรับ business rules

3.11.12.3 Authorization

Requirements:

  • เฉพาะ authenticated users เท่านั้นที่สามารถ request document number
  • เฉพาะ Project Admin เท่านั้นที่แก้ไข template ได้
  • เฉพาะ Super Admin เท่านั้นที่ reset counter ได้ (requires approval)

3.11.12.4 Rate Limiting

Requirements:

  • Limit ต่อ user: 10 requests/minute (prevent abuse)
  • Limit ต่อ IP: 50 requests/minute

3.11.13 Error Handling Requirements

3.11.13.1 Retry Mechanism

Requirements:

ระบบต้องจัดการ error scenarios ต่อไปนี้:

Scenario Strategy Max Retries Expected Response
Redis Unavailable Fallback to DB Lock 0 Continue (degraded performance)
Lock Timeout Exponential Backoff 5 HTTP 503 after final retry
Version Conflict Immediate Retry 2 HTTP 409 after final retry
DB Connection Error Exponential Backoff 3 HTTP 500 after final retry

3.11.13.2 User Experience

Requirements:

  • Error messages ต้องเป็นภาษาไทย และเข้าใจง่าย
  • HTTP status codes ต้องสื่อความหมายที่ถูกต้อง
  • Frontend ควรแสดง retry option สำหรับ transient errors

3.11.14 Configuration Management Requirements

3.11.14.1 Template Management

Requirements:

  • Project Admin ต้องสามารถกำหนด/แก้ไข template ผ่าน Admin Panel
  • ระบบต้องvalidate template ก่อนบันทึก
  • การเปลี่ยนแปลง template ต้องไม่ส่งผลต่อเอกสารที่สร้างไว้แล้ว

3.11.14.2 Template Versioning

Requirements:

  • ระบบต้องเก็บ history ของ template changes
  • ระบบต้องบันทึก user, timestamp, และเหตุผลในการเปลี่ยนแปลง
  • ระบบควรสามารถ rollback ไปเวอร์ชันก่อนหน้าได้

3.11.14.3 Counter Reset Policy

Requirements:

  • Counter ต้องreset ตามปี (อัตโนมัติ)
  • Admin ต้องสามารถ manual reset counter ได้ (require approval + audit log)

3.11.15 Audit Trail Requirements

3.11.15.1 Audit Logging

Requirements:

ระบบต้องบันทึกข้อมูลต่อไปนี้สำหรับทุก document number generation:

  • document_id - เอกสารที่ถูกสร้าง
  • generated_number - เลขที่ถูกสร้าง
  • counter_key - key ที่ใช้ในการนับ (JSON format)
  • template_used - template ที่ใช้
  • user_id - ผู้ที่ request
  • ip_address - IP address ของผู้ request
  • timestamp - เวลาที่สร้าง
  • retry_count - จำนวนครั้งที่ retry
  • performance_metrics - Lock wait time, total duration

3.11.15.2 Error Logging

Requirements:

  • ระบบต้องบันทึก error แยกต่างหาก พร้อม error type classification
  • ระบบควรalert ops team สำหรับ critical errors

3.11.15.3 Retention Policy

Requirements:

  • Audit log ต้องเก็บอย่างน้อย 7 ปี (ตาม พ.ร.บ. ข้อมูลอิเล็กทรอนิกส์)

3.11.16 Performance Requirements

3.11.16.1 Response Time

SLA Targets:

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

3.11.16.2 Throughput

Capacity Targets:

Load Level Target Notes
Normal load ≥ 50 req/s ใช้งานปกติ
Peak load ≥ 100 req/s ช่วงเร่งงาน
Burst ≥ 200 req/s short duration
Support > 500 req/s Scale horizontally

3.11.16.3 Availability

SLA Targets:

  • Uptime: ≥ 99.5% (excluding planned maintenance)
  • Maximum downtime: ≤ 3.6 ชั่วโมง/เดือน
  • RTO: ≤ 30 นาที
  • RPO: ≤ 5 นาที
  • Graceful degradation: Fallback to DB-only
  • Auto-recovery: From Redis failure

3.11.17 Monitoring & Alerting Requirements

3.11.17.1 Metrics

Requirements:

ระบบต้องcollect metrics ต่อไปนี้:

  • Lock acquisition time (p50, p95, p99)
  • Lock acquisition success/failure rate
  • Counter generation latency
  • Retry count distribution
  • Redis connection status
  • Database connection pool usage
  • Sequence utilization (% of max)
  • Numbers generated per day
  • Manual overrides per day

3.11.17.2 Alerts

Requirements:

ระบบต้องalert สำหรับ conditions ต่อไปนี้:

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
🟡 Warning Lock failures > 5% in 5 min Slack
🟡 Warning Avg lock wait time > 1 sec Slack
🟡 Warning Retry count > 100/hour Slack
🟡 Warning Sequence >90% used Slack
🟡 Warning High error rate Slack

3.11.17.3 Dashboard

Requirements:

  • Ops team ต้องมี real-time dashboard (Grafana) แสดง:
    • Lock acquisition success rate
    • Lock wait time percentiles
    • Generation rate (per minute)
    • Error rate by type
    • Connection health status
    • Retry distribution

3.11.18 API Reference

Document Number Generation

POST /api/v1/documents/{documentId}/generate-number

สร้างเลขที่เอกสารสำหรับ document ที่ระบุ

Request Body:

{
  "counterKey": {
    "projectId": 2,
    "originatorOrgId": 22,
    "recipientOrgId": 10,
    "correspondenceTypeId": 6,
    "subTypeId": 0,
    "rfaTypeId": 0,
    "disciplineId": 0,
    "resetScope": "YEAR_2025"
  }
}

Response:

{
  "documentNumber": "คคง.-สคฉ.3-0001-2568",
  "generatedAt": "2025-12-02T15:30:00Z"
}

Reserve Number

POST /api/document-numbering/reserve

Request:

{
  "document_type": "COR",
  "project_id": 1,
  "contract_id": null,
  "metadata": {}
}

Response 201:

{
  "token": "uuid-v4",
  "document_number": "COR-2025-00042",
  "expires_at": "2025-01-16T10:30:00Z"
}

Confirm Reservation

POST /api/document-numbering/confirm

Request:

{
  "token": "uuid-v4"
}

Response 200:

{
  "document_number": "COR-2025-00042",
  "confirmed_at": "2025-01-16T10:25:00Z"
}

Manual Override

POST /api/document-numbering/manual
Authorization: Bearer <admin-token>

Request:

{
  "document_type": "COR",
  "document_number": "COR-2024-99999",
  "reason": "Import from legacy system",
  "skip_validation": false
}

Response 201:

{
  "document_number": "COR-2024-99999",
  "is_manual": true,
  "created_at": "2025-01-16T10:25:00Z"
}

Template Management

GET /api/v1/document-numbering/configs

ดูรายการ template configuration ทั้งหมด

PUT /api/v1/document-numbering/configs/{configId}

แก้ไข template (Project Admin only)

POST /api/v1/document-numbering/configs/{configId}/reset-counter

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
  • Bulk import

3.11.19.3 Load Tests

# Must pass without duplicates
concurrent_users: 100
requests_per_second: 500
test_duration: 5 minutes
expected_duplicates: 0
  • Concurrent number generation (1000 req/s)
  • Lock contention under load
  • Redis failover scenarios
  • Database connection pool exhaustion

3.11.19.4 E2E Tests

  • Complete document creation flow
  • Void and replace workflow
  • Bulk import with validation
  • Admin configuration UI

3.11.20 Versioning Note

  • 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
  4. Update sequence counters to max values
  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
  • Week 5+: Monitor and optimize

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
  • System stability >99.9%

3.11.23 References


3.11.24 Appendix

3.11.24.1 Glossary

  • Sequence: ลำดับตัวเลขที่เพิ่มขึ้นอัตโนมัติ
  • Scope: ขอบเขตที่ sequence แยกตาม (project, contract, etc.)
  • Token: Format placeholder (e.g., {YYYY}, {SEQ})
  • Redlock: Distributed locking algorithm สำหรับ Redis

Approval Sign-off:

Role Name Date Signature
Product Owner ___________ _______ _________
Tech Lead ___________ _______ _________
QA Lead ___________ _______ _________

End of Document v1.6.2