251225:1703 On going update to 1.7.0: Refoctory drawing Module not finish
This commit is contained in:
399
docs/20251224-document-numbering-summary.md
Normal file
399
docs/20251224-document-numbering-summary.md
Normal file
@@ -0,0 +1,399 @@
|
||||
# 📋 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**
|
||||
Reference in New Issue
Block a user