251208:1625 Frontend: to be complete admin panel, Backend: tobe recheck all task
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
|
||||
1. **Database Schema:**
|
||||
|
||||
- ✅ ทุกตารางถูกสร้างตาม Data Dictionary v1.4.5
|
||||
- ✅ ทุกตารางถูกสร้างตาม Data Dictionary v1.5.1
|
||||
- ✅ Foreign Keys ถูกต้องครบถ้วน
|
||||
- ✅ Indexes ครบตาม Specification
|
||||
- ✅ Virtual Columns สำหรับ JSON fields
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Document Numbering Service
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** Ready for Implementation
|
||||
**Priority:** P1 (High - Critical for Documents)
|
||||
**Estimated Effort:** 7-8 days
|
||||
**Dependencies:** TASK-BE-001 (Database), TASK-BE-002 (Auth), TASK-BE-003 (Redis Setup)
|
||||
@@ -50,14 +50,18 @@
|
||||
- ✅ Fallback to DB pessimistic lock when Redis unavailable
|
||||
- ✅ Retry with exponential backoff (5 retries max for lock, 2 for version conflict, 3 for DB errors)
|
||||
|
||||
### 3. Document Types Support
|
||||
### 3. Document Types Support & Scoping
|
||||
|
||||
- ✅ LETTER / RFI / MEMO / EMAIL / MOM / INSTRUCTION / NOTICE / OTHER
|
||||
- ✅ **General Correspondence** (LETTER / MEMO / etc.) → **Project Level Scope**
|
||||
- Counter Key: `(project_id, originator_org_id, recipient_org_id, corr_type_id, 0, 0, 0, year)`
|
||||
- ✅ TRANSMITTAL
|
||||
- *Note*: Templates separate per Project. `{PROJECT}` token is optional in format but counter is partitioned by Project.
|
||||
|
||||
- ✅ **Transmittal** → **Project Level Scope** with Sub-Type lookup
|
||||
- Counter Key: `(project_id, originator_org_id, recipient_org_id, corr_type_id, sub_type_id, 0, 0, year)`
|
||||
- ✅ RFA
|
||||
|
||||
- ✅ **RFA** → **Contract Level Scope** (Implicit)
|
||||
- Counter Key: `(project_id, originator_org_id, NULL, corr_type_id, 0, rfa_type_id, discipline_id, year)`
|
||||
- *Mechanism*: `rfa_type_id` and `discipline_id` are linked to specific Contracts in the DB. Different contracts have different Type IDs, ensuring separate counters.
|
||||
|
||||
### 4. Error Handling
|
||||
|
||||
@@ -85,41 +89,33 @@
|
||||
|
||||
### Step 1: Database Entities
|
||||
|
||||
#### 1.1 Document Number Config Entity
|
||||
|
||||
```typescript
|
||||
// File: backend/src/modules/document-numbering/entities/document-number-config.entity.ts
|
||||
// File: backend/src/modules/document-numbering/entities/document-number-format.entity.ts
|
||||
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { Project } from '../../project/entities/project.entity';
|
||||
import { DocumentType } from '../../document-type/entities/document-type.entity';
|
||||
import { CorrespondenceType } from '../../correspondence-type/entities/correspondence-type.entity';
|
||||
|
||||
@Entity('document_number_configs')
|
||||
export class DocumentNumberConfig {
|
||||
@Entity('document_number_formats')
|
||||
export class DocumentNumberFormat {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
project_id: number;
|
||||
|
||||
@Column()
|
||||
doc_type_id: number;
|
||||
@Column({ name: 'correspondence_type_id' })
|
||||
correspondenceTypeId: number;
|
||||
|
||||
@Column({ default: 0, comment: 'ประเภทย่อย (nullable, use 0 for fallback)' })
|
||||
sub_type_id: number;
|
||||
// Note: Schema currently only has project_id + correspondence_type_id.
|
||||
// If we need sub_type/discipline specific templates, we might need schema update or use JSON config.
|
||||
// For now, aligning with lcbp3-v1.5.1-schema.sql which has format_template column.
|
||||
|
||||
@Column({ default: 0, comment: 'สาขาวิชา (nullable, use 0 for fallback)' })
|
||||
discipline_id: number;
|
||||
|
||||
@Column({ length: 255, comment: 'e.g. {PROJECT}-{ORG}-{TYPE}-{DISCIPLINE}-{SEQ:4}-{REV}' })
|
||||
template: string;
|
||||
@Column({ name: 'format_template', length: 255, comment: 'e.g. {PROJECT}-{ORIGINATOR}-{CORR_TYPE}-{SEQ:4}' })
|
||||
formatTemplate: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string;
|
||||
|
||||
@Column({ default: 0, comment: 'For template versioning' })
|
||||
version: number;
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
|
||||
@@ -130,11 +126,10 @@ export class DocumentNumberConfig {
|
||||
@JoinColumn({ name: 'project_id' })
|
||||
project: Project;
|
||||
|
||||
@ManyToOne(() => DocumentType)
|
||||
@JoinColumn({ name: 'doc_type_id' })
|
||||
documentType: DocumentType;
|
||||
@ManyToOne(() => CorrespondenceType)
|
||||
@JoinColumn({ name: 'correspondence_type_id' })
|
||||
correspondenceType: CorrespondenceType;
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 Document Number Counter Entity
|
||||
|
||||
@@ -158,8 +153,8 @@ export class DocumentNumberCounter {
|
||||
@PrimaryColumn({ name: 'originator_organization_id' })
|
||||
originatorOrganizationId: number;
|
||||
|
||||
@PrimaryColumn({ name: 'recipient_organization_id', nullable: true })
|
||||
recipientOrganizationId: number | null; // NULL for RFA
|
||||
@PrimaryColumn({ name: 'recipient_organization_id', default: -1 })
|
||||
recipientOrganizationId: number; // -1 if NULL (standardized for composite key)
|
||||
|
||||
@PrimaryColumn({ name: 'correspondence_type_id' })
|
||||
correspondenceTypeId: number;
|
||||
@@ -189,7 +184,7 @@ export class DocumentNumberCounter {
|
||||
|
||||
> **⚠️ หมายเหตุ Schema:**
|
||||
>
|
||||
> - Primary Key ใช้ `COALESCE(recipient_organization_id, 0)` ในการสร้าง constraint (ดู migration file)
|
||||
> - Primary Key ใช้ `recipient_organization_id = -1` แทน NULL (ตาม Schema v1.5.1)
|
||||
> - `sub_type_id`, `rfa_type_id`, `discipline_id` ใช้ `0` แทน NULL
|
||||
> - Counter reset อัตโนมัติทุกปี (แยก counter ตาม `current_year`)
|
||||
|
||||
@@ -309,7 +304,7 @@ import { Repository, DataSource } from 'typeorm';
|
||||
import Redlock from 'redlock';
|
||||
import Redis from 'ioredis';
|
||||
import { DocumentNumberCounter } from './entities/document-number-counter.entity';
|
||||
import { DocumentNumberConfig } from './entities/document-number-config.entity';
|
||||
import { DocumentNumberFormat } from './entities/document-number-format.entity';
|
||||
import { DocumentNumberAudit } from './entities/document-number-audit.entity';
|
||||
import { GenerateNumberDto } from './dto/generate-number.dto';
|
||||
import { MetricsService } from '../metrics/metrics.service';
|
||||
@@ -321,8 +316,8 @@ export class DocumentNumberingService {
|
||||
constructor(
|
||||
@InjectRepository(DocumentNumberCounter)
|
||||
private counterRepo: Repository<DocumentNumberCounter>,
|
||||
@InjectRepository(DocumentNumberConfig)
|
||||
private configRepo: Repository<DocumentNumberConfig>,
|
||||
@InjectRepository(DocumentNumberFormat)
|
||||
private formatRepo: Repository<DocumentNumberFormat>,
|
||||
@InjectRepository(DocumentNumberAudit)
|
||||
private auditRepo: Repository<DocumentNumberAudit>,
|
||||
private dataSource: DataSource,
|
||||
@@ -470,8 +465,8 @@ export class DocumentNumberingService {
|
||||
}
|
||||
|
||||
// Step 4: Get config and format number
|
||||
const config = await this.getConfig(dto.projectId, dto.docTypeId, subTypeId, disciplineId);
|
||||
const formattedNumber = await this.formatNumber(config.template, {
|
||||
const config = await this.getConfig(dto.projectId, dto.docTypeId);
|
||||
const formattedNumber = await this.formatNumber(config.formatTemplate, {
|
||||
projectId: dto.projectId,
|
||||
docTypeId: dto.docTypeId,
|
||||
subTypeId,
|
||||
@@ -561,8 +556,8 @@ export class DocumentNumberingService {
|
||||
}
|
||||
|
||||
// Format number
|
||||
const config = await this.getConfig(dto.projectId, dto.docTypeId, subTypeId, disciplineId);
|
||||
const formattedNumber = await this.formatNumber(config.template, {
|
||||
const config = await this.getConfig(dto.projectId, dto.docTypeId);
|
||||
const formattedNumber = await this.formatNumber(config.formatTemplate, {
|
||||
projectId: dto.projectId,
|
||||
docTypeId: dto.docTypeId,
|
||||
subTypeId,
|
||||
@@ -576,7 +571,7 @@ export class DocumentNumberingService {
|
||||
await manager.save(DocumentNumberAudit, {
|
||||
generated_number: formattedNumber,
|
||||
counter_key: `db_lock:${dto.projectId}:${dto.docTypeId}`,
|
||||
template_used: config.template,
|
||||
template_used: config.formatTemplate,
|
||||
sequence_number: nextNumber,
|
||||
user_id: dto.userId,
|
||||
ip_address: dto.ipAddress,
|
||||
@@ -596,8 +591,9 @@ export class DocumentNumberingService {
|
||||
private async formatNumber(template: string, data: any): Promise<string> {
|
||||
const tokens = {
|
||||
'{PROJECT}': await this.getProjectCode(data.projectId),
|
||||
'{ORG}': await this.getOrgCode(data.organizationId),
|
||||
'{TYPE}': await this.getTypeCode(data.docTypeId),
|
||||
'{ORIGINATOR}': await this.getOriginatorOrgCode(data.originatorOrganizationId),
|
||||
'{RECIPIENT}': await this.getRecipientOrgCode(data.recipientOrganizationId),
|
||||
'{CORR_TYPE}': await this.getTypeCode(data.docTypeId),
|
||||
'{SUB_TYPE}': await this.getSubTypeCode(data.subTypeId),
|
||||
'{DISCIPLINE}': await this.getDisciplineCode(data.disciplineId),
|
||||
'{CATEGORY}': await this.getCategoryCode(data.categoryId),
|
||||
@@ -661,39 +657,26 @@ export class DocumentNumberingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration template
|
||||
* Get configuration template (Format)
|
||||
*/
|
||||
private async getConfig(
|
||||
projectId: number,
|
||||
docTypeId: number,
|
||||
subTypeId: number,
|
||||
disciplineId: number,
|
||||
): Promise<DocumentNumberConfig> {
|
||||
// Try exact match first
|
||||
let config = await this.configRepo.findOne({
|
||||
correspondenceTypeId: number,
|
||||
): Promise<DocumentNumberFormat> {
|
||||
// Note: Schema currently only separates by project_id and correspondence_type_id
|
||||
// If we need sub-type specific templates, we should check if they are supported in the future schema.
|
||||
// Converting old logic slightly to match v1.5.1 schema columns.
|
||||
|
||||
const config = await this.formatRepo.findOne({
|
||||
where: {
|
||||
project_id: projectId,
|
||||
doc_type_id: docTypeId,
|
||||
sub_type_id: subTypeId,
|
||||
discipline_id: disciplineId,
|
||||
correspondenceTypeId: correspondenceTypeId,
|
||||
},
|
||||
});
|
||||
|
||||
// Fallback to default (subTypeId=0, disciplineId=0)
|
||||
if (!config) {
|
||||
config = await this.configRepo.findOne({
|
||||
where: {
|
||||
project_id: projectId,
|
||||
doc_type_id: docTypeId,
|
||||
sub_type_id: 0,
|
||||
discipline_id: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
throw new NotFoundException(
|
||||
`Document number config not found for project=${projectId}, docType=${docTypeId}`
|
||||
`Document number format not found for project=${projectId}, type=${correspondenceTypeId}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1241,14 +1224,14 @@ ensure:
|
||||
|
||||
## 🚨 Risks & Mitigation
|
||||
|
||||
| Risk | Impact | Probability | Mitigation |
|
||||
|------|--------|-------------|------------|
|
||||
| Redis lock failure | High | Low | Automatic fallback to DB lock |
|
||||
| Version conflicts under high load | Medium | Medium | Exponential backoff retry (2x) |
|
||||
| Lock timeout | Medium | Low | Retry 5x with exponential backoff |
|
||||
| Performance degradation | High | Medium | Redis caching, connection pooling, monitoring |
|
||||
| DB connection pool exhaustion | High | Low | Retry 3x, increase pool size, monitoring |
|
||||
| Rate limit bypass | Medium | Low | Multi-layer limiting (user + IP + global) |
|
||||
| Risk | Impact | Probability | Mitigation |
|
||||
| --------------------------------- | ------ | ----------- | --------------------------------------------- |
|
||||
| Redis lock failure | High | Low | Automatic fallback to DB lock |
|
||||
| Version conflicts under high load | Medium | Medium | Exponential backoff retry (2x) |
|
||||
| Lock timeout | Medium | Low | Retry 5x with exponential backoff |
|
||||
| Performance degradation | High | Medium | Redis caching, connection pooling, monitoring |
|
||||
| DB connection pool exhaustion | High | Low | Retry 3x, increase pool size, monitoring |
|
||||
| Rate limit bypass | Medium | Low | Multi-layer limiting (user + IP + global) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1292,7 +1275,7 @@ Stored in database (`document_number_configs` table), configurable per:
|
||||
|
||||
## 🔄 Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 1.0 | 2025-11-30 | Initial task definition |
|
||||
| 2.0 | 2025-12-02 | Comprehensive update with all 9 tokens, 4 document types, 4 error scenarios, audit logging, monitoring, rate limiting, and complete implementation details |
|
||||
| Version | Date | Changes |
|
||||
| ------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1.0 | 2025-11-30 | Initial task definition |
|
||||
| 2.0 | 2025-12-02 | Comprehensive update with all 9 tokens, 4 document types, 4 error scenarios, audit logging, monitoring, rate limiting, and complete implementation details |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Workflow Engine Module
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** Completed
|
||||
**Priority:** P0 (Critical - Core Infrastructure)
|
||||
**Estimated Effort:** 10-14 days
|
||||
**Dependencies:** TASK-BE-001 (Database), TASK-BE-002 (Auth)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: RFA Module
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** In Progress
|
||||
**Priority:** P1 (High - Core Business Module)
|
||||
**Estimated Effort:** 8-12 days
|
||||
**Dependencies:** TASK-BE-001, TASK-BE-002, TASK-BE-003, TASK-BE-004, TASK-BE-006
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Drawing Module (Shop & Contract Drawings)
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** In Progress
|
||||
**Priority:** P2 (Medium - Supporting Module)
|
||||
**Estimated Effort:** 6-8 days
|
||||
**Dependencies:** TASK-BE-001, TASK-BE-002, TASK-BE-003, TASK-BE-004
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Circulation & Transmittal Modules
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** In Progress
|
||||
**Priority:** P2 (Medium)
|
||||
**Estimated Effort:** 5-7 days
|
||||
**Dependencies:** TASK-BE-001, TASK-BE-002, TASK-BE-003, TASK-BE-006
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Search & Elasticsearch Integration
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** 🚧 In Progress
|
||||
**Priority:** P2 (Medium - Performance Enhancement)
|
||||
**Estimated Effort:** 4-6 days
|
||||
**Dependencies:** TASK-BE-001, TASK-BE-005, TASK-BE-007
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
## 🎯 Objectives
|
||||
|
||||
- ✅ Elasticsearch Integration
|
||||
- ✅ Full-text Search (Correspondences, RFAs, Drawings)
|
||||
- ✅ Advanced Filters
|
||||
- ✅ Search Result Aggregations
|
||||
- ✅ Auto-indexing
|
||||
- [x] Elasticsearch Integration
|
||||
- [x] Full-text Search (Correspondences, RFAs, Drawings)
|
||||
- [x] Advanced Filters
|
||||
- [ ] Search Result Aggregations (Pending verification)
|
||||
- [x] Auto-indexing (Implemented via Direct Call, not Queue yet)
|
||||
|
||||
---
|
||||
|
||||
@@ -28,21 +28,21 @@
|
||||
|
||||
1. **Search Capabilities:**
|
||||
|
||||
- ✅ Search across multiple document types
|
||||
- ✅ Full-text search in title, description
|
||||
- ✅ Filter by project, status, date range
|
||||
- ✅ Sort results by relevance/date
|
||||
- [x] Search across multiple document types
|
||||
- [x] Full-text search in title, description
|
||||
- [x] Filter by project, status, date range
|
||||
- [x] Sort results by relevance/date
|
||||
|
||||
2. **Indexing:**
|
||||
|
||||
- ✅ Auto-index on document create/update
|
||||
- ✅ Async indexing (via queue)
|
||||
- ✅ Bulk re-indexing command
|
||||
- [x] Auto-index on document create/update (Direct Call implemented)
|
||||
- [ ] Async indexing (via queue) - **Pending**
|
||||
- [ ] Bulk re-indexing command - **Pending**
|
||||
|
||||
3. **Performance:**
|
||||
- ✅ Search results < 500ms
|
||||
- ✅ Pagination support
|
||||
- ✅ Highlight search terms
|
||||
- [x] Search results < 500ms
|
||||
- [x] Pagination support
|
||||
- [x] Highlight search terms
|
||||
|
||||
---
|
||||
|
||||
@@ -462,12 +462,12 @@ describe('SearchService', () => {
|
||||
|
||||
## 📦 Deliverables
|
||||
|
||||
- [ ] SearchService with Elasticsearch
|
||||
- [ ] Search Indexer (Queue Worker)
|
||||
- [ ] Index Mappings
|
||||
- [ ] Queue Integration
|
||||
- [ ] Search Controller
|
||||
- [ ] Bulk Re-indexing Command
|
||||
- [x] SearchService with Elasticsearch
|
||||
- [ ] Search Indexer (Queue Worker) - **Pending**
|
||||
- [x] Index Mappings (Implemented in Service)
|
||||
- [ ] Queue Integration - **Pending**
|
||||
- [x] Search Controller
|
||||
- [ ] Bulk Re-indexing Command - **Pending**
|
||||
- [ ] Unit Tests (75% coverage)
|
||||
- [ ] API Documentation
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Notification & Audit Log Services
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** Completed
|
||||
**Priority:** P3 (Low - Supporting Services)
|
||||
**Estimated Effort:** 3-5 days
|
||||
**Dependencies:** TASK-BE-001, TASK-BE-002
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: Master Data Management Module
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** Completed
|
||||
**Priority:** P1 (High - Required for System Setup)
|
||||
**Estimated Effort:** 6-8 days
|
||||
**Dependencies:** TASK-BE-001 (Database), TASK-BE-002 (Auth)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Task: User Management Module
|
||||
|
||||
**Status:** Not Started
|
||||
**Status:** Completed
|
||||
**Priority:** P1 (High - Core User Features)
|
||||
**Estimated Effort:** 5-7 days
|
||||
**Dependencies:** TASK-BE-001 (Database), TASK-BE-002 (Auth & RBAC)
|
||||
|
||||
@@ -29,11 +29,11 @@ Build UI for configuring and managing workflows using the DSL-based workflow eng
|
||||
|
||||
## ✅ Acceptance Criteria
|
||||
|
||||
- [ ] List all workflows with status
|
||||
- [ ] Create/edit workflows with DSL editor
|
||||
- [ ] Visual workflow builder functional
|
||||
- [ ] DSL validation shows errors
|
||||
- [ ] Test workflow with sample data
|
||||
- [x] List all workflows with status
|
||||
- [x] Create/edit workflows with DSL editor
|
||||
- [x] Visual workflow builder functional
|
||||
- [x] DSL validation shows errors
|
||||
- [x] Test workflow with sample data
|
||||
- [ ] Workflow templates available
|
||||
- [ ] Version history viewable
|
||||
|
||||
|
||||
@@ -29,13 +29,13 @@ Build UI for configuring and managing document numbering templates including tem
|
||||
|
||||
## ✅ Acceptance Criteria
|
||||
|
||||
- [ ] List all numbering templates by document type
|
||||
- [ ] Create/edit templates with format preview
|
||||
- [ ] Template variables easily selectable
|
||||
- [ ] Preview shows example numbers
|
||||
- [ ] View current number sequences
|
||||
- [ ] Annual reset configurable
|
||||
- [ ] Validation prevents conflicts
|
||||
- [x] List all numbering templates by document type
|
||||
- [x] Create/edit templates with format preview
|
||||
- [x] Template variables easily selectable
|
||||
- [x] Preview shows example numbers
|
||||
- [x] View current number sequences
|
||||
- [x] Annual reset configurable
|
||||
- [x] Validation prevents conflicts
|
||||
|
||||
---
|
||||
|
||||
@@ -67,10 +67,21 @@ export default function NumberingPage() {
|
||||
Manage document numbering templates and sequences
|
||||
</p>
|
||||
</div>
|
||||
<Button>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
New Template
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<Select defaultValue="1">
|
||||
<SelectTrigger className="w-[200px]">
|
||||
<SelectValue placeholder="Select Project" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">LCBP3</SelectItem>
|
||||
<SelectItem value="2">LCBP3-Maintenance</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
New Template
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4">
|
||||
@@ -161,14 +172,16 @@ import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
const VARIABLES = [
|
||||
{ key: '{ORG}', name: 'Organization Code', example: 'กทท' },
|
||||
{ key: '{DOCTYPE}', name: 'Document Type', example: 'CORR' },
|
||||
{ key: '{DISC}', name: 'Discipline', example: 'STR' },
|
||||
{ key: '{YYYY}', name: 'Year (4-digit)', example: '2025' },
|
||||
{ key: '{YY}', name: 'Year (2-digit)', example: '25' },
|
||||
{ key: '{MM}', name: 'Month', example: '12' },
|
||||
{ key: '{SEQ}', name: 'Sequence Number', example: '0001' },
|
||||
{ key: '{CONTRACT}', name: 'Contract Code', example: 'C01' },
|
||||
{ key: '{ORIGINATOR}', name: 'Originator Code', example: 'PAT' },
|
||||
{ key: '{RECIPIENT}', name: 'Recipient Code', example: 'CN' },
|
||||
{ key: '{CORR_TYPE}', name: 'Correspondence Type', example: 'RFA' },
|
||||
{ key: '{SUB_TYPE}', name: 'Sub Type', example: '21' },
|
||||
{ key: '{DISCIPLINE}', name: 'Discipline', example: 'STR' },
|
||||
{ key: '{RFA_TYPE}', name: 'RFA Type', example: 'SDW' },
|
||||
{ key: '{YEAR:B.E.}', name: 'Year (B.E.)', example: '2568' },
|
||||
{ key: '{YEAR:A.D.}', name: 'Year (A.D.)', example: '2025' },
|
||||
{ key: '{SEQ:4}', name: 'Sequence (4-digit)', example: '0001' },
|
||||
{ key: '{REV}', name: 'Revision', example: 'A' },
|
||||
];
|
||||
|
||||
export function TemplateEditor({ template, onSave }: any) {
|
||||
@@ -201,9 +214,16 @@ export function TemplateEditor({ template, onSave }: any) {
|
||||
<SelectValue placeholder="Select document type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="correspondence">Correspondence</SelectItem>
|
||||
<SelectItem value="rfa">RFA</SelectItem>
|
||||
<SelectItem value="drawing">Drawing</SelectItem>
|
||||
<SelectItem value="RFA">RFA</SelectItem>
|
||||
<SelectItem value="RFI">RFI</SelectItem>
|
||||
<SelectItem value="TRANSMITTAL">Transmittal</SelectItem>
|
||||
<SelectItem value="LETTER">Letter</SelectItem>
|
||||
<SelectItem value="MEMO">Memorandum</SelectItem>
|
||||
<SelectItem value="EMAIL">Email</SelectItem>
|
||||
<SelectItem value="MOM">Minutes of Meeting</SelectItem>
|
||||
<SelectItem value="INSTRUCTION">Instruction</SelectItem>
|
||||
<SelectItem value="NOTICE">Notice</SelectItem>
|
||||
<SelectItem value="OTHER">Other</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
|
||||
## 📊 Overview
|
||||
|
||||
| Task ID | Title | Status | Completion % | Notes |
|
||||
| --------------- | ------------------------- | ----------------- | ------------ | ------------------------------------------------------ |
|
||||
| **TASK-BE-001** | Database Migrations | ✅ **Done** | 100% | Schema v1.5.1 active. TypeORM configured. |
|
||||
| **TASK-BE-002** | Auth & RBAC | ✅ **Done** | 100% | JWT, Refresh Token, RBAC Guard, Permissions complete. |
|
||||
| **TASK-BE-003** | File Storage | ✅ **Done** | 100% | MinIO/S3 strategies implemented (in `common`). |
|
||||
| **TASK-BE-004** | Document Numbering | ✅ **Done** | 100% | **High Quality**: Redlock + Optimistic Locking logic. |
|
||||
| **TASK-BE-005** | Correspondence Module | ✅ **Done** | 95% | CRUD, Workflow Submit, References, Audit Log complete. |
|
||||
| **TASK-BE-006** | Workflow Engine | ✅ **Done** | 100% | DSL Evaluator, Versioning, Event Dispatching complete. |
|
||||
| **TASK-BE-007** | RFA Module | ✅ **Done** | 95% | Full Swagger, Revision handling, Workflow integration. |
|
||||
| **TASK-BE-008** | Drawing Module | ✅ **Done** | 95% | Split into `ShopDrawing` & `ContractDrawing`. |
|
||||
| **TASK-BE-009** | Circulation & Transmittal | ✅ **Done** | 90% | Modules exist and registered in `app.module.ts`. |
|
||||
| **TASK-BE-010** | Search (Elasticsearch) | 🚧 **In Progress** | 80% | Module registered, needs deep verification of mapping. |
|
||||
| **TASK-BE-011** | Notification & Audit | ✅ **Done** | 100% | Global Audit Interceptor & Notification Module active. |
|
||||
| **TASK-BE-012** | Master Data Management | ✅ **Done** | 100% | Disciplines, SubTypes, Tags, Config APIs complete. |
|
||||
| **TASK-BE-013** | User Management | ✅ **Done** | 100% | CRUD, Assignments, Preferences, Soft Delete complete. |
|
||||
| Task ID | Title | Status | Completion % | Notes |
|
||||
| --------------- | ------------------------- | ----------------- | ------------ | ----------------------------------------------------------------------- |
|
||||
| **TASK-BE-001** | Database Migrations | ✅ **Done** | 100% | Schema v1.5.1 active. TypeORM configured. |
|
||||
| **TASK-BE-002** | Auth & RBAC | ✅ **Done** | 100% | JWT, Refresh Token, RBAC Guard, Permissions complete. |
|
||||
| **TASK-BE-003** | File Storage | ✅ **Done** | 100% | MinIO/S3 strategies implemented (in `common`). |
|
||||
| **TASK-BE-004** | Document Numbering | ✅ **Done** | 100% | **High Quality**: Redlock + Optimistic Locking logic. |
|
||||
| **TASK-BE-005** | Correspondence Module | ✅ **Done** | 95% | CRUD, Workflow Submit, References, Audit Log complete. |
|
||||
| **TASK-BE-006** | Workflow Engine | ✅ **Done** | 100% | DSL Evaluator, Versioning, Event Dispatching complete. |
|
||||
| **TASK-BE-007** | RFA Module | ✅ **Done** | 95% | Full Swagger, Revision handling, Workflow integration. |
|
||||
| **TASK-BE-008** | Drawing Module | ✅ **Done** | 95% | Split into `ShopDrawing` & `ContractDrawing`. |
|
||||
| **TASK-BE-009** | Circulation & Transmittal | ✅ **Done** | 90% | Modules exist and registered in `app.module.ts`. |
|
||||
| **TASK-BE-010** | Search (Elasticsearch) | 🚧 **In Progress** | 70% | Basic search working (Direct Indexing). Missing: Queue & Bulk Re-index. |
|
||||
| **TASK-BE-011** | Notification & Audit | ✅ **Done** | 100% | Global Audit Interceptor & Notification Module active. |
|
||||
| **TASK-BE-012** | Master Data Management | ✅ **Done** | 100% | Disciplines, SubTypes, Tags, Config APIs complete. |
|
||||
| **TASK-BE-013** | User Management | ✅ **Done** | 100% | CRUD, Assignments, Preferences, Soft Delete complete. |
|
||||
|
||||
## 🛠 Detailed Findings by Component
|
||||
|
||||
|
||||
Reference in New Issue
Block a user