Files
lcbp3/4_Data_Dictionary_V1_4_4.md
2025-11-28 17:12:05 +07:00

2924 lines
135 KiB
Markdown

# **ตารางฐานข้อมูล (Data Dictionary) - LCBP3-DMS (V1.4.4)**
เอกสารนี้สรุปโครงสร้างตาราง, Foreign Keys (FK), และ Constraints ที่สำคัญทั้งหมดในฐานข้อมูล LCBP3-DMS (v1.4) เพื่อใช้เป็นเอกสารอ้างอิงสำหรับทีมพัฒนา Backend (NestJS) และ Frontend (Next.js) โดยอิงจาก Requirements และ SQL Script ล่าสุด [GEMINI]
**สถานะ:** FINAL GUIDELINE
**วันที่:** 2025-11-26
**อ้างอิง:** Requirements v1.4.4 & FullStackJS Guidelines v1.4.4
**Classification:** Internal Technical Documentation
## 📝 สรุปรายการปรับปรุง (Summary of Changes)
1. **เพิ่มตาราง `disciplines`**: สำหรับเก็บข้อมูลสาขางาน (เช่น GEN, STR, ARC)
2. **เพิ่มตาราง `correspondence_sub_types`**: สำหรับเก็บรหัสย่อย (เช่น MAT-11, SHP-12)
3. **แก้ไขตาราง `correspondences`**: เพิ่ม Column `discipline_id`
4. **แก้ไขตาราง `rfas`**: เพิ่ม Column `discipline_id`
5. **แก้ไขตาราง `document_number_counters`**: เพิ่ม `discipline_id` ใน Primary Key
6. Seeded data for disciplines and RFA types based on Requirement 6B.
---
## **1. 🏢 Core & Master Data Tables (องค์กร, โครงการ, สัญญา)**
### 1.1 organization_roles
**Purpose**: Master table for organization role types in the system
| Column Name | Data Type | Constraints | Description |
| ----------- | ----------- | --------------------------- | ---------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for organization role |
| role_name | VARCHAR(20) | NOT NULL, UNIQUE | Role name (OWNER, DESIGNER, CONSULTANT, CONTRACTOR, THIRD PARTY) |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (role_name)
**Business Rules**:
- Predefined system roles for organization types
- Cannot be deleted if referenced by organizations
---
### 1.2 organizations
**Purpose**: Master table storing all organizations involved in the system
| Column Name | Data Type | Constraints | Description |
| ----------------- | ------------ | ----------------------------------- | ---------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for organization |
| organization_code | VARCHAR(20) | NOT NULL, UNIQUE | Organization code (e.g., 'กทท.', 'TEAM') |
| organization_name | VARCHAR(255) | NOT NULL | Full organization name |
| is_active | BOOLEAN | DEFAULT TRUE | Active status (1=active, 0=inactive) |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (organization_code)
- INDEX (is_active)
**Relationships**:
- Referenced by: users, project_organizations, contract_organizations, correspondences, circulations
**Seed Data**: Pre-populated with 15 organizations including:
- Port Authority of Thailand (กทท.)
- Project supervision consultants (สค©.3-xx)
- Design consultants (TEAM)
- Construction supervisors (คคง.)
- Contractors (ผรม.1-4)
- Third parties (EN, CAR)
---
### 1.3 projects
**Purpose**: Master table for all projects in the system
| Column Name | Data Type | Constraints | Description |
| ------------ | ------------ | --------------------------- | ----------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for project |
| project_code | VARCHAR(50) | NOT NULL, UNIQUE | Project code (e.g., 'LCBP3') |
| project_name | VARCHAR(255) | NOT NULL | Full project name |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (project_code)
- INDEX (is_active)
**Relationships**:
- Referenced by: contracts, correspondences, document_number_formats, drawings
**Seed Data**: 5 projects for Laem Chabang Port Phase 3 (LCBP3) including main project and 4 sub-contracts
---
### 1.4 contracts
**Purpose**: Master table for contracts within projects
| Column Name | Data Type | Constraints | Description |
| ------------- | ------------ | ----------------------------------- | ------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for contract |
| project_id | INT | NOT NULL, FK | Reference to projects table |
| contract_code | VARCHAR(50) | NOT NULL, UNIQUE | Contract code |
| contract_name | VARCHAR(255) | NOT NULL | Full contract name |
| description | TEXT | NULL | Contract description |
| start_date | DATE | NULL | Contract start date |
| end_date | DATE | NULL | Contract end date |
| is_active | BOOLEAN | DEFAULT TRUE | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (contract_code)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- INDEX (project_id, is_active)
**Relationships**:
- Parent: projects
- Referenced by: contract_organizations, user_assignments
**Seed Data**: 7 contracts including design, supervision, construction, and environmental monitoring
---
## **2. 👥 Users & RBAC Tables (ผู้ใช้, สิทธิ์, บทบาท)**
### 2.1 users
**Purpose**: Master table storing all system users
| Column Name | Data Type | Constraints | Description |
| ----------------------- | ------------ | ----------------------------------- | -------------------------------- |
| user_id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for user |
| username | VARCHAR(50) | NOT NULL, UNIQUE | Login username |
| password_hash | VARCHAR(255) | NOT NULL | Hashed password (bcrypt) |
| first_name | VARCHAR(50) | NULL | User's first name |
| last_name | VARCHAR(50) | NULL | User's last name |
| email | VARCHAR(100) | NOT NULL, UNIQUE | Email address |
| line_id | VARCHAR(100) | NULL | LINE messenger ID |
| primary_organization_id | INT | NULL, FK | Primary organization affiliation |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| failed_attempts | INT | DEFAULT 0 | Failed login attempts counter |
| locked_until | DATETIME | NULL | Account lock expiration time |
| last_login_at | TIMESTAMP | NULL | Last successful login timestamp |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
| deleted_at | DATETIME | NULL | Deleted at |
**Indexes**:
- PRIMARY KEY (user_id)
- UNIQUE (username)
- UNIQUE (email)
- FOREIGN KEY (primary_organization_id) REFERENCES organizations(id) ON DELETE SET NULL
- INDEX (is_active)
- INDEX (email)
**Relationships**:
- Parent: organizations (primary_organization_id)
- Referenced by: user_assignments, audit_logs, notifications, circulation_routings
**Security Features**:
- Password stored as bcrypt hash
- Account locking after failed attempts
- Last login tracking
**Seed Data**: 3 initial users (superadmin, editor01, viewer01)
---
### 2.2 roles
**Purpose**: Master table defining system roles with scope levels
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | --------------------------- | ---------------------------------------------------- |
| role_id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for role |
| role_name | VARCHAR(100) | NOT NULL | Role name (e.g., 'Superadmin', 'Document Control') |
| scope | ENUM | NOT NULL | Scope level: Global, Organization, Project, Contract |
| description | TEXT | NULL | Role description |
| is_system | BOOLEAN | DEFAULT FALSE | System role flag (cannot be deleted) |
**Indexes**:
- PRIMARY KEY (role_id)
- INDEX (scope)
**Relationships**:
- Referenced by: role_permissions, user_assignments
**Seed Data**: 7 predefined roles
1. Superadmin (Global) - Full system access
2. Org Admin (Organization) - Organization management
3. Document Control (Organization) - Document lifecycle management
4. Editor (Organization) - Document creation and editing
5. Viewer (Organization) - Read-only access
6. Project Manager (Project) - Project-level management
7. Contract Admin (Contract) - Contract-specific administration
---
### 2.3 permissions
**Purpose**: Master table defining all system permissions
| Column Name | Data Type | Constraints | Description |
| --------------- | ------------ | --------------------------- | ------------------------------------------------------ |
| permission_id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier for permission |
| permission_name | VARCHAR(100) | NOT NULL, UNIQUE | Permission code (e.g., 'rfas.create', 'document.view') |
| description | TEXT | NULL | Permission description |
| module | VARCHAR(50) | NULL | Related module name |
| scope_level | ENUM | NULL | Scope: GLOBAL, ORG, PROJECT |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (permission_id)
- UNIQUE (permission_name)
- INDEX (module)
- INDEX (scope_level)
- INDEX (is_active)
**Relationships**:
- Referenced by: role_permissions
**Permission Categories**:
1. **System Management** (1): system.manage_all
2. **Organization Management** (2-5): create, edit, delete, view
3. **Project Management** (6-9, 23-26): create, edit, delete, view, manage members/contracts/reports
4. **Role & Permission Management** (10-13): create, edit, delete roles, assign permissions
5. **Master Data Management** (14-17): document types, statuses, categories, tags
6. **User Management** (18-22): create, edit, delete, view, assign organization
7. **Contract Management** (27-28): manage members, view
8. **Document Management** (29-44): CRUD operations, workflows, circulation
9. **Search & Reporting** (48-49): advanced search, generate reports
**Total Permissions**: 49
---
### 2.4 role_permissions
**Purpose**: Junction table mapping roles to permissions (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------- | --------- | --------------- | ------------------------------ |
| role_id | INT | PRIMARY KEY, FK | Reference to roles table |
| permission_id | INT | PRIMARY KEY, FK | Reference to permissions table |
**Indexes**:
- PRIMARY KEY (role_id, permission_id)
- FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE
- FOREIGN KEY (permission_id) REFERENCES permissions(permission_id) ON DELETE CASCADE
- INDEX (permission_id)
**Relationships**:
- Parent: roles, permissions
**Seed Data**: Complete permission mappings for all 7 roles
- Superadmin: All 49 permissions
- Org Admin: 15 permissions (user/org/tag management, view access)
- Document Control: 26 permissions (full document lifecycle)
- Editor: 12 permissions (document CRUD without admin powers)
- Viewer: 2 permissions (view and search only)
- Project Manager: 23 permissions (project management + document CRUD)
- Contract Admin: 15 permissions (contract management + document CRUD)
---
### 2.5 user_assignments
**Purpose**: Junction table assigning users to roles with scope context
| Column Name | Data Type | Constraints | Description |
| ------------------- | --------- | --------------------------- | ---------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| user_id | INT | NOT NULL, FK | Reference to users table |
| role_id | INT | NOT NULL, FK | Reference to roles table |
| organization_id | INT | NULL, FK | Organization scope (if applicable) |
| project_id | INT | NULL, FK | Project scope (if applicable) |
| contract_id | INT | NULL, FK | Contract scope (if applicable) |
| assigned_by_user_id | INT | NULL, FK | User who made the assignment |
| assigned_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Assignment timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
- FOREIGN KEY (role_id) REFERENCES roles(role_id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE CASCADE
- FOREIGN KEY (assigned_by_user_id) REFERENCES users(user_id)
- INDEX (user_id, role_id)
- INDEX (organization_id)
- INDEX (project_id)
- INDEX (contract_id)
**Constraints**:
- CHECK: Only one scope field (organization_id, project_id, contract_id) can be NOT NULL, or all NULL for Global scope
**Relationships**:
- Parent: users, roles, organizations, projects, contracts
**Business Rules**:
- User can have multiple role assignments with different scopes
- Scope inheritance: Contract → Project → Organization → Global
- Global scope: all scope fields are NULL
---
### 2.6 project_organizations
**Purpose**: Junction table linking projects to participating organizations (M:N)
| Column Name | Data Type | Constraints | Description |
| --------------- | --------- | --------------- | -------------------------------- |
| project_id | INT | PRIMARY KEY, FK | Reference to projects table |
| organization_id | INT | PRIMARY KEY, FK | Reference to organizations table |
**Indexes**:
- PRIMARY KEY (project_id, organization_id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE
- INDEX (organization_id)
**Relationships**:
- Parent: projects, organizations
**Seed Data**: Pre-populated with project-organization relationships
---
### 2.7 contract_organizations
**Purpose**: Junction table linking contracts to participating organizations with roles (M:N)
| Column Name | Data Type | Constraints | Description |
| ---------------- | ------------ | --------------- | ------------------------------------------------------------------------- |
| contract_id | INT | PRIMARY KEY, FK | Reference to contracts table |
| organization_id | INT | PRIMARY KEY, FK | Reference to organizations table |
| role_in_contract | VARCHAR(100) | NULL | Organization's role in contract (Owner, Designer, Consultant, Contractor) |
**Indexes**:
- PRIMARY KEY (contract_id, organization_id)
- FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE
- INDEX (organization_id)
- INDEX (role_in_contract)
**Relationships**:
- Parent: contracts, organizations
**Seed Data**: Pre-populated with contract-organization-role relationships
---
## **3. ✉️ Correspondences Tables (เอกสารหลัก, Revisions, Workflows)**
### 3.1 correspondence_types
**Purpose**: Master table for correspondence document types
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | --------------------------- | --------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| type_code | VARCHAR(50) | NOT NULL, UNIQUE | Type code (e.g., 'RFA', 'RFI', 'TRANSMITTAL') |
| type_name | VARCHAR(255) | NOT NULL | Full type name |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (type_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: correspondences, document_number_formats, document_number_counters
**Seed Data**: 10 correspondence types including RFA, RFI, TRANSMITTAL, EMAIL, INSTRUCTION, LETTER, MEMO, MOM, NOTICE, OTHER
---
### 3.2 correspondence_status
**Purpose**: Master table for correspondence status codes
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | --------------------------- | ------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| status_code | VARCHAR(50) | NOT NULL, UNIQUE | Status code (e.g., 'DRAFT', 'SUBOWN') |
| status_name | VARCHAR(255) | NOT NULL | Full status name |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (status_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: correspondence_revisions
**Seed Data**: 23 status codes covering draft, submission, reply, resubmission, closure, and cancellation states by different parties (Owner, Designer, CSC, Contractor)
---
### 3.3 correspondences
**Purpose**: Master table for correspondence documents (non-revisioned data)
| Column Name | Data Type | Constraints | Description |
| ------------------------- | ------------ | --------------------------- | -------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Master correspondence ID |
| correspondence_number | VARCHAR(100) | NOT NULL | Document number (from numbering system) |
| correspondence_type_id | INT | NOT NULL, FK | Reference to correspondence_types |
| **discipline_id** | **INT** | **NULL, FK** | **Reference to disciplines (if applicable)** |
| is_internal_communication | TINYINT(1) | DEFAULT 0 | Internal (1) or external (0) communication |
| project_id | INT | NOT NULL, FK | Reference to projects table |
| originator_id | INT | NULL, FK | Originating organization |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| created_by | INT | NULL, FK | User who created the record |
| deleted_at | DATETIME | NULL | Soft delete timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE RESTRICT
- **FOREIGN KEY (discipline_id) REFERENCES disciplines(id) ON DELETE SET NULL**
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (originator_id) REFERENCES organizations(id) ON DELETE SET NULL
- FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL
- UNIQUE KEY (project_id, correspondence_number)
- INDEX (correspondence_type_id)
- INDEX (originator_id)
- INDEX (deleted_at)
**Relationships**:
- Parent: correspondence_types, **disciplines**, projects, organizations, users
- Children: correspondence_revisions, correspondence_recipients, correspondence_tags, correspondence_references, correspondence_attachments, circulations, transmittals
**Business Rules**:
- One correspondence can have multiple revisions
- Correspondence number must be unique within a project
- Soft delete preserves history
---
### 3.4 correspondence_revisions
**Purpose**: Child table storing revision history of correspondences (1:N)
| Column Name | Data Type | Constraints | Description |
| ------------------------ | ------------ | --------------------------------- | ------------------------------------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique revision ID |
| correspondence_id | INT | NOT NULL, FK | Master correspondence ID |
| revision_number | INT | NOT NULL | Revision sequence (0, 1, 2...) |
| revision_label | VARCHAR(10) | NULL | Display revision (A, B, 1.1...) |
| is_current | BOOLEAN | DEFAULT FALSE | Current revision flag |
| correspondence_status_id | INT | NOT NULL, FK | Current status of this revision |
| title | VARCHAR(255) | NOT NULL | Document title |
| document_date | DATE | NULL | Document date |
| issued_date | DATETIME | NULL | Issue date |
| received_date | DATETIME | NULL | Received date |
| due_date | DATETIME | NULL | Due date for response |
| description | TEXT | NULL | Revision description |
| details | JSON | NULL | Type-specific details (e.g., RFI questions) |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Revision creation timestamp |
| created_by | INT | NULL, FK | User who created revision |
| updated_by | INT | NULL, FK | User who last updated |
| v_ref_project_id | INT | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Project ID จาก JSON details เพื่อทำ Index |
| v_ref_type | VARCHAR(50) | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Type จาก JSON details |
| details | JSON | NULL | Type-specific details (e.g., RFI questions) |
| v_doc_subtype | VARCHAR(50) | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Type จาก JSON details |
| schema_version | INT | DEFAULT 1 | Version of the schema used with this details |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- FOREIGN KEY (correspondence_status_id) REFERENCES correspondence_status(id) ON DELETE RESTRICT
- FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL
- FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL
- UNIQUE KEY (correspondence_id, revision_number)
- UNIQUE KEY (correspondence_id, is_current) - Only one current revision per correspondence
- INDEX (correspondence_status_id)
- INDEX (is_current)
- INDEX (document_date)
- INDEX (issued_date)
- INDEX (v_ref_project_id)
- INDEX (v_ref_type)
- INDEX (v_doc_subtype)
- **Relationships**:
- Parent: correspondences, correspondence_status, users
**Business Rules**:
- Only one revision can be marked as current (is_current=TRUE) per correspondence
- Revision numbers are sequential starting from 0
- JSON details field allows type-specific data storage
---
### 3.5 correspondence_recipients
**Purpose**: Junction table for correspondence recipients (TO/CC) (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------------------- | ---------------- | --------------- | ---------------------------- |
| correspondence_id | INT | PRIMARY KEY, FK | Reference to correspondences |
| recipient_organization_id | INT | PRIMARY KEY, FK | Recipient organization |
| recipient_type | ENUM('TO', 'CC') | PRIMARY KEY | Recipient type |
**Indexes**:
- PRIMARY KEY (correspondence_id, recipient_organization_id, recipient_type)
- FOREIGN KEY (correspondence_id) REFERENCES correspondence_revisions(correspondence_id) ON DELETE CASCADE
- FOREIGN KEY (recipient_organization_id) REFERENCES organizations(id) ON DELETE RESTRICT
- INDEX (recipient_organization_id)
- INDEX (recipient_type)
**Relationships**:
- Parent: correspondences, organizations
**Business Rules**:
- One organization can be both TO and CC recipient
- Cascade delete when correspondence is deleted
---
### 3.6 tags
**Purpose**: Master table for document tagging system
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | ----------------------------------- | ------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique tag ID |
| tag_name | VARCHAR(100) | NOT NULL, UNIQUE | Tag name |
| description | TEXT | NULL | Tag description |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (tag_name)
- INDEX (tag_name) - For autocomplete
**Relationships**:
- Referenced by: correspondence_tags
---
### 3.7 correspondence_tags
**Purpose**: Junction table linking correspondences to tags (M:N)
| Column Name | Data Type | Constraints | Description |
| ----------------- | --------- | --------------- | ---------------------------- |
| correspondence_id | INT | PRIMARY KEY, FK | Reference to correspondences |
| tag_id | INT | PRIMARY KEY, FK | Reference to tags |
**Indexes**:
- PRIMARY KEY (correspondence_id, tag_id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
- INDEX (tag_id)
**Relationships**:
- Parent: correspondences, tags
---
### 3.8 correspondence_references
**Purpose**: Junction table for cross-referencing correspondences (M:N)
| Column Name | Data Type | Constraints | Description |
| --------------------- | --------- | --------------- | ------------------------------------- |
| src_correspondence_id | INT | PRIMARY KEY, FK | Source correspondence ID |
| tgt_correspondence_id | INT | PRIMARY KEY, FK | Target (referenced) correspondence ID |
**Indexes**:
- PRIMARY KEY (src_correspondence_id, tgt_correspondence_id)
- FOREIGN KEY (src_correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- FOREIGN KEY (tgt_correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- INDEX (tgt_correspondence_id)
**Relationships**:
- Parent: correspondences (both sides)
**Business Rules**:
- Allows tracing document relationships
- Bi-directional references should be created as separate records
### 3.9 ตาราง correspondence_routing_templates
**Purpose**: เก็บข้อมูลแม่แบบ (Template) ของสายงานการส่งต่อเอกสารเพื่อขออนุมัติ ทำให้ไม่ต้องกำหนดขั้นตอนซ้ำทุกครั้ง สามารถสร้างเป็นแม่แบบทั่วไป หรือเฉพาะสำหรับโครงการใดโครงการหนึ่งได้
| Column Name | Data Type | Constraints | Description |
| --------------- | ------------ | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | ID หลัก (Primary Key) ของแม่แบบ รันค่าอัตโนมัติ |
| template_name | VARCHAR(255) | NOT NULL | ชื่อของแม่แบบ เช่น "เสนอโครงการ", "ขออนุมัติจัดซื้อ" |
| description | TEXT | NULL | คำอธิบายรายละเอียดเกี่ยวกับแม่แบบนี้ |
| project_id | INT | NULL | ID ของโครงการที่แม่แบบนี้สังกัดอยู่ (ถ้ามี) **ค่า NULL หมายถึง** เป็น "แม่แบบทั่วไป" ที่สามารถใช้กับทุกโครงการได้ |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | วันที่และเวลาที่สร้างแม่แบบนี้ |
| updated_at | TIMESTAMP | NOT NULL,`DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | วันที่และเวลาที่แก้ไขข้อมูลในแม่แบบนี้ล่าสุด |
| is_active | BOOLEAN | DEFAULT TRUE | สถานะใช้งาน |
| workflow_config | JSON | NULL | เก็บ State Machine Configuration หรือ Rules เพิ่มเติมที่ซับซ้อนกว่า Column ปกติ |
**Indexes**:
- ux_routing_template_name_project (template_name, project_id): ดัชนีแบบ UNIQUE ป้องกันการมีชื่อแม่แบบซ้ำกันในแต่ละโครงการ หรือในส่วนของแม่แบบทั่วไป (ที่ project_id เป็น NULL)
**ความสัมพันธ์ Foreign Key:**
- fk_crt_project: อ้างอิงไปยัง projects(id)
- ON DELETE CASCAD`: ถ้าโครงการ (projects) ถูกลบ แม่แบบที่เกี่ยวข้องกับโครงการนั้นๆ จะถูกลบไปด้วยทั้งหมด
---
### 3.10 ตาราง correspondence_routing_template_steps
**Purpose**: เก็บรายละเอียดของแต่ละขั้นตอน (Steps) ภายในแม่แบบสายงาน (correspondence_routing_templates) กำหนดว่าจะส่งไปที่องค์กรไหน ลำดับเป็นเท่าไร และเพื่อวัตถุประสงค์อะไร
| Column Name | Data Type | Constraints | Description |
| :----------------- | --------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | ID หลักของขั้นตอน |
| template_id | INT | NOT NULL | ID ของแม่แบบที่ขั้นตอนนี้สังกัดอยู่ |
| sequence | INT | NOT NULL | ลำดับของขั้นตอน (1, 2, 3, ...) |
| to_organization_id | INT | NOT NULL | ID ขององค์กรที่เป็นผู้รับในขั้นตอนนี้ |
| step_purpose | ENUM | NOT NULL,DEFAULT FOR_REVIEW | วัตถุประสงค์ของการส่งต่อในขั้นตอนนี้ **ค่าที่เป็นไปได้:** [FOR_APPROVAL: เพื่ออนุมัติ, FOR_REVIEW: เพื่อตรวจสอบ/พิจารณา, FOR_INFORMATION: เพื่อทราบ] |
| expected_days | INT | NULL | วันที่คาดหวัง |
**Indexes**:
- ux_cor_template_sequence (template_id, sequence): ดัชนีแบบ UNIQUE ป้องกันการมีลำดับขั้นตอนซ้ำกันภายในแม่แบบเดียวกัน
**ความสัมพันธ์ Foreign Key:**
- fk_cwts_template: อ้างอิงไปยัง correspondence_routing_templates(id)
- ON DELETE CASCADE: ถ้าแม่แบบถูกลบ ขั้นตอนทั้งหมดภายในแม่แบบนั้นจะถูกลบไปด้วย
- fk_cwts_org: อ้างอิงไปยัง organizations(id)
- ON DELETE CASCADE: ถ้าองค์กรถูกลบ ขั้นตอนที่ชี้ไปยังองค์กรนั้นจะถูกลบ
---
### 3.11 ตาราง correspondence_routings
**Purpose**: เป็นตารางที่เก็บข้อมูลการส่งต่อเอกสารจริง (Instance/Run-time) ติดตามประวัติการเคลื่อนย้ายของแต่ละเอกสาร ว่าผ่านใครมาบ้าง อยู่ที่ใคร และสถานะปัจจุบันคืออะไร
| Column Name | Data Type | Constraints | Description |
| -------------------- | --------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | ID หลักของรายการส่งต่อ |
| correspondence_id | INT | NOT NUL | ID ของเอกสาร (FK ไปยัง correspondence_revisions) |
| template_id | INT | NULL | ID ของแม่แบบที่ใช้สร้างสายงานนี้ (เก็บไว้เป็นข้อมูลอ้างอิง) |
| sequence | INT | NOT NULL | ลำดับของขั้นตอนการส่งต่อจริง |
| from_organization_id | INT | NOT NULL | ID ขององค์กรผู้ส่ง |
| to_organization_id | INT | NOT NULL | ID ขององค์กรผู้รับ |
| step_purpose | ENUM | NOT NULL, DEFAULT FOR_REVIEW | วัตถุประสงค์ของการส่งต่อในขั้นตอนนี้จริง **ค่าที่เป็นไปได้:** [FOR_APPROVAL: เพื่ออนุมัติ, FOR_REVIEW: เพื่อตรวจสอบ/พิจารณา, FOR_INFORMATION: เพื่อทราบ, FOR_ACTION: เพื่อดำเนินการ] |
| status | ENUM | NOT NULL, DEFAULT SENT | [ACTIONED: ดำเนินการแล้ว, FORWARDED: ส่งต่อแล้ว, REPLIE: ตอบกลับแล้ว] |
| comments | TEXT | NULL | หมายเหตุหรือความคิดเห็นในการส่งต่อ |
| due_date | DATETIME | NULL | วันที่ครบกำหนดที่ต้องดำเนินการในขั้นตอนนี้ |
| processed_by_user_id | INT | NULL | ID ของผู้ใช้ที่ดำเนินการในขั้นตอนนี้จริงๆ |
| processed_at | TIMESTAMP | NULL | เวลาที่ผู้ใช้ดำเนินการเสร็จสิ้น |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | เวลาที่สร้างรายการส่งต่อนี้ |
| state_context | JSON | NULL | Snapshot ของตัวแปรต่างๆ ใน Workflow ณ จุดนี้ (เช่น ผู้อนุมัติ, เงื่อนไขที่ผ่าน) |
**Indexes**:
- ux_cor_routing_sequence (correspondence_id, sequence): ดัชนีแบบ UNIQUE ทำให้มั่นใจได้ว่าแต่ละเอกสารจะมีขั้นตอนการส่งต่อตามลำดับได้เพียงชุดเดียว
**ความสัมพันธ์ Foreign Key:**
- fk_crs_correspondence: อ้างอิงไปยัง correspondence_revisions(correspondence_id)
- ON DELETE CASCADE`: ถ้าเอกสาร (revision) ถูกลบ ประวัติการส่งต่อทั้งหมดจะถูกลบไปด้วย
- fk_crs_template: อ้างอิงไปยัง correspondence_routing_templates(id)
- ON DELETE SET NULL: ถ้าแม่แบบถูกลบ ค่า template_id ในตารางนี้จะถูกเปลี่ยนเป็น NULL เพื่อรักษาประวัติการส่งต่อไว้
- fk_crs_from_org: อ้างอิงไปยัง organizations(id)
- ON DELETE CASCADE: ถ้าองค์กรผู้ส่งถูกลบ รายการส่งต่อนี้จะถูกลบ
- fk_crs_to_org: อ้างอิงไปยัง organizations(id)
- ON DELETE CASCADE: ถ้าองค์กรผู้รับถูกลบ รายการส่งต่อนี้จะถูกลบ
- fk_crs_processed_by_user: อ้างอิงไปยัง users(user_id)
- ON DELETE SET NULL: ถ้าผู้ใช้ถูกลบ ค่า processed_by_user_id จะถูกเปลี่ยนเป็น NULL เพื่อรักษาประวัติการดำเนินการไว้
---
### 3.12 ตาราง correspondence_status_transitions
**Purpose**: ตารางนี้ใช้กำหนดกฎ (State Machine) ว่าสถานะใดสามารถเปลี่ยนไปเป็นสถานะใดได้บ้าง โดยขึ้นอยู่กับประเภทของหนังสือ เพื่อควบคุมการไหลของสถานะให้ถูกต้องตามข้อบังคับ
| Column Name | Data Type | Constraints | Description |
| -------------- | --------- | ----------- | ------------------------------------------------------ |
| type_id | INT | PRIMARY KEY | ID ของประเภทหนังสือ (เช่น หนังสือภายใน, หนังสือภายนอก) |
| from_status_id | INT | PRIMARY KEY | ID ของสถานะต้นทาง (เช่น ร่าง) |
| to_status_id | INT | PRIMARY KEY | ID ของสถานะปลายทาง (เช่น รออนุมัติ) |
**คีย์หลัก (Primary Key):**
- (type_id, from_status_id, to_status_id)`: คีย์หลักแบบประกอบ ทำให้แน่ใจว่าแต่ละประเภทหนังสือ การเปลี่ยนจากสถานะหนึ่งไปอีกสถานะหนึ่งจะซ้ำกันไม่ได้
**ความสัมพันธ์ Foreign Key:**
- fk_cst_type : อ้างอิงไปยัง correspondence_types(id)
- fk_cst_from : อ้างอิงไปยัง correspondence_status(id)
- fk_cst_to : อ้างอิงไปยัง correspondence_status(id)
- ไม่มีการกำหนด ON DELETE จึงเป็นค่าเริ่มต้น RESTRICT หมายความว่า จะลบประเภทหนังสือหรือสถานะไม่ได้ ถ้ายังมีการใช้งานอยู่ในตารางนี้
---
## **4. 📐 approval: RFA Tables (เอกสารขออนุมัติ, Workflows)**
### 4.1 rfa_types
**Purpose**: Master table for RFA (Request for Approval) types
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | --------------------------- | ------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| type_code | VARCHAR(20) | NOT NULL, UNIQUE | Type code (DWG, DOC, MAT, etc.) |
| type_name | VARCHAR(100) | NOT NULL | Full type name |
| description | TEXT | NULL | Type description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (type_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: rfas
**Seed Data**: 11 RFA types including Shop Drawing (DWG), Document (DOC), Specification (SPC), Calculation (CAL), Test Report (TRP), Survey Report (SRY), QA/QC Document, Method Statement (MES), Material (MAT), As-Built (ASB), Other (OTH)
---
### 4.2 rfa_status_codes
**Purpose**: Master table for RFA status codes
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | --------------------------- | --------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| status_code | VARCHAR(20) | NOT NULL, UNIQUE | Status code (DFT, FAP, FRE, etc.) |
| status_name | VARCHAR(100) | NOT NULL | Full status name |
| description | TEXT | NULL | Status description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (status_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: rfa_revisions
**Seed Data**: 7 status codes
- DFT: Draft
- FAP: For Approve
- FRE: For Review
- FCO: For Construction
- ASB: AS-Built
- OBS: Obsolete
- CC: Canceled
---
### 4.3 rfa_approve_codes
**Purpose**: Master table for RFA approval result codes
| Column Name | Data Type | Constraints | Description |
| ------------ | ------------ | --------------------------- | -------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| approve_code | VARCHAR(20) | NOT NULL, UNIQUE | Approval code (1A, 1C, 3R, etc.) |
| approve_name | VARCHAR(100) | NOT NULL | Full approval name |
| description | TEXT | NULL | Code description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (approve_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: rfa_revisions
**Seed Data**: 8 approval codes
- 1A: Approved by Authority
- 1C: Approved by CSC
- 1N: Approved As Note
- 1R: Approved with Remarks
- 3C: Consultant Comments
- 3R: Revise and Resubmit
- 4X: Reject
- 5N: No Further Action
---
### 4.4 rfas
**Purpose**: Master table for RFA documents (non-revisioned data)
| Column Name | Data Type | Constraints | Description |
| ----------------- | --------- | --------------------------- | -------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Master RFA ID |
| rfa_type_id | INT | NOT NULL, FK | Reference to rfa_types |
| **discipline_id** | **INT** | **NULL, FK** | **Reference to disciplines (if applicable)** |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| created_by | INT | NULL, FK | User who created the record |
| deleted_at | DATETIME | NULL | Soft delete timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (rfa_type_id) REFERENCES rfa_types(id)
- **FOREIGN KEY (discipline_id) REFERENCES disciplines(id) ON DELETE SET NULL**
- FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL
- INDEX (rfa_type_id)
- INDEX (deleted_at)
**Relationships**:
- Parent: rfa_types, **disciplines**, users
- Children: rfa_revisions
**Business Rules**:
- One RFA can have multiple revisions
- Soft delete preserves history
---
### 4.5 rfa_revisions
**Purpose**: Child table storing revision history of RFAs (1:N)
| Column Name | Data Type | Constraints | Description |
| ------------------- | ------------ | --------------------------------- | --------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique revision ID |
| correspondence_id | INT | NOT NULL, FK | Link to correspondence (RFA as correspondence) |
| rfa_id | INT | NOT NULL, FK | Master RFA ID |
| revision_number | INT | NOT NULL | Revision sequence (0, 1, 2...) |
| revision_label | VARCHAR(10) | NULL | Display revision (A, B, 1.1...) |
| is_current | BOOLEAN | DEFAULT FALSE | Current revision flag |
| rfa_status_code_id | INT | NOT NULL, FK | Current RFA status |
| rfa_approve_code_id | INT | NULL, FK | Approval result code |
| title | VARCHAR(255) | NOT NULL | RFA title |
| document_date | DATE | NULL | Document date |
| issued_date | DATE | NULL | Issue date for approval |
| received_date | DATETIME | NULL | Received date |
| approved_date | DATE | NULL | Approval date |
| description | TEXT | NULL | Revision description |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Revision creation timestamp |
| created_by | INT | NULL, FK | User who created revision |
| updated_by | INT | NULL, FK | User who last updated |
| details | JSON | NULL | Type-specific details (e.g., RFI questions) |
| v_ref_drawing_count | INT | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Drawing Count จาก JSON details เพื่อทำ Index |
| schema_version | INT | DEFAULT 1 | Version of the schema used with this details |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- FOREIGN KEY (rfa_id) REFERENCES rfas(id) ON DELETE CASCADE
- FOREIGN KEY (rfa_status_code_id) REFERENCES rfa_status_codes(id)
- FOREIGN KEY (rfa_approve_code_id) REFERENCES rfa_approve_codes(id) ON DELETE SET NULL
- FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL
- FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL
- UNIQUE KEY (rfa_id, revision_number)
- UNIQUE KEY (rfa_id, is_current)
- INDEX (rfa_status_code_id)
- INDEX (rfa_approve_code_id)
- INDEX (is_current)
- INDEX (v_ref_drawing_count): ตัวอย่างการ Index ข้อมูลตัวเลขใน JSON
**Relationships**:
- Parent: correspondences, rfas, rfa_status_codes, rfa_approve_codes, users
- Children: rfa_items, rfa_workflows
**Business Rules**:
- RFA is a specialized type of correspondence
- Only one revision can be current per RFA
- Links to shop drawings through rfa_items
---
### 4.6 rfa_items
**Purpose**: Junction table linking RFA revisions to shop drawing revisions (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------------------ | --------- | --------------- | ------------------------------ |
| rfarev_correspondence_id | INT | PRIMARY KEY, FK | RFA revision correspondence ID |
| shop_drawing_revision_id | INT | PRIMARY KEY, FK | Shop drawing revision ID |
**Indexes**:
- PRIMARY KEY (rfarev_correspondence_id, shop_drawing_revision_id)
- FOREIGN KEY (rfarev_correspondence_id) REFERENCES rfa_revisions(correspondence_id) ON DELETE CASCADE
- FOREIGN KEY (shop_drawing_revision_id) REFERENCES shop_drawing_revisions(id) ON DELETE CASCADE
- INDEX (shop_drawing_revision_id)
**Relationships**:
- Parent: rfa_revisions, shop_drawing_revisions
**Business Rules**:
- Used primarily for RFA type = 'DWG' (Shop Drawing)
- One RFA can contain multiple shop drawings
- One shop drawing can be referenced by multiple RFAs
---
### 4.7 rfa_workflow_templates
**Purpose**: Master table for RFA approval workflow templates
| Column Name | Data Type | Constraints | Description |
| --------------- | ------------ | ----------------------------------- | ------------------------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique template ID |
| template_name | VARCHAR(100) | NOT NULL | Template name |
| description | TEXT | NULL | Template description |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
| workflow_config | JSON | NULL | เก็บ State Machine Configuration หรือ Rules เพิ่มเติมที่ซับซ้อนกว่า Column ปกติ |
**Indexes**:
- PRIMARY KEY (id)
- INDEX (is_active)
- INDEX (template_name)
**Relationships**:
- Children: rfa_workflow_template_steps
**Business Rules**:
- Defines reusable approval workflows for RFAs
- Can be assigned to specific RFA types or organizations
---
### 4.8 rfa_workflow_template_steps
**Purpose**: Child table defining steps in workflow templates
| Column Name | Data Type | Constraints | Description |
| --------------- | --------- | --------------------------- | ----------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique step ID |
| template_id | INT | NOT NULL, FK | Reference to workflow template |
| step_number | INT | NOT NULL | Step sequence order |
| organization_id | INT | NOT NULL, FK | Organization responsible for step |
| role_id | INT | NULL, FK | Required role for this step |
| action_type | ENUM | NULL | Action type: REVIEW, APPROVE, ACKNOWLEDGE |
| duration_days | INT | NULL | Expected duration in days |
| is_optional | BOOLEAN | DEFAULT FALSE | Optional step flag |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (template_id) REFERENCES rfa_workflow_templates(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- FOREIGN KEY (role_id) REFERENCES roles(role_id)
- INDEX (template_id, step_number)
- INDEX (organization_id)
**Relationships**:
- Parent: rfa_workflow_templates, organizations, roles
**Business Rules**:
- Steps are executed in step_number order
- Optional steps can be skipped
- Duration used for deadline calculation
---
### 4.9 rfa_workflows
**Purpose**: Transaction log table tracking actual RFA approval workflow execution
| Column Name | Data Type | Constraints | Description |
| --------------- | --------- | ----------------------------------- | ---------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique workflow log ID |
| rfa_revision_id | INT | NOT NULL, FK | Reference to RFA revision |
| step_number | INT | NOT NULL | Current step number |
| organization_id | INT | NOT NULL, FK | Organization responsible |
| assigned_to | INT | NULL, FK | Assigned user ID |
| action_type | ENUM | NULL | Action type: REVIEW, APPROVE, ACKNOWLEDGE |
| status | ENUM | NULL | Status: PENDING, IN_PROGRESS, COMPLETED, REJECTED |
| comments | TEXT | NULL | Comments/remarks |
| completed_at | DATETIME | NULL | Completion timestamp |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
| state_context | JSON\* | NULL | เก็บข้อมูล Context ของ Workflow ณ ขณะนั้น (Snapshot) |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (rfa_revision_id) REFERENCES rfa_revisions(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- FOREIGN KEY (assigned_to) REFERENCES users(user_id)
- INDEX (rfa_revision_id, step_number)
- INDEX (assigned_to, status)
- INDEX (status)
**Relationships**:
- Parent: rfa_revisions, organizations, users
**Business Rules**:
- Records actual workflow execution history
- Tracks who did what and when
- Multiple records per RFA revision (one per step)
- Status changes tracked via updated_at
### 4.10 disciplines
**Purpose**: Master table for Project Disciplines (สาขางาน) [Added in v1.4.4 based on Req 6B]
| Column Name | Data Type | Constraints | Description |
| --------------- | ------------ | --------------------------- | -------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| contract_id | INT | NOT NULL, FK | Reference to contracts |
| discipline_code | VARCHAR(10) | NOT NULL | Code (e.g., 'GEN', 'STR', 'ARC') |
| code_name_th | VARCHAR(255) | NULL | Thai Name |
| code_name_en | VARCHAR(255) | NULL | English Name |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE CASCADE
- **UNIQUE KEY (contract_id, discipline_code)** - Ensures unique code per contract
**Relationships**:
- Parent: contracts
- Referenced by: rfas, correspondences, document_number_counters
---
### 4.11 correspondence_sub_types
**Purpose**: Master table for Correspondence/RFA Sub-types mapping [Added in v1.4.4 based on Req 6B]
| Column Name | Data Type | Constraints | Description |
| ---------------------- | ------------ | --------------------------- | -------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| contract_id | INT | NOT NULL, FK | Reference to contracts |
| correspondence_type_id | INT | NOT NULL, FK | Reference to correspondence_types |
| sub_type_code | VARCHAR(20) | NOT NULL | Sub-type Code (e.g., 'MAT', 'SHP') |
| sub_type_name | VARCHAR(255) | NULL | Full Name |
| sub_type_number | VARCHAR(10) | NULL | Numeric code for running number (e.g., '11') |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE CASCADE
- FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE
**Relationships**:
- Parent: contracts, correspondence_types
- Referenced by: (Used in logic for Document Numbering)
---
## **5. 📐 Drawings Tables (แบบ, หมวดหมู่)**
### 5.1 contract_drawing_volumes
**Purpose**: Master table for contract drawing volume classification
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | ----------------------------------- | ------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique volume ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| volume_code | VARCHAR(50) | NOT NULL | Volume code |
| volume_name | VARCHAR(255) | NOT NULL | Volume name |
| description | TEXT | NULL | Volume description |
| sort_order | INT | DEFAULT 0 | Display order |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- UNIQUE KEY (project_id, volume_code)
- INDEX (sort_order)
**Relationships**:
- Parent: projects
- Referenced by: contract_drawings
**Business Rules**:
- Volume codes must be unique within a project
- Used for organizing large sets of contract drawings
---
### 5.2 contract_drawing_cats
**Purpose**: Master table for contract drawing main categories
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | ----------------------------------- | ------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique category ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| cat_code | VARCHAR(50) | NOT NULL | Category code |
| cat_name | VARCHAR(255) | NOT NULL | Category name |
| description | TEXT | NULL | Category description |
| sort_order | INT | DEFAULT 0 | Display order |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- UNIQUE KEY (project_id, cat_code)
- INDEX (sort_order)
**Relationships**:
- Parent: projects
- Referenced by: contract_drawing_subcat_cat_maps
**Business Rules**:
- Category codes must be unique within a project
- Hierarchical relationship with sub-categories via mapping table
---
### 5.3 contract_drawing_sub_cats
**Purpose**: Master table for contract drawing sub-categories
| Column Name | Data Type | Constraints | Description |
| ------------ | ------------ | ----------------------------------- | ------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique sub-category ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| sub_cat_code | VARCHAR(50) | NOT NULL | Sub-category code |
| sub_cat_name | VARCHAR(255) | NOT NULL | Sub-category name |
| description | TEXT | NULL | Sub-category description |
| sort_order | INT | DEFAULT 0 | Display order |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- UNIQUE KEY (project_id, sub_cat_code)
- INDEX (sort_order)
**Relationships**:
- Parent: projects
- Referenced by: contract_drawings, contract_drawing_subcat_cat_maps
**Business Rules**:
- Sub-category codes must be unique within a project
- Can be mapped to multiple main categories via mapping table
---
### 5.4 contract_drawing_subcat_cat_maps
**Purpose**: Junction table mapping sub-categories to main categories (M:N)
| Column Name | Data Type | Constraints | Description |
| ----------- | --------- | --------------- | -------------------------- |
| project_id | INT | PRIMARY KEY, FK | Reference to projects |
| sub_cat_id | INT | PRIMARY KEY, FK | Reference to sub-category |
| cat_id | INT | PRIMARY KEY, FK | Reference to main category |
**Indexes**:
- PRIMARY KEY (project_id, sub_cat_id, cat_id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (sub_cat_id) REFERENCES contract_drawing_sub_cats(id) ON DELETE CASCADE
- FOREIGN KEY (cat_id) REFERENCES contract_drawing_cats(id) ON DELETE CASCADE
- INDEX (sub_cat_id)
- INDEX (cat_id)
**Relationships**:
- Parent: projects, contract_drawing_sub_cats, contract_drawing_cats
**Business Rules**:
- Allows flexible categorization
- One sub-category can belong to multiple main categories
- All three fields required for uniqueness
---
### 5.5 contract_drawings
**Purpose**: Master table for contract drawings (from contract specifications)
| Column Name | Data Type | Constraints | Description |
| ----------- | ------------ | ----------------------------------- | ------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique drawing ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| condwg_no | VARCHAR(255) | NOT NULL | Contract drawing number |
| title | VARCHAR(255) | NOT NULL | Drawing title |
| sub_cat_id | INT | NULL, FK | Reference to sub-category |
| volume_id | INT | NULL, FK | Reference to volume |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
| deleted_at | DATETIME | NULL | Soft delete timestamp |
| updated_by | INT | NULL, FK | User who last updated |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (sub_cat_id) REFERENCES contract_drawing_sub_cats(id) ON DELETE RESTRICT
- FOREIGN KEY (volume_id) REFERENCES contract_drawing_volumes(id) ON DELETE RESTRICT
- FOREIGN KEY (updated_by) REFERENCES users(user_id)
- UNIQUE KEY (project_id, condwg_no)
- INDEX (sub_cat_id)
- INDEX (volume_id)
- INDEX (deleted_at)
**Relationships**:
- Parent: projects, contract_drawing_sub_cats, contract_drawing_volumes, users
- Referenced by: shop_drawing_revision_contract_refs, contract_drawing_attachments
**Business Rules**:
- Drawing numbers must be unique within a project
- Represents baseline/contract drawings
- Referenced by shop drawings for compliance tracking
- Soft delete preserves history
---
### 5.6 shop_drawing_main_categories
**Purpose**: Master table for shop drawing main categories (discipline-level)
| Column Name | Data Type | Constraints | Description |
| ------------------ | ------------ | ----------------------------------- | ------------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique category ID |
| main_category_code | VARCHAR(50) | NOT NULL, UNIQUE | Category code (ARCH, STR, MEP, etc.) |
| main_category_name | VARCHAR(255) | NOT NULL | Category name |
| description | TEXT | NULL | Category description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (main_category_code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: shop_drawing_sub_categories, shop_drawings
**Business Rules**:
- Global categories (not project-specific)
- Typically represents engineering disciplines
---
### 5.7 shop_drawing_sub_categories
**Purpose**: Master table for shop drawing sub-categories (component-level)
| Column Name | Data Type | Constraints | Description |
| ----------------- | ------------ | ----------------------------------- | ----------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique sub-category ID |
| sub_category_code | VARCHAR(50) | NOT NULL, UNIQUE | Sub-category code (STR-COLUMN, ARCH-DOOR, etc.) |
| sub_category_name | VARCHAR(255) | NOT NULL | Sub-category name |
| main_category_id | INT | NOT NULL, FK | Reference to main category |
| description | TEXT | NULL | Sub-category description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (sub_category_code)
- FOREIGN KEY (main_category_id) REFERENCES shop_drawing_main_categories(id)
- INDEX (main_category_id)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Parent: shop_drawing_main_categories
- Referenced by: shop_drawings
**Business Rules**:
- Global sub-categories (not project-specific)
- Hierarchical under main categories
- Represents specific drawing types or components
---
### 5.8 shop_drawings
**Purpose**: Master table for shop drawings (contractor-submitted)
| Column Name | Data Type | Constraints | Description |
| ---------------- | ------------ | ----------------------------------- | -------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique drawing ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| drawing_number | VARCHAR(100) | NOT NULL, UNIQUE | Shop drawing number |
| title | VARCHAR(500) | NOT NULL | Drawing title |
| main_category_id | INT | NOT NULL, FK | Reference to main category |
| sub_category_id | INT | NOT NULL, FK | Reference to sub-category |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
| deleted_at | DATETIME | NULL | Soft delete timestamp |
| updated_by | INT | NULL, FK | User who last updated |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (drawing_number)
- FOREIGN KEY (project_id) REFERENCES projects(id)
- FOREIGN KEY (main_category_id) REFERENCES shop_drawing_main_categories(id)
- FOREIGN KEY (sub_category_id) REFERENCES shop_drawing_sub_categories(id)
- FOREIGN KEY (updated_by) REFERENCES users(user_id)
- INDEX (project_id)
- INDEX (main_category_id)
- INDEX (sub_category_id)
- INDEX (deleted_at)
**Relationships**:
- Parent: projects, shop_drawing_main_categories, shop_drawing_sub_categories, users
- Children: shop_drawing_revisions
**Business Rules**:
- Drawing numbers are globally unique across all projects
- Represents contractor shop drawings
- Can have multiple revisions
- Soft delete preserves history
---
### 5.9 shop_drawing_revisions
**Purpose**: Child table storing revision history of shop drawings (1:N)
| Column Name | Data Type | Constraints | Description |
| --------------- | ----------- | --------------------------- | ------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique revision ID |
| shop_drawing_id | INT | NOT NULL, FK | Master shop drawing ID |
| revision_number | INT | NOT NULL | Revision sequence (0, 1, 2...) |
| revision_label | VARCHAR(10) | NULL | Display revision (A, B, C...) |
| revision_date | DATE | NULL | Revision date |
| description | TEXT | NULL | Revision description/changes |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Revision creation timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (shop_drawing_id) REFERENCES shop_drawings(id) ON DELETE CASCADE
- UNIQUE KEY (shop_drawing_id, revision_number)
- INDEX (revision_date)
**Relationships**:
- Parent: shop_drawings
- Referenced by: rfa_items, shop_drawing_revision_contract_refs, shop_drawing_revision_attachments
**Business Rules**:
- Revision numbers are sequential starting from 0
- Each revision can reference multiple contract drawings
- Each revision can have multiple file attachments
- Linked to RFAs for approval tracking
---
### 5.10 shop_drawing_revision_contract_refs
**Purpose**: Junction table linking shop drawing revisions to referenced contract drawings (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------------------ | --------- | --------------- | ---------------------------------- |
| shop_drawing_revision_id | INT | PRIMARY KEY, FK | Reference to shop drawing revision |
| contract_drawing_id | INT | PRIMARY KEY, FK | Reference to contract drawing |
**Indexes**:
- PRIMARY KEY (shop_drawing_revision_id, contract_drawing_id)
- FOREIGN KEY (shop_drawing_revision_id) REFERENCES shop_drawing_revisions(id) ON DELETE CASCADE
- FOREIGN KEY (contract_drawing_id) REFERENCES contract_drawings(id) ON DELETE CASCADE
- INDEX (contract_drawing_id)
**Relationships**:
- Parent: shop_drawing_revisions, contract_drawings
**Business Rules**:
- Tracks which contract drawings each shop drawing revision is based on
- Ensures compliance with contract specifications
- One shop drawing revision can reference multiple contract drawings
---
## **6. 🔄 Circulations Tables (ใบเวียนภายใน)**
### 6.1 circulation_status_codes
**Purpose**: Master table for circulation workflow status codes
| Column Name | Data Type | Constraints | Description |
| ----------- | ----------- | --------------------------- | --------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique status ID |
| code | VARCHAR(20) | NOT NULL, UNIQUE | Status code (OPEN, IN_REVIEW, COMPLETED, CANCELLED) |
| description | VARCHAR(50) | NOT NULL | Status description |
| sort_order | INT | DEFAULT 0 | Display order |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (code)
- INDEX (is_active)
- INDEX (sort_order)
**Relationships**:
- Referenced by: circulations
**Seed Data**: 4 status codes
- OPEN: Initial status when created
- IN_REVIEW: Under review by recipients
- COMPLETED: All recipients have responded
- CANCELLED: Withdrawn/cancelled
---
### 6.2 circulations
**Purpose**: Master table for internal circulation sheets (document routing)
| Column Name | Data Type | Constraints | Description |
| ----------------------- | ------------ | ----------------------------------- | ----------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique circulation ID |
| correspondence_id | INT | UNIQUE, FK | Link to correspondence (1:1 relationship) |
| organization_id | INT | NOT NULL, FK | Organization that owns this circulation |
| circulation_no | VARCHAR(100) | NOT NULL | Circulation sheet number |
| circulation_subject | VARCHAR(500) | NOT NULL | Subject/title |
| circulation_status_code | VARCHAR(20) | NOT NULL, FK | Current status code |
| created_by_user_id | INT | NOT NULL, FK | User who created circulation |
| submitted_at | TIMESTAMP | NULL | Submission timestamp |
| closed_at | TIMESTAMP | NULL | Closure timestamp |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE (correspondence_id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id)
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- FOREIGN KEY (circulation_status_code) REFERENCES circulation_status_codes(code)
- FOREIGN KEY (created_by_user_id) REFERENCES users(user_id)
- INDEX (organization_id)
- INDEX (circulation_status_code)
- INDEX (created_by_user_id)
**Relationships**:
- Parent: correspondences, organizations, circulation_status_codes, users
- Children: circulation_routings, circulation_attachments
**Business Rules**:
- Internal document routing within organization
- One-to-one relationship with correspondences
- Tracks document review/approval workflow
- Status progression: OPEN → IN_REVIEW → COMPLETED/CANCELLED
---
### 6.3 circulation_templates
**Purpose**: Master table for circulation workflow templates
| Column Name | Data Type | Constraints | Description |
| --------------- | ------------ | ----------------------------------- | --------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique template ID |
| template_name | VARCHAR(100) | NOT NULL | Template name |
| description | TEXT | NULL | Template description |
| organization_id | INT | NOT NULL, FK | Template owner organization |
| is_active | TINYINT(1) | DEFAULT 1 | Active status |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- INDEX (organization_id)
- INDEX (is_active)
**Relationships**:
- Parent: organizations
- Children: circulation_template_assignees
**Business Rules**:
- Organization-specific templates
- Defines reusable routing workflows
---
### 6.4 circulation_template_assignees
**Purpose**: Child table defining steps in circulation templates
| Column Name | Data Type | Constraints | Description |
| --------------- | --------- | --------------------------- | --------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique step ID |
| template_id | INT | NOT NULL, FK | Reference to template |
| step_number | INT | NOT NULL | Step sequence order |
| organization_id | INT | NOT NULL, FK | Organization responsible for step |
| role_id | INT | NULL, FK | Required role for this step |
| duration_days | INT | NULL | Expected duration in days |
| is_optional | BOOLEAN | DEFAULT FALSE | Optional step flag |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (template_id) REFERENCES circulation_templates(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- FOREIGN KEY (role_id) REFERENCES roles(role_id)
- INDEX (template_id, step_number)
- INDEX (organization_id)
**Relationships**:
- Parent: circulation_templates, organizations, roles
**Business Rules**:
- Steps executed in step_number order
- Optional steps can be skipped
- Duration used for deadline calculation
---
### 6.5 circulation_routings
**Purpose**: Transaction log table tracking actual circulation routing execution
| Column Name | Data Type | Constraints | Description |
| --------------- | --------- | ----------------------------------- | ------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique routing log ID |
| circulation_id | INT | NOT NULL, FK | Reference to circulation |
| step_number | INT | NOT NULL | Current step number |
| organization_id | INT | NOT NULL, FK | Organization responsible |
| assigned_to | INT | NULL, FK | Assigned user ID |
| status | ENUM | NULL | Status: PENDING, IN_PROGRESS, COMPLETED, REJECTED |
| comments | TEXT | NULL | Comments/remarks |
| completed_at | DATETIME | NULL | Completion timestamp |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (circulation_id) REFERENCES circulations(id) ON DELETE CASCADE
- FOREIGN KEY (organization_id) REFERENCES organizations(id)
- FOREIGN KEY (assigned_to) REFERENCES users(user_id)
- INDEX (circulation_id, step_number)
- INDEX (assigned_to, status)
- INDEX (status)
**Relationships**:
- Parent: circulations, organizations, users
**Business Rules**:
- Records actual routing history
- Multiple records per circulation (one per step)
- Tracks who reviewed/approved and when
- Used in v_user_tasks view for pending items
---
## **7. 📤 Transmittals Tables (เอกสารนำส่ง)**
### 7.1 transmittals
**Purpose**: Child table for transmittal-specific data (1:1 with correspondences)
| Column Name | Data Type | Constraints | Description |
| ----------------- | --------- | --------------- | --------------------------------------------------------- |
| correspondence_id | INT | PRIMARY KEY, FK | Reference to correspondences (1:1) |
| purpose | ENUM | NULL | Purpose: FOR_APPROVAL, FOR_INFORMATION, FOR_REVIEW, OTHER |
| remarks | TEXT | NULL | Additional remarks |
**Indexes**:
- PRIMARY KEY (correspondence_id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- INDEX (purpose)
**Relationships**:
- Parent: correspondences
- Children: transmittal_items
**Business Rules**:
- One-to-one relationship with correspondences
- Transmittal is a correspondence type for forwarding documents
- Contains metadata about the transmission
---
### 7.2 transmittal_items
**Purpose**: Junction table listing documents included in transmittal (M:N)
| Column Name | Data Type | Constraints | Description |
| ---------------------- | ------------ | --------------------------- | --------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique item ID |
| transmittal_id | INT | NOT NULL, FK | Reference to transmittal |
| item_correspondence_id | INT | NOT NULL, FK | Reference to document being transmitted |
| quantity | INT | DEFAULT 1 | Number of copies |
| remarks | VARCHAR(255) | NULL | Item-specific remarks |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (transmittal_id) REFERENCES transmittals(correspondence_id) ON DELETE CASCADE
- FOREIGN KEY (item_correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- UNIQUE KEY (transmittal_id, item_correspondence_id)
- INDEX (item_correspondence_id)
**Relationships**:
- Parent: transmittals, correspondences
**Business Rules**:
- One transmittal can contain multiple documents
- Tracks quantity of physical copies (if applicable)
- Links to any type of correspondence document
---
## **8. 📎 File Management Tables (ไฟล์แนบ)**
### 8.1 attachments
**Purpose**: Central repository for all file attachments in the system
| Column Name | Data Type | Constraints | Description |
| ------------------- | ------------ | --------------------------- | -------------------------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique attachment ID |
| original_filename | VARCHAR(255) | NOT NULL | Original filename from upload |
| stored_filename | VARCHAR(255) | NOT NULL | System-generated unique filename |
| file_path | VARCHAR(500) | NOT NULL | Full file path on server (/share/dms-data/) |
| mime_type | VARCHAR(100) | NOT NULL | MIME type (application/pdf, image/jpeg, etc.) |
| file_size | INT | NOT NULL | File size in bytes |
| uploaded_by_user_id | INT | NOT NULL, FK | User who uploaded file |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Upload timestamp |
| is_temporary | BOOLEAN | DEFAULT TRUE | ระบุว่าเป็นไฟล์ชั่วคราว (ยังไม่ได้ Commit) |
| temp_id\* | VARCHAR(100) | NULL | ID ชั่วคราวสำหรับอ้างอิงตอน Upload Phase 1 (อาจใช้ร่วมกับ id หรือแยกก็ได้) |
| expires_at | DATETIME | NULL | เวลาหมดอายุของไฟล์ Temp (เพื่อให้ Cron Job ลบออก) |
| checksum | VARCHAR(64) | NULL | SHA-256 Checksum สำหรับ Verify File Integrity [Req 3.9.3] |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (uploaded_by_user_id) REFERENCES users(user_id) ON DELETE CASCADE
- INDEX (stored_filename)
- INDEX (mime_type)
- INDEX (uploaded_by_user_id)
- INDEX (created_at)
**Relationships**:
- Parent: users
- Referenced by: correspondence_attachments, circulation_attachments, shop_drawing_revision_attachments, contract_drawing_attachments
**Business Rules**:
- Central storage prevents file duplication
- Stored filename prevents naming conflicts
- File path points to QNAP NAS storage
- Original filename preserved for download
- One file record can be linked to multiple documents
---
### 8.2 correspondence_attachments
**Purpose**: Junction table linking correspondences to file attachments (M:N)
| Column Name | Data Type | Constraints | Description |
| ----------------- | --------- | --------------- | ---------------------------- |
| correspondence_id | INT | PRIMARY KEY, FK | Reference to correspondences |
| attachment_id | INT | PRIMARY KEY, FK | Reference to attachments |
| is_main_document | BOOLEAN | DEFAULT FALSE | Main/primary document flag |
**Indexes**:
- PRIMARY KEY (correspondence_id, attachment_id)
- FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
- FOREIGN KEY (attachment_id) REFERENCES attachments(id) ON DELETE CASCADE
- INDEX (attachment_id)
- INDEX (is_main_document)
**Relationships**:
- Parent: correspondences, attachments
**Business Rules**:
- One correspondence can have multiple attachments
- One attachment can be linked to multiple correspondences
- is_main_document identifies primary file (typically PDF)
---
### 8.3 circulation_attachments
**Purpose**: Junction table linking circulations to file attachments (M:N)
| Column Name | Data Type | Constraints | Description |
| ---------------- | --------- | --------------- | -------------------------- |
| circulation_id | INT | PRIMARY KEY, FK | Reference to circulations |
| attachment_id | INT | PRIMARY KEY, FK | Reference to attachments |
| is_main_document | BOOLEAN | DEFAULT FALSE | Main/primary document flag |
**Indexes**:
- PRIMARY KEY (circulation_id, attachment_id)
- FOREIGN KEY (circulation_id) REFERENCES circulations(id) ON DELETE CASCADE
- FOREIGN KEY (attachment_id) REFERENCES attachments(id) ON DELETE CASCADE
- INDEX (attachment_id)
- INDEX (is_main_document)
**Relationships**:
- Parent: circulations, attachments
---
### 8.4 shop_drawing_revision_attachments
**Purpose**: Junction table linking shop drawing revisions to file attachments (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------------------ | --------- | --------------- | ---------------------------------- |
| shop_drawing_revision_id | INT | PRIMARY KEY, FK | Reference to shop drawing revision |
| attachment_id | INT | PRIMARY KEY, FK | Reference to attachments |
| file_type | ENUM | NULL | File type: PDF, DWG, SOURCE, OTHER |
| is_main_document | BOOLEAN | DEFAULT FALSE | Main/primary document flag |
**Indexes**:
- PRIMARY KEY (shop_drawing_revision_id, attachment_id)
- FOREIGN KEY (shop_drawing_revision_id) REFERENCES shop_drawing_revisions(id) ON DELETE CASCADE
- FOREIGN KEY (attachment_id) REFERENCES attachments(id) ON DELETE CASCADE
- INDEX (attachment_id)
- INDEX (file_type)
- INDEX (is_main_document)
**Relationships**:
- Parent: shop_drawing_revisions, attachments
**Business Rules**:
- file_type categorizes drawing file formats
- Typically includes PDF for viewing and DWG for editing
- SOURCE may include native CAD files
---
### 8.5 contract_drawing_attachments
**Purpose**: Junction table linking contract drawings to file attachments (M:N)
| Column Name | Data Type | Constraints | Description |
| ------------------- | --------- | --------------- | ---------------------------------- |
| contract_drawing_id | INT | PRIMARY KEY, FK | Reference to contract drawing |
| attachment_id | INT | PRIMARY KEY, FK | Reference to attachments |
| file_type | ENUM | NULL | File type: PDF, DWG, SOURCE, OTHER |
| is_main_document | BOOLEAN | DEFAULT FALSE | Main/primary document flag |
**Indexes**:
- PRIMARY KEY (contract_drawing_id, attachment_id)
- FOREIGN KEY (contract_drawing_id) REFERENCES contract_drawings(id) ON DELETE CASCADE
- FOREIGN KEY (attachment_id) REFERENCES attachments(id) ON DELETE CASCADE
- INDEX (attachment_id)
- INDEX (file_type)
- INDEX (is_main_document)
**Relationships**:
- Parent: contract_drawings, attachments
---
## **9. 🔢 Document Numbering Tables (การสร้างเลขที่เอกสาร)**
### 9.1 document_number_formats
**Purpose**: Master table defining document numbering templates per project and type
| Column Name | Data Type | Constraints | Description |
| ---------------------- | ------------ | ----------------------------------- | -------------------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique format ID |
| project_id | INT | NOT NULL, FK | Reference to projects |
| correspondence_type_id | INT | NOT NULL, FK | Reference to correspondence types |
| format_template | VARCHAR(255) | NOT NULL | Template string (e.g., '{ORG_CODE}-{TYPE_CODE}-{SEQ:4}') |
| description | TEXT | NULL | Format description |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Record creation timestamp |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | Last update timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
- FOREIGN KEY (correspondence_type_id) REFERENCES correspondence_types(id) ON DELETE CASCADE
- UNIQUE KEY (project_id, correspondence_type_id)
- INDEX (project_id)
- INDEX (correspondence_type_id)
**Relationships**:
- Parent: projects, correspondence_types
**Business Rules**:
- One format template per project per correspondence type combination
- Template placeholders: {ORG_CODE}, {TYPE_CODE}, {YEAR}, {SEQ:n} where n is zero-padding length
- Used by document numbering module to generate unique document numbers
---
### 9.2 document_number_counters
**Purpose**: Transaction table maintaining running sequence numbers for document numbering
| Column Name | Data Type | Constraints | Description |
| -------------------------- | --------- | --------------- | ---------------------------------------------------- |
| project_id | INT | PRIMARY KEY, FK | Reference to projects |
| originator_organization_id | INT | PRIMARY KEY, FK | Originating organization |
| correspondence_type_id | INT | PRIMARY KEY, FK | Reference to correspondence types |
| **discipline_id** | **INT** | **PRIMARY KEY** | **Discipline ID (0 if not applicable)** |
| current_year | INT | PRIMARY KEY | Year (Buddhist calendar) |
| version | INT | DEFAULT 0 | ใช้สำหรับ Optimistic Locking (ตรวจสอบค่าก่อน Update) |
| last_number | INT | DEFAULT 0 | Last assigned sequence number |
**Indexes**:
- **PRIMARY KEY (project_id, originator_organization_id, correspondence_type_id, discipline_id, current_year)**
- 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
- INDEX (project_id)
- INDEX (originator_organization_id)
- INDEX (correspondence_type_id)
- INDEX (current_year)
**Relationships**:
- Parent: projects, organizations, correspondence_types
**Business Rules**:
- **Updated v1.4.4:** Composite primary key now includes `discipline_id` to support independent running numbers per discipline (e.g., STR-001, ARC-001).
- Counter resets each year
- Thread-safe increments handled by DocumentNumberingService in NestJS using Redis Lock and Optimistic Locking on version column
- last_number tracks highest assigned number
- Used with document_number_formats to generate complete document numbers
---
## **10. ⚙️ System & Logs Tables (ระบบและ Log)**
### 10.1 audit_logs
**Purpose**: Comprehensive audit trail for all significant system actions
| Column Name | Data Type | Constraints | Description |
| ---------------- | ----------------------------------------- | --------------------------------- | ------------------------------------------------------------ |
| audit_id | BIGINT | PRIMARY KEY, AUTO_INCREMENT | Unique audit log ID |
| user_id | INT | NULL, FK | User who performed action |
| action | VARCHAR(100) | NOT NULL | Action code (e.g., 'rfa.create', 'login.success') |
| entity_type | VARCHAR(50) | NULL | Entity/module affected (e.g., 'rfa', 'correspondence') |
| entity_id | VARCHAR(50) | NULL | Primary ID of affected record |
| details_json | JSON | NULL | Additional context/details in JSON format |
| ip_address | VARCHAR(45) | NULL | Client IP address (supports IPv6) |
| user_agent | VARCHAR(255) | NULL | Browser user agent string |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Action timestamp |
| v_ref_project_id | INT | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Project ID จาก JSON details เพื่อทำ Index |
| v_ref_type | VARCHAR(50) | GENERATED ALWAYS AS (...) VIRTUAL | Virtual Column ดึง Type จาก JSON details |
| request_id | VARCHAR(100) | NULL | Request ID/Trace ID เพื่อเชื่อมโยงกับ App Logs |
| severity | ENUM('INFO', 'WARN', 'ERROR', 'CRITICAL') | NULL | ระดับความรุนแรงของเหตุการณ์ |
**Indexes**:
- PRIMARY KEY (audit_id)
- FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL
- INDEX (user_id)
- INDEX (action)
- INDEX (entity_type, entity_id)
- INDEX (created_at)
- INDEX (ip_address)
- INDEX (v_ref_project_id)
- INDEX (v_ref_type)
**Relationships**:
- Parent: users
**Business Rules**:
- Immutable records (no updates/deletes)
- Captures all CRUD operations on sensitive data
- Includes authentication events (login, logout, failed attempts)
- JSON details field for flexible data storage
- Retention policy: typically 7 years for compliance
- Used for security audits, compliance reporting, and troubleshooting
**Common Actions**:
- Authentication: login.success, login.failed, logout
- Documents: correspondence.create, correspondence.update, rfa.submit
- Users: user.create, user.deactivate, role.assign
- Workflow: rfa.approve, rfa.reject, circulation.complete
---
### 10.2 notifications
**Purpose**: User notification queue for email, LINE, and in-system alerts
| Column Name | Data Type | Constraints | Description |
| ----------------- | ------------ | --------------------------- | ------------------------------------------------ |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique notification ID |
| user_id | INT | NOT NULL, FK | Recipient user ID |
| title | VARCHAR(255) | NOT NULL | Notification title/subject |
| message | TEXT | NOT NULL | Notification message body |
| notification_type | ENUM | NOT NULL | Type: EMAIL, LINE, SYSTEM |
| is_read | BOOLEAN | DEFAULT FALSE | Read status flag |
| entity_type | VARCHAR(50) | NULL | Related entity type (e.g., 'rfa', 'circulation') |
| entity_id | INT | NULL | Related entity ID |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Notification creation timestamp |
**Indexes**:
- PRIMARY KEY (id)
- FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
- INDEX (user_id)
- INDEX (notification_type)
- INDEX (is_read)
- INDEX (entity_type, entity_id)
- INDEX (created_at)
- COMPOSITE INDEX (user_id, is_read, created_at) - For user notification listing
**Relationships**:
- Parent: users
**Business Rules**:
- EMAIL: Sent via SMTP to user's email address
- LINE: Sent via LINE Notify API to user's LINE ID
- SYSTEM: In-app notifications displayed in user interface
- Same notification can trigger multiple types (EMAIL + SYSTEM)
- entity_type/entity_id allow deep-linking to related records
- is_read flag only applicable for SYSTEM notifications
- Auto-cleanup: delete read notifications older than 30 days
**Common Notification Triggers**:
- Task assignment (circulation routing, RFA workflow)
- Document status changes (submitted, approved, rejected)
- Approaching deadlines
- System announcements
- Mention in comments
---
### 10.3 search_indices
**Purpose**: Full-text search index for document content
| Column Name | Data Type | Constraints | Description |
| ----------- | ----------- | --------------------------- | ------------------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique index ID |
| entity_type | VARCHAR(50) | NOT NULL | Entity type (e.g., 'correspondence', 'rfa') |
| entity_id | INT | NOT NULL | Entity primary ID |
| content | TEXT | NOT NULL | Searchable text content |
| indexed_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Last indexing timestamp |
**Indexes**:
- PRIMARY KEY (id)
- INDEX (entity_type, entity_id)
- INDEX (indexed_at)
**Business Rules**:
- Automatically populated/updated when documents change
- Content includes: title, description, document number, metadata
- May include OCR text from PDF attachments (future enhancement)
- Used by advanced search functionality
- Periodic re-indexing to catch missed updates
- Supports Boolean operators, phrase searching
**Search Features**:
- Natural language queries
- Wildcard support (\*, ?)
- Boolean operators (AND, OR, NOT)
- Phrase matching with quotes
- Result ranking by relevance
---
### 10.4 backup_logs
**Purpose**: Log table tracking database and file backup operations
| Column Name | Data Type | Constraints | Description |
| ------------- | ------------ | --------------------------- | ---------------------------------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Unique backup log ID |
| backup_type | ENUM | NOT NULL | Type: DATABASE, FILES, FULL |
| backup_path | VARCHAR(500) | NOT NULL | Path to backup file/directory |
| file_size | BIGINT | NULL | Backup file size in bytes |
| status | ENUM | NOT NULL | Status: STARTED, COMPLETED, FAILED |
| started_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Backup start timestamp |
| completed_at | TIMESTAMP | NULL | Backup completion timestamp |
| error_message | TEXT | NULL | Error details if failed |
**Indexes**:
- PRIMARY KEY (id)
- INDEX (backup_type)
- INDEX (status)
- INDEX (started_at)
- INDEX (completed_at)
**Business Rules**:
- DATABASE: MariaDB dump of database schema and data
- FILES: Backup of attachment files from QNAP storage
- FULL: Complete system backup (database + files)
- Triggered by n8n cron jobs
- Backup retention policy defined in backup strategy
- Failed backups trigger alert notifications
- completed_at - started_at = backup duration
**Monitoring**:
- Alert if no successful backup in 24 hours
- Track backup size trends over time
- Verify backup integrity with test restores
---
### 10.5 json_schemas
**Purpose**: องรับ **Centralized JSON Schema Registry** เพื่อ Validate ข้อมูล JSON Details ของเอกสารแต่ละประเภท ตาม Requirements 6.11.1 และ Backend Plan T2.5.1
| Column Name | Data Type | Constraints | Description |
| :-------------------- | :------------- | :--------------- | :----------------------------------------------------------- |
| **id** | `INT` | PK, AI | Unique Identifier |
| **schema_code** | `VARCHAR(100)` | UNIQUE, NOT NULL | รหัส Schema (เช่น `RFA_DWG_V1`, `CORR_RFI_V1`) |
| **version** | `INT` | NOT NULL | เวอร์ชันของ Schema |
| **table_name** | `VARCHAR(100)` | NOT NULL | ชื่อตารางที่ Schema นี้ผูกอยู่ (เช่น rfa_revisions) |
| **schema_definition** | `JSON` | NOT NULL | โครงสร้าง JSON Schema (Standard JSON Schema format) |
| **ui_schema** | `JSON` | NULL | โครงสร้าง UI Schema สำหรับ Frontend Form Generator |
| **virtual_columns** | `JSON` | NULL | Config สำหรับสร้าง Generated Columns ใน DB เพื่อ Performance |
| **migration_script** | `JSON` | NULL | Rules สำหรับแปลงข้อมูลจากเวอร์ชันก่อนหน้า (Migration) |
| **is_active** | `BOOLEAN` | DEFAULT TRUE | สถานะการใช้งาน |
| **created_at** | `TIMESTAMP` | | วันที่สร้าง |
| **updated_at** | `TIMESTAMP` | | วันที่อัปเดต |
**Indexes**:
- UNIQUE KEY (schema_code, version): ป้องกัน Version ซ้ำใน Schema เดียวกัน
### 10.6 user_preferences
**Purpose**: แยกข้อมูลการตั้งค่าส่วนตัว (เช่น Notification Settings) ออกจากตาราง Users เพื่อความยืดหยุ่น ตาม Requirements 5.5 และ 6.8.3
| Column Name | Data Type | Constraints | Description |
| :--------------- | :------------ | :-------------- | :---------------------------------------- |
| **user_id** | `INT` | PK, FK | อ้างอิงตาราง users |
| **notify_email** | `BOOLEAN` | DEFAULT TRUE | รับแจ้งเตือนทางอีเมล |
| **notify_line** | `BOOLEAN` | DEFAULT TRUE | รับแจ้งเตือนทาง LINE |
| **digest_mode** | `BOOLEAN` | DEFAULT TRUE | รับแจ้งเตือนแบบรวม (Digest) แทน Real-time |
| **ui_theme** | `VARCHAR(20)` | DEFAULT 'light' | ธีมหน้าจอ (Light/Dark) |
| **updated_at** | `TIMESTAMP` | | วันที่แก้ไขล่าสุด |
## **11. 📊 Views & Procedures (วิว และ โปรซีเดอร์)**
### 11.1 v_current_correspondences
**Purpose**: View showing current revision of all non-RFA correspondences
**Columns**:
- correspondence_id, correspondence_number, correspondence_type_id/code/name
- project_id, project_code, project_iname
- organization_id, organization_code, organization_name
- revision_id, revision_number, revision_label
- title, document_date, issued_date, received_date, due_date
- correspondence_status_id, correspondence_status_code, correspondence_status_name
- created_by, created_by_username, revision_created_at
**Filters**:
- is_current = TRUE (only latest revision)
- correspondence_type NOT IN ('RFA') (excludes RFAs)
- deleted_at IS NULL (excludes soft-deleted records)
**Business Rules**:
- Provides flattened view of current correspondence state
- Joins correspondence_revisions with is_current flag
- Used by dashboard, document listing screens
- Excludes RFAs (they have separate view)
---
### 11.2 v_current_rfas
**Purpose**: View showing current revision of all RFA documents
**Columns**:
- rfa_id, rfa_type_id, rfa_type_code, rfa_type_name
- correspondence_id, correspondence_number
- project_id, project_code, project_iname
- organization_id, organization_name
- revision_id, revision_number, revision_label
- title, document_date, issued_date, received_date, approved_date
- rfa_status_code_id, rfa_status_code, rfa_status_name
- rfa_approve_code_id, rfa_approve_code, rfa_approve_code_name
- created_by, created_by_username, revision_created_at
**Filters**:
- is_current = TRUE
- deleted_at IS NULL (both rfas and correspondences)
**Business Rules**:
- Specialized view for RFA documents
- Includes RFA-specific fields (approval codes, approved date)
- Joins across rfas → rfa_revisions → correspondences
- Used by RFA management screens
---
### 11.3 v_contract_parties_all
**Purpose**: View showing all organization relationships across contracts and projects
**Columns**:
- contract_id, contract_code, contract_name
- project_id, project_code, project_iname
- organization_id, organization_code, organization_name
- role_in_contract
**Business Rules**:
- Joins contracts → projects → contract_organizations → organizations
- Shows only active contracts (is_active = TRUE)
- Used for permission checks and document routing
- Supports multi-organization projects/contracts
---
### 11.4 v_user_tasks
**Purpose**: View showing pending tasks assigned to users (action items)
**Columns**:
- routing_id, circulation_id, circulation_no, circulation_subject
- correspondence_id, correspondence_number
- project_id, project_code, project_name
- user_id, username, first_name, last_name
- organization_id, organization_name
- step_number, task_status, comments
- completed_at, assigned_at, circulation_created_at
**Filters**:
- status IN ('PENDING', 'IN_PROGRESS')
- assigned_to IS NOT NULL
**Business Rules**:
- Shows circulation routings requiring user action
- Used for "My Tasks" / "Inbox" functionality
- Excludes completed/cancelled tasks
- Ordered by creation date (oldest first)
---
### 11.5 v_audit_log_details
**Purpose**: View enriching audit logs with user information
**Columns**:
- audit_id, user_id, username, email, first_name, last_name
- action, entity_type, entity_id
- details_json, ip_address, user_agent
- created_at
**Business Rules**:
- Joins audit_logs with users table
- Used for audit trail reports
- Includes user details even if user later deleted (LEFT JOIN)
---
### 11.6 v_user_all_permissions
**Purpose**: View showing all effective permissions for users across all scopes
**Columns**:
- user_id, role_id, role_name
- permission_id, permission_name
- module, scope_level
- organization_id, project_id, contract_id
- permission_scope (GLOBAL, ORGANIZATION, PROJECT, CONTRACT)
**Business Rules**:
- UNION of permissions from Global, Organization, Project, and Contract scopes
- Used for authorization checks
- Considers role-permission mappings at all levels
- Only shows active permissions (is_active = 1)
- One row per user-permission-scope combination
**Usage Example**:
```sql
SELECT permission_name
FROM v_user_all_permissions
WHERE user_id = ?
AND project_id = ?
AND permission_name = 'document.edit';
```
---
### 11.7 v_documents_with_attachments
**Purpose**: View showing all documents and their attachment counts
**Columns**:
- document_type (CORRESPONDENCE, CIRCULATION, SHOP_DRAWING, CONTRACT_DRAWING)
- document_id, document_number
- project_id, project_code, project_name
- attachment_count, latest_attachment_date
**Business Rules**:
- UNION of all document types with attachments
- Used for document listing with file indicators
- Helps identify documents missing attachments
- Aggregates count per document
---
### 11.8 v_document_statistics
**Purpose**: View providing aggregated document statistics by project, type, and status
**Columns**:
- project_id, project_code, project_name
- correspondence_type_id, correspondence_type_code, correspondence_type_name
- status_id, status_code, status_name
- document_count, revision_count
**Business Rules**:
- CROSS JOIN creates all possible combinations
- LEFT JOIN shows zeros for combinations with no documents
- Only includes active projects, types, and statuses
- Used for dashboard charts and reports
- Groups by project → type → status
---
## Database Indexes Summary
### Performance Optimization Indexes
**Primary Indexes** (automatic with PRIMARY KEY):
- All tables have PRIMARY KEY with AUTO_INCREMENT
**Foreign Key Indexes** (automatic with FOREIGN KEY):
- All FK relationships automatically indexed
**Additional Performance Indexes**:
1. **Correspondence Tables**:
- `idx_correspondences_type_project` on (correspondence_type_id, project_id)
- `idx_corr_revisions_current_status` on (is_current, correspondence_status_id)
- `idx_corr_revisions_correspondence_current` on (correspondence_id, is_current)
- `idx_correspondences_project_type` on (project_id, correspondence_type_id)
2. **RFA Tables**:
- `idx_rfa_revisions_current_status` on (is_current, rfa_status_code_id)
- `idx_rfa_revisions_rfa_current` on (rfa_id, is_current)
3. **Circulation Tables**:
- `idx_circulation_routings_status_assigned` on (status, assigned_to)
- `idx_circulation_routings_circulation_status` on (circulation_id, status)
4. **Document Numbering**:
- `idx_doc_counter_composite` on (project_id, originator_organization_id, correspondence_type_id, current_year)
5. **Audit & Notifications**:
- `idx_audit_logs_reporting` on (created_at, entity_type, action)
- `idx_notifications_user_unread` on (user_id, is_read, created_at)
---
## Data Integrity Constraints
### Foreign Key Constraints
**Cascade Delete**:
- Parent-child relationships where child should be deleted with parent
- Examples: correspondence_revisions, shop_drawing_revisions, project/contract relationships
**Restrict Delete**:
- Prevents deletion if references exist
- Examples: correspondence_types, rfa_status_codes, organizations (when referenced)
**Set NULL**:
- Preserves record but removes reference
- Examples: originator_id, created_by, updated_by
### Unique Constraints
1. **Globally Unique**:
- usernames, emails
- shop_drawing.drawing_number
2. **Unique Within Scope**:
- (project_id, correspondence_number)
- (project_id, condwg_no)
- (correspondence_id, revision_number)
- (rfa_id, revision_number)
3. **Composite Unique**:
- (correspondence_id, is_current) - ensures only one current revision
- (project_id, correspondence_type_id) - in document_number_formats
### Check Constraints
1. **user_assignments.chk_scope**:
- Ensures only one scope field (organization_id, project_id, contract_id) is NOT NULL
- OR all are NULL for Global scope
### Business Rule Constraints
1. **Soft Delete Pattern**:
- deleted_at timestamp instead of hard delete
- Preserves audit trail and relationships
- Applied to: correspondences, rfas, shop_drawings, contract_drawings
2. **Current Revision Pattern**:
- is_current flag with UNIQUE constraint
- Ensures only one current revision per document
3. **Sequential Numbering**:
- revision_number starts at 0, increments by 1
- Enforced by application logic + stored procedure
---
## Security & Permissions Model
### Access Control Hierarchy
```tree
Global Scope (Superadmin)
└── Organization Scope (Org Admin, Document Control)
└── Project Scope (Project Manager)
└── Contract Scope (Contract Admin)
```
### Permission Inheritance
- Users can have multiple role assignments at different scopes
- More specific scopes inherit access from broader scopes
- Permission checks evaluate all applicable scopes
- View v_user_all_permissions aggregates effective permissions
### Role-Based Access Control (RBAC)
**7 Predefined Roles**:
1. Superadmin (Global) - Full system access
2. Org Admin (Organization) - Organization management
3. Document Control (Organization) - Document lifecycle + admin powers
4. Editor (Organization) - Document CRUD
5. Viewer (Organization) - Read-only
6. Project Manager (Project) - Project + document management
7. Contract Admin (Contract) - Contract-specific management
### Permission Categories (49 total)
1. **System Management** (1): Full system control
2. **Organization Management** (4): CRUD on organizations
3. **Project Management** (8): CRUD + member/contract management
4. **Role & Permission Management** (4): RBAC administration
5. **Master Data Management** (4): Document types, categories, tags
6. **User Management** (5): User CRUD + organization assignment
7. **Contract Management** (2): Contract administration
8. **Document Management** (16): Full document lifecycle
9. **Workflow Management** (3): Approval workflow control
10. **Search & Reporting** (2): Advanced search, report generation
---
## Data Migration & Seeding
### Pre-populated Master Data
1. **organization_roles**: Not used in current implementation
2. **organizations**: 15 organizations (Owner, Consultants, Contractors, Third parties)
3. **projects**: 5 projects (LCBP3 + 4 sub-contracts)
4. **contracts**: 7 contracts
5. **users**: 3 initial users (superadmin, editor01, viewer01)
6. **roles**: 7 predefined roles
7. **permissions**: 49 system permissions
8. **role_permissions**: Complete permission mappings
9. **project_organizations**: Project-organization relationships
10. **contract_organizations**: Contract-organization-role relationships
11. **correspondence_types**: 10 types
12. **correspondence_status**: 23 status codes
13. **rfa_types**: 11 types
14. **rfa_status_codes**: 7 statuses
15. **rfa_approve_codes**: 8 approval codes
16. **circulation_status_codes**: 4 statuses
### Initial Passwords
All seed users have password: `password123`
- Hashed as: `$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq`
- **Must be changed on first login in production**
---
## Backup & Recovery Strategy
### Database Backup
**Strategy**:
- Daily full database backups
- Hourly incremental backups (transaction logs)
- Retention: 30 days online, 7 years archived
**Backup Method**:
- MariaDB mysqldump for logical backups
- MariaDB Backup (Mariabackup) for physical backups
- Automated via n8n cron workflows
### File Backup
**Strategy**:
- Daily backup of /share/dms-data/ directory
- QNAP snapshot every 4 hours
- Offsite replication to secondary NAS
**File Organization**:
```tree
/share/dms-data/
├── attachments/
│ ├── 2025/
│ │ ├── 01/
│ │ │ └── {uuid}-{filename}
│ │ └── 02/
│ └── 2024/
└── temp/
```
### Recovery Procedures
1. **Point-in-Time Recovery**: Using transaction logs
2. **Full Restore**: From latest full backup
3. **Selective Restore**: Individual tables or records
4. **File Recovery**: From QNAP snapshots or backup
---
## Performance Optimization
### Query Optimization
1. **Use Indexed Columns**: WHERE, JOIN, ORDER BY clauses
2. **Avoid SELECT**: Specify needed columns
3. **Use Views**: For complex, frequently-used queries
4. **Limit Result Sets**: Use LIMIT and pagination
5. **Analyze Slow Queries**: Enable slow query log
### Index Maintenance
```sql
-- Check index usage
SELECT * FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'lcbp3';
-- Optimize tables
OPTIMIZE TABLE correspondences;
-- Analyze tables
ANALYZE TABLE correspondences;
```
### Connection Pooling
- Backend uses connection pool (NestJS TypeORM)
- Min pool size: 5
- Max pool size: 20
- Idle timeout: 10 minutes
---
## Data Validation Rules
### Required Fields Validation
**At Application Level**:
- Email format validation
- Date range validation (start_date < end_date)
- File size limits (5MB per attachment)
- File type restrictions (PDF, DWG, DOC, XLS, images)
**At Database Level**:
- NOT NULL constraints
- UNIQUE constraints
- Foreign key constraints
- Check constraints (user_assignments scope)
### Business Logic Validation
1. **Document Workflow**:
- Cannot edit submitted documents (unless Document Control)
- Cannot skip workflow steps (unless forced)
- Must provide approval comments
2. **User Management**:
- Cannot delete users with active assignments
- Cannot deactivate own account
- Must have valid organization for non-Global roles
3. **File Management**:
- Original filename preserved for audit
- Unique stored filename prevents conflicts
- File path must exist and be accessible
---
## Change Log & Versioning
### Database Version: v1.4.0
**Changes from v1.3.0**:
- Added comprehensive RBAC system (roles, permissions, user_assignments)
- Refactored organization-project-contract relationships
- Added junction tables for M:N relationships
- Implemented soft delete pattern
- Added full-text search support
- Enhanced audit logging with JSON details
- Added circulation workflow templates
- Improved document numbering with stored procedure
- Added comprehensive views for common queries
- Optimized indexes for performance
**Migration Path**:
- v1.3.0 → v1.4.0: Run migration script (not provided in this excerpt)
- Backup database before migration
- Test migration on staging environment first
---
## Technical Specifications
### Database Configuration
**MariaDB Server**:
- Version: 10.11
- Character Set: utf8mb4
- Collation: utf8mb4_general_ci
- Time Zone: +07:00 (Bangkok/Asia)
- SQL Mode: STRICT_TRANS_TABLES, NO_ENGINE_SUBSTITUTION
**Connection Settings**:
- Host: Container on QNAP TS-473A
- Port: 3306 (default)
- Max Connections: 100
- Max Packet Size: 64MB
### Table Engine
**InnoDB Features Used**:
- ACID compliance
- Foreign key constraints
- Row-level locking
- Crash recovery
- Transaction support
### Storage Requirements
**Estimated Initial Size**:
- Database: ~50 MB (with seed data)
- Indexes: ~20 MB
- Total: ~70 MB
**Growth Estimates**:
- 1,000 documents/month: +100 MB/month (database)
- 10 attachments/document @ 2MB avg: +20 GB/month (files)
- Plan for 1TB+ storage within first year
---
## Application Integration
### Backend (NestJS)
**TypeORM Entities**:
- One entity class per table
- Decorators for columns, relationships
- DTOs for data transfer
- Repositories for data access
**Key Modules**:
- AuthModule: Authentication, authorization
- DocumentsModule: Correspondence, RFA management
- DrawingsModule: Shop drawing, contract drawing
- WorkflowModule: Circulation, approval workflows
- FilesModule: Attachment management
- UsersModule: User, role, permission management
### Frontend (Next.js)
**Key Features**:
- Document listing/search
- Document creation wizards
- Workflow approval interface
- File upload/download
- User management console
- Dashboard analytics
### Integration Points
1. **Document Numbering**:
- Call DocumentNumberingService.generateNextNumber() (NestJS) which handles Redis locking and retry logic
- Format with template from document_number_formats
- Store in correspondences.correspondence_number
2. **File Upload**:
- Upload to QNAP /share/dms-data/
- Create attachment record
- Link via junction table
3. **Workflow Execution**:
- Check rfa_workflow_templates
- Create rfa_workflows records
- Update status as steps complete
- Send notifications
4. **Permission Checks**:
- Query v_user_all_permissions
- Cache results per session
- Re-check on sensitive operations
---
## Monitoring & Maintenance
### Health Checks
```sql
-- Database size
SELECT
table_schema,
SUM(data_length + index_length) / 1024 / 1024 AS size_mb
FROM information_schema.TABLES
WHERE table_schema = 'dms_db'
GROUP BY table_schema;
-- Table sizes
SELECT
table_name,
(data_length + index_length) / 1024 / 1024 AS size_mb,
table_rows
FROM information_schema.TABLES
WHERE table_schema = 'dms_db'
ORDER BY (data_length + index_length) DESC;
-- Active connections
SHOW PROCESSLIST;
-- Lock wait statistics
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
```
### Scheduled Maintenance
**Daily**:
- Full database backup
- Check backup log for failures
- Monitor disk space
**Weekly**:
- OPTIMIZE tables
- ANALYZE tables
- Review slow query log
- Check for deadlocks
**Monthly**:
- Review audit logs
- Clean up old notifications (30+ days)
- Archive old audit logs (7+ years)
- Verify backup integrity (test restore)
**Quarterly**:
- Review and optimize indexes
- Update database statistics
- Capacity planning review
---
## Glossary
**Terms**:
- **Correspondence**: Any formal document exchanged between parties
- **RFA**: Request for Approval - formal submittal for review/approval
- **Circulation**: Internal document routing workflow
- **Transmittal**: Cover sheet for forwarding multiple documents
- **Shop Drawing**: Detailed construction drawing from contractor
- **Contract Drawing**: Baseline drawing from contract specifications
- **Revision**: Version of a document
- **Originator**: Organization that creates/sends a document
- **Recipient**: Organization that receives a document (TO or CC)
- **Scope**: Level of permission application (Global, Organization, Project, Contract)
**Acronyms**:
- **DMS**: Document Management System
- **LCBP3**: Laem Chabang Port Phase 3
- **RBAC**: Role-Based Access Control
- **RFA**: Request for Approval
- **RFI**: Request for Information
- **CSC**: Construction Supervision Consultant
- **TO**: Primary recipient (action required)
- **CC**: Carbon copy (for information)
- **QNAP**: Network Attached Storage device manufacturer
---
## **Document Control:**
- **Document:** Data Dictionary v1.4.4
- **Version:** 1.4
- **Date:** 2025-11-26
- **Author:** NAP LCBP3-DMS & Gemini
- **Status:** FINAL.Rev.04
- **Classification:** Internal Technical Documentation
- **Approved By:** Nattanin
---
`End of Data Dictionary v1.4.4 (ฉบับปรับปรุง)`