Files
lcbp3/specs/99-archives/docs/20251224-document-numbering-summary.md
admin 158179d4a5
All checks were successful
Build and Deploy / deploy (push) Successful in 6m25s
260224:1606 20260224:1600 V1.8.0
2026-02-24 16:06:15 +07:00

400 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 📋 Document Numbering System Summary
> **Version:** v1.7.0
> **Last Updated:** 2025-12-24
> **Status:** Implemented (with known build issues)
---
## 📊 Architecture Overview
ระบบ Document Numbering ใช้สำหรับสร้างเลขที่เอกสารอัตโนมัติ โดยมี **Reserve-Confirm Pattern** และ **Two-Phase Locking** (Redis + DB Optimistic Lock) เพื่อป้องกัน Race Conditions
```mermaid
flowchart TB
subgraph Frontend["Frontend (Next.js)"]
A[lib/api/numbering.ts]
B[components/numbering/*]
C[types/dto/numbering.dto.ts]
end
subgraph Backend["Backend (NestJS)"]
D[Controllers]
E[DocumentNumberingService]
F[Sub-Services]
G[Entities]
end
A --> D
B --> A
E --> F
E --> G
```
---
## 📁 Backend Structure
### Module Location
`backend/src/modules/document-numbering/`
| Directory | Files | Description |
| -------------- | ----- | ----------------------------------------------------------------------------------- |
| `controllers/` | 3 | Public, Admin, Metrics Controllers |
| `services/` | 8 | Main + Counter, Reservation, Format, Lock, Template, Audit, Metrics, ManualOverride |
| `entities/` | 5 | Format, Counter, Reservation, Audit, Error |
| `dto/` | 5 | Preview, Reserve, ConfirmReservation, CounterKey, ManualOverride |
| `interfaces/` | 1 | GenerateNumberContext |
### Key Services
| Service | Responsibility |
| ------------------------------ | -------------------------------------------------------------------- |
| `DocumentNumberingService` | Main orchestrator (generateNextNumber, reserveNumber, previewNumber) |
| `CounterService` | Increment counter with Optimistic Lock |
| `ReservationService` | Reserve-Confirm pattern handling |
| `FormatService` | Token replacement & format resolution |
| `DocumentNumberingLockService` | Redis distributed lock (Redlock) |
| `ManualOverrideService` | Admin counter override |
| `AuditService` | Audit logging |
| `MetricsService` | Prometheus metrics |
---
## 📁 Frontend Structure
### Files
| Path | Description |
| -------------------------------------------- | ------------------------------ |
| `lib/api/numbering.ts` | API client + Types (335 lines) |
| `lib/services/document-numbering.service.ts` | Service wrapper |
| `types/dto/numbering.dto.ts` | DTOs for forms |
| `types/numbering.ts` | Type re-exports |
### Components (`components/numbering/`)
| Component | Description |
| -------------------------- | --------------------------- |
| `template-editor.tsx` | Editor for format templates |
| `template-tester.tsx` | Test number generation |
| `sequence-viewer.tsx` | View counter sequences |
| `metrics-dashboard.tsx` | Audit/Error logs dashboard |
| `manual-override-form.tsx` | Admin counter override |
| `void-replace-form.tsx` | Void & Replace number |
| `cancel-number-form.tsx` | Cancel/Skip a number |
| `bulk-import-form.tsx` | Bulk import counters |
| `audit-logs-table.tsx` | Audit logs table |
### Admin Pages
- `app/(admin)/admin/numbering/` - Template management
- `app/(admin)/admin/system-logs/numbering/` - System logs
---
## 💾 Database Schema (v1.7.0)
### 5 Tables
| Table | Purpose | Key Feature |
| ------------------------------ | ------------------------- | ------------------------------------------- |
| `document_number_formats` | Template รูปแบบเลขที่เอกสาร | Unique per (project, correspondence_type) |
| `document_number_counters` | Running Number Counter | **8-Column Composite PK** + Optimistic Lock |
| `document_number_audit` | Audit Trail สำหรับทุกการสร้าง | เก็บ ≥ 7 ปี |
| `document_number_errors` | Error Log | 5 Error Types |
| `document_number_reservations` | **Two-Phase Commit** | Reserve → Confirm Pattern |
---
## 🔑 Counter Composite Primary Key (8 Columns)
```sql
PRIMARY KEY (
project_id,
originator_organization_id,
recipient_organization_id, -- 0 = no recipient (RFA)
correspondence_type_id,
sub_type_id, -- 0 = ไม่ระบุ (for TRANSMITTAL)
rfa_type_id, -- 0 = ไม่ใช่ RFA
discipline_id, -- 0 = ไม่ระบุ
reset_scope -- 'YEAR_2024', 'NONE', etc.
)
```
### Reset Scope Values
| Value | Description |
| --------------- | -------------------------------- |
| `YEAR_XXXX` | Reset ทุกปี เช่น `YEAR_2024` |
| `MONTH_XXXX_XX` | Reset ทุกเดือน เช่น `MONTH_2024_01` |
| `CONTRACT_XXXX` | Reset ต่อสัญญา |
| `NONE` | ไม่ Reset |
### Constraints
```sql
CONSTRAINT chk_last_number_positive CHECK (last_number >= 0)
CONSTRAINT chk_reset_scope_format CHECK (
reset_scope IN ('NONE')
OR reset_scope LIKE 'YEAR_%'
OR reset_scope LIKE 'MONTH_%'
OR reset_scope LIKE 'CONTRACT_%'
)
```
---
## 📜 Business Rules
### 1⃣ Number Generation Rules
| Rule | Description |
| ----------------------------- | ---------------------------------------------------- |
| **Uniqueness** | เลขที่เอกสารห้ามซ้ำกันภายใน Project |
| **Sequence Reset** | Reset ตาม `reset_scope` (ปกติ Reset ต่อปี) |
| **Idempotency** | ใช้ `Idempotency-Key` header ป้องกันการสร้างซ้ำ |
| **Race Condition Prevention** | Redis Lock (Primary) + DB Optimistic Lock (Fallback) |
| **Format Fallback** | ใช้ Default Format ถ้าไม่มี Specific Format |
### 2⃣ Two-Phase Commit (Reserve → Confirm)
```mermaid
stateDiagram-v2
[*] --> RESERVED: Reserve Number
RESERVED --> CONFIRMED: Confirm (Save Document)
RESERVED --> CANCELLED: Cancel / Timeout (15 min)
CONFIRMED --> VOID: Admin Void
VOID --> [*]
CANCELLED --> [*]
```
| Status | Description |
| ----------- | ----------------------------------- |
| `RESERVED` | จองแล้ว รอ Confirm (หมดอายุใน 15 นาที) |
| `CONFIRMED` | ยืนยันแล้ว ใช้งานจริง |
| `CANCELLED` | ยกเลิก (User/System/Timeout) |
| `VOID` | Admin Void (ยกเลิกเลขที่หลัง Confirm) |
### 3⃣ Format Template Tokens
| Token | Example Value | Description |
| -------------- | ------------- | ---------------------------- |
| `{PROJECT}` | `LCBP3` | Project Code |
| `{ORG}` | `NAP` | Originator Organization Code |
| `{RECIPIENT}` | `PAT` | Recipient Organization Code |
| `{TYPE}` | `LET` | Correspondence Type Code |
| `{DISCIPLINE}` | `STR` | Discipline Code |
| `{SEQ:N}` | `0001` | Sequence padded to N digits |
| `{YEAR}` | `2025` | 4-digit CE Year |
| `{YEAR:BE}` | `2568` | 4-digit Buddhist Era Year |
| `{REV}` | `0` | Revision Number |
### Example Format
```
Template: {ORG}-{RECIPIENT}-{TYPE}-{YEAR:BE}-{SEQ:4}
Result: NAP-PAT-LET-67-0001
```
### 4⃣ Format Resolution Priority
1. **Specific Format**: project_id + correspondence_type_id
2. **Default Format**: project_id + correspondence_type_id = NULL
3. **Fallback**: `{ORG}-{RECIPIENT}-{SEQ:4}-{YEAR:BE}`
---
## 🛡️ Concurrency Control Strategy
```mermaid
sequenceDiagram
participant API
participant Redis
participant DB
API->>Redis: Acquire Lock (TTL: 5s)
alt Redis Lock Success
API->>DB: SELECT counter + UPDATE (increment)
API->>Redis: Release Lock
else Redis Lock Failed/Timeout
Note over API,DB: Fallback to DB Optimistic Lock
API->>DB: SELECT FOR UPDATE + INCREMENT
API->>DB: Check version (Optimistic Lock)
end
```
| Strategy | Use Case |
| ---------------------- | ------------------------------------------- |
| **Redis Redlock** | Primary - Distributed Lock across instances |
| **DB Optimistic Lock** | Fallback - When Redis down/timeout |
| **Version Column** | Prevent concurrent updates |
---
## 🔄 Generation Flow
```mermaid
sequenceDiagram
participant Client
participant Controller
participant Service
participant RedisLock
participant CounterService
participant FormatService
participant DB
Client->>Controller: POST /preview or Reserve
Controller->>Service: generateNextNumber(ctx)
Service->>RedisLock: acquireLock(counterKey)
Service->>CounterService: incrementCounter(key)
CounterService->>DB: SELECT FOR UPDATE + INCREMENT
DB-->>CounterService: sequence
CounterService-->>Service: sequence
Service->>FormatService: format(options)
FormatService->>DB: Lookup (Project, Type, Org, Discipline)
FormatService-->>Service: formattedNumber
Service->>DB: save AuditLog
Service->>RedisLock: releaseLock()
Service-->>Controller: { number, auditId }
Controller-->>Client: Response
```
---
## 🔌 API Endpoints
### Public (`/document-numbering`)
| Method | Endpoint | Permission | Description |
| ------ | --------------- | ------------------------ | --------------------------- |
| POST | `/preview` | `correspondence.read` | Preview เลขที่ (ไม่ increment) |
| GET | `/sequences` | `correspondence.read` | ดู Counter ทั้งหมด |
| GET | `/logs/audit` | `system.view_logs` | Audit Logs |
| GET | `/logs/errors` | `system.view_logs` | Error Logs |
| PATCH | `/counters/:id` | `system.manage_settings` | Update Counter (Deprecated) |
### Admin (`/admin/document-numbering`)
| Method | Endpoint | Description |
| ------ | ------------------------ | --------------------------- |
| GET | `/templates` | ดู Templates ทั้งหมด |
| GET | `/templates?projectId=X` | ดู Templates ตาม Project |
| POST | `/templates` | สร้าง/แก้ไข Template |
| DELETE | `/templates/:id` | ลบ Template |
| GET | `/metrics` | Audit + Error Logs combined |
| POST | `/manual-override` | Override Counter Value |
| POST | `/void-and-replace` | Void + สร้างเลขใหม่ |
| POST | `/cancel` | ยกเลิกเลขที่ |
| POST | `/bulk-import` | Import Counters จาก Legacy |
---
## 📈 Audit & Monitoring
### Audit Log Operations
| Operation | Description |
| ----------------- | ------------------ |
| `RESERVE` | จองเลขที่ |
| `CONFIRM` | ยืนยันการใช้เลขที่ |
| `MANUAL_OVERRIDE` | Admin แก้ไข Counter |
| `VOID_REPLACE` | Void และสร้างใหม่ |
| `CANCEL` | ยกเลิกเลขที่ |
### Audit Log Fields
| Field | Description |
| ------------------- | ----------------------------- |
| `counter_key` | JSON 8 fields (Composite Key) |
| `reservation_token` | UUID v4 สำหรับ Reserve-Confirm |
| `idempotency_key` | Request Idempotency Key |
| `template_used` | Format Template ที่ใช้ |
| `retry_count` | จำนวนครั้งที่ retry |
| `lock_wait_ms` | เวลารอ Redis lock (ms) |
| `total_duration_ms` | เวลารวมทั้งหมด (ms) |
| `fallback_used` | NONE / DB_LOCK / RETRY |
### Error Types
| Type | Description |
| ------------------ | ------------------------------- |
| `LOCK_TIMEOUT` | Redis lock หมดเวลา |
| `VERSION_CONFLICT` | Optimistic lock fail |
| `DB_ERROR` | Database error |
| `REDIS_ERROR` | Redis connection error |
| `VALIDATION_ERROR` | Template/Input validation error |
### Prometheus Metrics
| Metric | Type | Description |
| -------------------------------- | --------- | ----------------------------- |
| `numbering_sequences_total` | Counter | Total sequences generated |
| `numbering_sequence_utilization` | Gauge | Utilization of sequence space |
| `numbering_lock_wait_seconds` | Histogram | Time waiting for locks |
| `numbering_lock_failures_total` | Counter | Lock acquisition failures |
---
## 🔐 Permissions
| Permission | Description |
| ------------------------ | --------------------------------------------- |
| `correspondence.read` | Preview, View Sequences |
| `system.view_logs` | View Audit/Error Logs |
| `system.manage_settings` | Template CRUD, Override, Void, Cancel, Import |
---
## ⚠️ Known Issues (Current Build)
### TypeScript Errors
1. **DTO Field Mismatch**
- `PreviewNumberDto.originatorId` vs Service expects `originatorOrganizationId`
2. **Missing Properties in PreviewNumberDto**
- `correspondenceTypeId` (used as `typeId`)
- `customTokens`
3. **TypeScript Initializers**
- DTOs need `!` or default values for strict mode
### Files Needing Fix
- `dto/preview-number.dto.ts`
- `dto/reserve-number.dto.ts`
- `dto/confirm-reservation.dto.ts`
- `dto/counter-key.dto.ts`
- `entities/document-number-format.entity.ts`
- `entities/document-number-error.entity.ts`
- `services/document-numbering.service.ts`
---
## 📚 Related Documentation
- [specs/01-requirements/03.11-document-numbering.md](../specs/01-requirements/03.11-document-numbering.md)
- [specs/03-implementation/document-numbering.md](../specs/03-implementation/document-numbering.md)
- [specs/07-database/data-dictionary-v1.7.0.md](../specs/07-database/data-dictionary-v1.7.0.md)
- [specs/07-database/lcbp3-v1.7.0-schema.sql](../specs/07-database/lcbp3-v1.7.0-schema.sql)
---
## 📝 Changelog
### v1.7.0
- Changed `document_number_counters` PK from 5 to **8 columns**
- Added `document_number_reservations` table for Two-Phase Commit
- Added `reset_scope` field (replaces `current_year`)
- Enhanced `document_number_audit` with operation tracking
- Added `idempotency_key` support
### v1.5.1
- Initial implementation
- Basic format templating
- Counter management
---
**End of Document**