690514:2019 204-rfa-approval-refactor #01
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
-- ==========================================================
|
||||
-- DMS v1.8.0 Migration Support Tables
|
||||
-- ไฟล์นี้แยกจาก schema หลัก (lcbp3-v1.8.0-schema-01/02/03)
|
||||
-- ใช้สำหรับ n8n Migration Workflow เท่านั้น
|
||||
-- ลบได้ทั้งหมดหลัง Migration เสร็จสิ้น
|
||||
-- ==========================================================
|
||||
-- รันบน MariaDB **ก่อน** เริ่ม n8n Workflow
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- =====================================================
|
||||
-- 1. Checkpoint — ติดตามความคืบหน้าของ Batch
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS migration_progress (
|
||||
batch_id VARCHAR(50) PRIMARY KEY,
|
||||
last_processed_index INT DEFAULT 0,
|
||||
STATUS ENUM('RUNNING', 'COMPLETED', 'FAILED') DEFAULT 'RUNNING',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: ติดตามความคืบหน้า Batch (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- 2. Review Queue — รายการที่ต้องตรวจสอบโดยคน
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS migration_review_queue (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
document_number VARCHAR(100) NOT NULL,
|
||||
subject TEXT COMMENT 'หัวข้อเรื่อง (ตรงกับ correspondence_revisions.subject)',
|
||||
original_subject TEXT COMMENT 'หัวข้อเดิมจาก Excel (ก่อน AI แก้ไข)',
|
||||
body TEXT NULL COMMENT 'เนื้อความสรุปจาก AI (เตรียมนำเข้า correspondence_revisions.body)',
|
||||
project_id INT NULL COMMENT 'Project ID จาก Lookups',
|
||||
sender_organization_id INT NULL COMMENT 'Sender ID จาก Lookups',
|
||||
receiver_organization_id INT NULL COMMENT 'Receiver ID จาก Lookups',
|
||||
received_date DATE NULL COMMENT 'วันที่รับเอกสาร',
|
||||
issued_date DATE NULL COMMENT 'วันที่ออกเอกสาร',
|
||||
remarks TEXT COMMENT 'หมายเหตุจากหน้างาน (response)',
|
||||
ai_suggested_category VARCHAR(50),
|
||||
ai_confidence DECIMAL(4, 3),
|
||||
ai_issues JSON,
|
||||
ai_summary TEXT COMMENT 'สรุปเนื้อหาจาก AI (4-5 บรรทัด)',
|
||||
extracted_tags JSON COMMENT 'Tag ที่ AI นำเสนอหรือจับคู่ได้',
|
||||
temp_attachment_id INT NULL COMMENT 'ID ของไฟล์ชั่วคราวจาก Two-Phase Storage',
|
||||
review_reason VARCHAR(255),
|
||||
STATUS ENUM('PENDING', 'APPROVED', 'REJECTED') DEFAULT 'PENDING',
|
||||
reviewed_by VARCHAR(100),
|
||||
reviewed_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uq_doc_number (document_number)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: Review Queue ชั่วคราว (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- 3. Error Log — บันทึก Error ระหว่าง Migration
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS migration_errors (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
batch_id VARCHAR(50),
|
||||
document_number VARCHAR(100),
|
||||
error_type ENUM(
|
||||
'FILE_NOT_FOUND',
|
||||
'MISSING_FILENAME',
|
||||
'FILE_ERROR',
|
||||
'AI_PARSE_ERROR',
|
||||
'API_ERROR',
|
||||
'DB_ERROR',
|
||||
'SECURITY',
|
||||
'UNKNOWN'
|
||||
),
|
||||
error_message TEXT,
|
||||
raw_ai_response TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_batch_id (batch_id),
|
||||
INDEX idx_error_type (error_type)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: Error Log (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- 4. Fallback State — สถานะ AI Model Fallback
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS migration_fallback_state (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
batch_id VARCHAR(50) UNIQUE,
|
||||
recent_error_count INT DEFAULT 0,
|
||||
is_fallback_active BOOLEAN DEFAULT FALSE,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: Fallback Model State (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- 5. Idempotency — ป้องกัน Import ซ้ำ
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS import_transactions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
idempotency_key VARCHAR(255) UNIQUE NOT NULL,
|
||||
document_number VARCHAR(100),
|
||||
batch_id VARCHAR(100),
|
||||
status_code INT DEFAULT 201,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_idem_key (idempotency_key)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: Idempotency Tracking (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- 6. Daily Summary — สรุปผลรายวัน
|
||||
-- =====================================================
|
||||
CREATE TABLE IF NOT EXISTS migration_daily_summary (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
batch_id VARCHAR(50),
|
||||
summary_date DATE,
|
||||
total_processed INT DEFAULT 0,
|
||||
auto_ingested INT DEFAULT 0,
|
||||
sent_to_review INT DEFAULT 0,
|
||||
rejected INT DEFAULT 0,
|
||||
errors INT DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uq_batch_date (batch_id, summary_date)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Migration: Daily Summary (ลบได้หลัง Migration เสร็จ)';
|
||||
|
||||
-- =====================================================
|
||||
-- Cleanup Script (รันหลัง Migration เสร็จสิ้นทั้งหมด)
|
||||
-- =====================================================
|
||||
-- DROP TABLE IF EXISTS migration_daily_summary;
|
||||
-- DROP TABLE IF EXISTS import_transactions;
|
||||
-- DROP TABLE IF EXISTS migration_fallback_state;
|
||||
-- DROP TABLE IF EXISTS migration_errors;
|
||||
-- DROP TABLE IF EXISTS migration_review_queue;
|
||||
-- DROP TABLE IF EXISTS migration_progress;
|
||||
@@ -0,0 +1,215 @@
|
||||
-- ==========================================================
|
||||
-- DMS v1.8.0 Schema Part 1/3: DROP Statements
|
||||
-- รันไฟล์นี้ก่อน เพื่อล้างตารางเดิมทั้งหมด
|
||||
-- ==========================================================
|
||||
-- ==========================================================
|
||||
-- DMS v1.8.0 Document Management System Database
|
||||
-- Deploy Script Schema
|
||||
-- Server: Container Station on QNAP TS-473A
|
||||
-- Database service: MariaDB 11.8
|
||||
-- database web ui: phpmyadmin 5-apache
|
||||
-- database development ui: DBeaver
|
||||
-- backend service: NestJS
|
||||
-- frontend service: next.js
|
||||
-- reverse proxy: jc21/nginx-proxy-manager:latest
|
||||
-- cron service: n8n
|
||||
-- ==========================================================
|
||||
-- [v1.8.0 UPDATE] Prepare migration
|
||||
-- Update: Upgraded from v1.7.0
|
||||
-- Last Updated: 2026-02-27
|
||||
-- Major Changes:
|
||||
-- 1. ปรับปรุง:
|
||||
-- 1.1 TABLE correspondences
|
||||
-- - INDEX idx_doc_number (correspondence_number),
|
||||
-- - INDEX idx_deleted_at (deleted_at),
|
||||
-- - INDEX idx_created_by (created_by),
|
||||
-- ==========================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
SET time_zone = '+07:00';
|
||||
|
||||
-- ปิดการตรวจสอบ Foreign Key ชั่วคราวเพื่อให้สามารถลบตารางได้ทั้งหมด
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
DROP VIEW IF EXISTS v_document_statistics;
|
||||
|
||||
DROP VIEW IF EXISTS v_documents_with_attachments;
|
||||
|
||||
DROP VIEW IF EXISTS v_user_all_permissions;
|
||||
|
||||
DROP VIEW IF EXISTS v_audit_log_details;
|
||||
|
||||
DROP VIEW IF EXISTS v_user_tasks;
|
||||
|
||||
DROP VIEW IF EXISTS v_contract_parties_all;
|
||||
|
||||
DROP VIEW IF EXISTS v_current_rfas;
|
||||
|
||||
DROP VIEW IF EXISTS v_current_correspondences;
|
||||
|
||||
-- DROP PROCEDURE IF EXISTS sp_get_next_document_number;
|
||||
-- 🗑️ DROP TABLE SCRIPT: LCBP3-DMS v1.4.2
|
||||
-- คำเตือน: ข้อมูลทั้งหมดจะหายไป กรุณา Backup ก่อนรันบน Production
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 1: ตาราง System, Logs & Preferences (ตารางปลายทาง/ส่วนเสริม)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS backup_logs;
|
||||
|
||||
DROP TABLE IF EXISTS search_indices;
|
||||
|
||||
DROP TABLE IF EXISTS notifications;
|
||||
|
||||
DROP TABLE IF EXISTS audit_logs;
|
||||
|
||||
-- [NEW v1.4.2] ตารางการตั้งค่าส่วนตัวของผู้ใช้ (FK -> users)
|
||||
DROP TABLE IF EXISTS user_preferences;
|
||||
|
||||
-- [NEW v1.4.2] ตารางเก็บ Schema สำหรับ Validate JSON (Stand-alone)
|
||||
DROP TABLE IF EXISTS json_schemas;
|
||||
|
||||
-- [v1.5.1 NEW] ตาราง Audit และ Error Log สำหรับ Document Numbering
|
||||
DROP TABLE IF EXISTS document_number_errors;
|
||||
|
||||
DROP TABLE IF EXISTS document_number_audit;
|
||||
|
||||
DROP TABLE IF EXISTS document_number_reservations;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 2: ตาราง Junction (เชื่อมโยงข้อมูล M:N)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS correspondence_tags;
|
||||
|
||||
DROP TABLE IF EXISTS asbuilt_revision_shop_revisions_refs;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawing_revision_contract_refs;
|
||||
|
||||
DROP TABLE IF EXISTS contract_drawing_subcat_cat_maps;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 3: ตารางไฟล์แนบและการเชื่อมโยง (Attachments)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS contract_drawing_attachments;
|
||||
|
||||
DROP TABLE IF EXISTS circulation_attachments;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawing_revision_attachments;
|
||||
|
||||
DROP TABLE IF EXISTS asbuilt_drawing_revision_attachments;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_revision_attachments;
|
||||
|
||||
DROP TABLE IF EXISTS attachments;
|
||||
|
||||
-- ตารางหลักเก็บ path ไฟล์
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 4: ตาราง Workflow & Routing (Process Logic)
|
||||
-- ============================================================
|
||||
-- Correspondence Workflow
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 5: ตาราง Mapping สิทธิ์และโครงสร้าง (Access Control)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS role_permissions;
|
||||
|
||||
DROP TABLE IF EXISTS user_assignments;
|
||||
|
||||
DROP TABLE IF EXISTS contract_organizations;
|
||||
|
||||
DROP TABLE IF EXISTS project_organizations;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 6: ตารางรายละเอียดของเอกสาร (Revisions & Items)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS transmittal_items;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawing_revisions;
|
||||
|
||||
DROP TABLE IF EXISTS asbuilt_drawing_revisions;
|
||||
|
||||
DROP TABLE IF EXISTS rfa_items;
|
||||
|
||||
DROP TABLE IF EXISTS rfa_revisions;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_references;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_recipients;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_revisions;
|
||||
|
||||
-- [Modified v1.4.2] มี Virtual Columns
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 7: ตารางเอกสารหลัก (Core Documents)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS circulations;
|
||||
|
||||
DROP TABLE IF EXISTS transmittals;
|
||||
|
||||
DROP TABLE IF EXISTS contract_drawings;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawings;
|
||||
|
||||
DROP TABLE IF EXISTS asbuilt_drawings;
|
||||
|
||||
DROP TABLE IF EXISTS rfas;
|
||||
|
||||
DROP TABLE IF EXISTS correspondences;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 8: ตารางหมวดหมู่และข้อมูลหลัก (Master Data)
|
||||
-- ============================================================
|
||||
-- [NEW 6B] ลบตารางใหม่ที่เพิ่มเข้ามาเพื่อป้องกัน Error เวลา Re-deploy
|
||||
DROP TABLE IF EXISTS correspondence_sub_types;
|
||||
|
||||
DROP TABLE IF EXISTS disciplines;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawing_sub_categories;
|
||||
|
||||
DROP TABLE IF EXISTS shop_drawing_main_categories;
|
||||
|
||||
DROP TABLE IF EXISTS contract_drawing_sub_cats;
|
||||
|
||||
DROP TABLE IF EXISTS contract_drawing_cats;
|
||||
|
||||
DROP TABLE IF EXISTS contract_drawing_volumes;
|
||||
|
||||
DROP TABLE IF EXISTS circulation_status_codes;
|
||||
|
||||
DROP TABLE IF EXISTS rfa_approve_codes;
|
||||
|
||||
DROP TABLE IF EXISTS rfa_status_codes;
|
||||
|
||||
DROP TABLE IF EXISTS rfa_types;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_status;
|
||||
|
||||
DROP TABLE IF EXISTS correspondence_types;
|
||||
|
||||
DROP TABLE IF EXISTS document_number_counters;
|
||||
|
||||
-- [Modified v1.4.2] มี version column
|
||||
DROP TABLE IF EXISTS document_number_formats;
|
||||
|
||||
DROP TABLE IF EXISTS tags;
|
||||
|
||||
-- ============================================================
|
||||
-- ส่วนที่ 9: ตารางผู้ใช้ บทบาท และโครงสร้างรากฐาน (Root Tables)
|
||||
-- ============================================================
|
||||
DROP TABLE IF EXISTS organization_roles;
|
||||
|
||||
DROP TABLE IF EXISTS roles;
|
||||
|
||||
DROP TABLE IF EXISTS permissions;
|
||||
|
||||
DROP TABLE IF EXISTS contracts;
|
||||
|
||||
DROP TABLE IF EXISTS projects;
|
||||
|
||||
DROP TABLE IF EXISTS refresh_tokens;
|
||||
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
-- Referenced by user_preferences, audit_logs, etc.
|
||||
DROP TABLE IF EXISTS organizations;
|
||||
|
||||
-- Referenced by users, projects, etc.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,542 @@
|
||||
-- ==========================================================
|
||||
-- DMS v1.8.0 Schema Part 3/3: Views, Indexes, Partitioning
|
||||
-- รัน: หลังจาก 02-schema-tables.sql เสร็จ
|
||||
-- ==========================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
SET time_zone = '+07:00';
|
||||
|
||||
-- ============================================================
|
||||
-- 5. PARTITIONING PREPARATION (Advance - Optional)
|
||||
-- ============================================================
|
||||
-- หมายเหตุ: การทำ Partitioning บนตารางที่มีอยู่แล้ว (audit_logs, notifications)
|
||||
-- มักจะต้อง Drop Primary Key เดิม แล้วสร้างใหม่โดยรวม Partition Key (created_at) เข้าไป
|
||||
-- ขั้นตอนนี้ควรทำแยกต่างหากเมื่อระบบเริ่มมีข้อมูลเยอะ หรือทำใน Maintenance Window
|
||||
--
|
||||
-- ตัวอย่าง SQL สำหรับ Audit Logs (Reference Only):
|
||||
-- ALTER TABLE audit_logs DROP PRIMARY KEY, ADD PRIMARY KEY (audit_id, created_at);
|
||||
-- ALTER TABLE audit_logs PARTITION BY RANGE (YEAR(created_at)) (
|
||||
-- PARTITION p2024 VALUES LESS THAN (2025),
|
||||
-- PARTITION p2025 VALUES LESS THAN (2026),
|
||||
-- PARTITION p_future VALUES LESS THAN MAXVALUE
|
||||
-- );
|
||||
-- =====================================================
|
||||
-- CREATE INDEXES
|
||||
-- =====================================================
|
||||
-- Indexes for correspondences
|
||||
CREATE INDEX idx_corr_type ON correspondences(correspondence_type_id);
|
||||
|
||||
CREATE INDEX idx_corr_project ON correspondences(project_id);
|
||||
|
||||
CREATE INDEX idx_rfa_rev_v_drawing_count ON rfa_revisions (v_ref_drawing_count);
|
||||
|
||||
-- Indexes for document_number_formats
|
||||
CREATE INDEX idx_document_number_formats_project ON document_number_formats (project_id);
|
||||
|
||||
CREATE INDEX idx_document_number_formats_type ON document_number_formats (correspondence_type_id);
|
||||
|
||||
CREATE INDEX idx_document_number_formats_project_type ON document_number_formats (project_id, correspondence_type_id);
|
||||
|
||||
-- Indexes for document_number_counters
|
||||
CREATE INDEX idx_document_number_counters_project ON document_number_counters (project_id);
|
||||
|
||||
CREATE INDEX idx_document_number_counters_org ON document_number_counters (originator_organization_id);
|
||||
|
||||
CREATE INDEX idx_document_number_counters_type ON document_number_counters (correspondence_type_id);
|
||||
|
||||
-- Indexes for tags
|
||||
CREATE INDEX idx_tags_name ON tags (tag_name);
|
||||
|
||||
CREATE INDEX idx_tags_created_at ON tags (created_at);
|
||||
|
||||
-- Index for circulations deadline_date (EC-CIRC-003 Overdue Badge)
|
||||
CREATE INDEX idx_circulations_deadline ON circulations (deadline_date);
|
||||
|
||||
-- Indexes for correspondence_tags
|
||||
CREATE INDEX idx_correspondence_tags_correspondence ON correspondence_tags (correspondence_id);
|
||||
|
||||
CREATE INDEX idx_correspondence_tags_tag ON correspondence_tags (tag_id);
|
||||
|
||||
-- Indexes for audit_logs
|
||||
CREATE INDEX idx_audit_logs_user ON audit_logs (user_id);
|
||||
|
||||
CREATE INDEX idx_audit_logs_action ON audit_logs (ACTION);
|
||||
|
||||
CREATE INDEX idx_audit_logs_entity ON audit_logs (entity_type, entity_id);
|
||||
|
||||
CREATE INDEX idx_audit_logs_created_at ON audit_logs (created_at);
|
||||
|
||||
CREATE INDEX idx_audit_logs_ip ON audit_logs (ip_address);
|
||||
|
||||
-- Indexes for notifications
|
||||
CREATE INDEX idx_notifications_user ON notifications (user_id);
|
||||
|
||||
CREATE INDEX idx_notifications_type ON notifications (notification_type);
|
||||
|
||||
CREATE INDEX idx_notifications_read ON notifications (is_read);
|
||||
|
||||
CREATE INDEX idx_notifications_entity ON notifications (entity_type, entity_id);
|
||||
|
||||
CREATE INDEX idx_notifications_created_at ON notifications (created_at);
|
||||
|
||||
-- Indexes for search_indices
|
||||
CREATE INDEX idx_search_indices_entity ON search_indices (entity_type, entity_id);
|
||||
|
||||
CREATE INDEX idx_search_indices_indexed_at ON search_indices (indexed_at);
|
||||
|
||||
-- Indexes for backup_logs
|
||||
CREATE INDEX idx_backup_logs_type ON backup_logs (backup_type);
|
||||
|
||||
CREATE INDEX idx_backup_logs_status ON backup_logs (STATUS);
|
||||
|
||||
CREATE INDEX idx_backup_logs_started_at ON backup_logs (started_at);
|
||||
|
||||
CREATE INDEX idx_backup_logs_completed_at ON backup_logs (completed_at);
|
||||
|
||||
-- =====================================================
|
||||
-- Additional Composite Indexes for Performance
|
||||
-- =====================================================
|
||||
-- Composite index for document_number_counters for faster lookups
|
||||
-- Composite index for notifications for user-specific queries
|
||||
CREATE INDEX idx_notifications_user_unread ON notifications (user_id, is_read, created_at);
|
||||
|
||||
-- Composite index for audit_logs for reporting
|
||||
CREATE INDEX idx_audit_logs_reporting ON audit_logs (created_at, entity_type, ACTION);
|
||||
|
||||
-- Composite index for search_indices for entity-based queries
|
||||
CREATE INDEX idx_search_entities ON search_indices (entity_type, entity_id, indexed_at);
|
||||
|
||||
-- สร้าง Index สำหรับ Cleanup Job
|
||||
CREATE INDEX idx_attachments_temp_cleanup ON attachments (is_temporary, expires_at);
|
||||
|
||||
CREATE INDEX idx_attachments_temp_id ON attachments (temp_id);
|
||||
|
||||
CREATE INDEX idx_audit_request_id ON audit_logs (request_id);
|
||||
|
||||
-- =====================================================
|
||||
-- SQL Script for LCBP3-DMS (V1.4.0) - MariaDB
|
||||
-- Generated from Data Dictionary
|
||||
-- =====================================================
|
||||
-- =====================================================
|
||||
-- 11. 📊 Views & Procedures (วิว และ โปรซีเดอร์)
|
||||
-- =====================================================
|
||||
-- View แสดง Revision "ปัจจุบัน" ของ correspondences ทั้งหมด (ที่ไม่ใช่ RFA)
|
||||
CREATE VIEW v_current_correspondences AS
|
||||
SELECT c.id AS correspondence_id,
|
||||
c.uuid AS correspondence_uuid,
|
||||
c.correspondence_number,
|
||||
c.correspondence_type_id,
|
||||
ct.type_code AS correspondence_type_code,
|
||||
ct.type_name AS correspondence_type_name,
|
||||
c.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
c.originator_id,
|
||||
org.uuid AS originator_uuid,
|
||||
org.organization_code AS originator_code,
|
||||
org.organization_name AS originator_name,
|
||||
cr.id AS revision_id,
|
||||
cr.uuid AS revision_uuid,
|
||||
cr.revision_number,
|
||||
cr.revision_label,
|
||||
cr.subject,
|
||||
cr.document_date,
|
||||
cr.issued_date,
|
||||
cr.received_date,
|
||||
cr.due_date,
|
||||
cr.correspondence_status_id,
|
||||
cs.status_code,
|
||||
cs.status_name,
|
||||
cr.created_by,
|
||||
u.username AS created_by_username,
|
||||
cr.created_at AS revision_created_at
|
||||
FROM correspondences c
|
||||
INNER JOIN correspondence_types ct ON c.correspondence_type_id = ct.id
|
||||
INNER JOIN projects p ON c.project_id = p.id
|
||||
LEFT JOIN organizations org ON c.originator_id = org.id
|
||||
INNER JOIN correspondence_revisions cr ON c.id = cr.correspondence_id
|
||||
INNER JOIN correspondence_status cs ON cr.correspondence_status_id = cs.id
|
||||
LEFT JOIN users u ON cr.created_by = u.user_id
|
||||
WHERE cr.is_current = TRUE
|
||||
AND c.correspondence_type_id NOT IN(
|
||||
SELECT id
|
||||
FROM correspondence_types
|
||||
WHERE type_code = 'RFA'
|
||||
)
|
||||
AND c.deleted_at IS NULL;
|
||||
|
||||
-- View แสดง Revision "ปัจจุบัน" ของ rfa_revisions ทั้งหมด
|
||||
CREATE VIEW v_current_rfas AS
|
||||
SELECT r.id AS rfa_id,
|
||||
c.uuid AS correspondence_uuid,
|
||||
r.rfa_type_id,
|
||||
rt.type_code AS rfa_type_code,
|
||||
rt.type_name_th AS rfa_type_name_th,
|
||||
rt.type_name_en AS rfa_type_name_en,
|
||||
c.correspondence_number,
|
||||
c.discipline_id,
|
||||
-- ✅ ดึงจาก Correspondences
|
||||
d.discipline_code,
|
||||
-- ✅ Join เพิ่มเพื่อแสดง code
|
||||
c.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
c.originator_id,
|
||||
org.uuid AS originator_uuid,
|
||||
org.organization_name AS originator_name,
|
||||
rr.id AS revision_id,
|
||||
cr.uuid AS revision_uuid,
|
||||
cr.revision_number,
|
||||
cr.revision_label,
|
||||
cr.subject,
|
||||
cr.document_date,
|
||||
cr.issued_date,
|
||||
cr.received_date,
|
||||
rr.approved_date,
|
||||
rr.rfa_status_code_id,
|
||||
rsc.status_code AS rfa_status_code,
|
||||
rsc.status_name AS rfa_status_name,
|
||||
rr.rfa_approve_code_id,
|
||||
rac.approve_code AS rfa_approve_code,
|
||||
rac.approve_name AS rfa_approve_name,
|
||||
cr.created_by,
|
||||
u.username AS created_by_username,
|
||||
cr.created_at AS revision_created_at
|
||||
FROM rfas r
|
||||
INNER JOIN rfa_types rt ON r.rfa_type_id = rt.id
|
||||
INNER JOIN correspondences c ON r.id = c.id
|
||||
INNER JOIN correspondence_revisions cr ON c.id = cr.correspondence_id
|
||||
INNER JOIN rfa_revisions rr ON cr.id = rr.id -- RFA uses shared primary key with correspondence_revisions (1:1)
|
||||
-- [FIX 1] เพิ่มการ Join ตาราง disciplines
|
||||
LEFT JOIN disciplines d ON c.discipline_id = d.id
|
||||
INNER JOIN projects p ON c.project_id = p.id
|
||||
INNER JOIN organizations org ON c.originator_id = org.id
|
||||
INNER JOIN rfa_status_codes rsc ON rr.rfa_status_code_id = rsc.id
|
||||
LEFT JOIN rfa_approve_codes rac ON rr.rfa_approve_code_id = rac.id
|
||||
LEFT JOIN users u ON cr.created_by = u.user_id
|
||||
WHERE cr.is_current = TRUE
|
||||
AND c.deleted_at IS NULL;
|
||||
|
||||
-- View แสดงความสัมพันธ์ทั้งหมดระหว่าง Contract, Project, และ Organization
|
||||
CREATE VIEW v_contract_parties_all AS
|
||||
SELECT c.id AS contract_id,
|
||||
c.uuid AS contract_uuid,
|
||||
c.contract_code,
|
||||
c.contract_name,
|
||||
p.id AS project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
o.id AS organization_id,
|
||||
o.uuid AS organization_uuid,
|
||||
o.organization_code,
|
||||
o.organization_name,
|
||||
co.role_in_contract
|
||||
FROM contracts c
|
||||
INNER JOIN projects p ON c.project_id = p.id
|
||||
INNER JOIN contract_organizations co ON c.id = co.contract_id
|
||||
INNER JOIN organizations o ON co.organization_id = o.id
|
||||
WHERE c.is_active = TRUE;
|
||||
|
||||
-- ============================================================
|
||||
-- View: v_user_tasks (Unified Workflow Engine Edition)
|
||||
-- ============================================================
|
||||
-- หน้าที่: รวมรายการงานที่ยังค้างอยู่ (Status = ACTIVE) จากทุกระบบ (RFA, Circulation, Correspondence)
|
||||
-- เพื่อนำไปแสดงในหน้า Dashboard "My Tasks"
|
||||
-- ============================================================
|
||||
CREATE OR REPLACE VIEW v_user_tasks AS
|
||||
SELECT -- 1. Workflow Instance Info
|
||||
wi.id AS instance_id,
|
||||
wd.workflow_code,
|
||||
wi.current_state,
|
||||
wi.status AS workflow_status,
|
||||
wi.created_at AS assigned_at,
|
||||
-- 2. Entity Info (Polymorphic Identity)
|
||||
wi.entity_type,
|
||||
wi.entity_id,
|
||||
-- 3. Normalized Document Info (ดึงข้อมูลจริงจากตารางลูกตามประเภท)
|
||||
-- ใช้ CASE WHEN เพื่อรวมคอลัมน์ที่ชื่อต่างกันให้เป็นชื่อกลาง (document_number, subject)
|
||||
CASE
|
||||
WHEN wi.entity_type = 'rfa_revision' THEN rfa_corr.correspondence_number
|
||||
WHEN wi.entity_type = 'circulation' THEN circ.circulation_no
|
||||
WHEN wi.entity_type = 'correspondence_revision' THEN corr_corr.correspondence_number
|
||||
ELSE 'N/A'
|
||||
END AS document_number,
|
||||
CASE
|
||||
WHEN wi.entity_type = 'rfa_revision' THEN rfa_corr_rev.subject
|
||||
WHEN wi.entity_type = 'circulation' THEN circ.circulation_subject
|
||||
WHEN wi.entity_type = 'correspondence_revision' THEN corr_rev.subject
|
||||
ELSE 'Unknown Document'
|
||||
END AS subject,
|
||||
-- 4. Context Info (สำหรับ Filter สิทธิ์การมองเห็นที่ Backend)
|
||||
-- ดึงเป็น JSON String เพื่อให้ Backend ไป Parse หรือใช้ JSON_CONTAINS
|
||||
JSON_UNQUOTE(JSON_EXTRACT(wi.context, '$.ownerId')) AS owner_id,
|
||||
JSON_EXTRACT(wi.context, '$.assigneeIds') AS assignee_ids_json
|
||||
FROM workflow_instances wi
|
||||
JOIN workflow_definitions wd ON wi.definition_id = wd.id -- 5. Joins for RFA (ซับซ้อนหน่อยเพราะ RFA ผูกกับ Correspondence อีกที)
|
||||
LEFT JOIN rfa_revisions rfa_rev ON wi.entity_type = 'rfa_revision'
|
||||
AND wi.entity_id = CAST(rfa_rev.id AS CHAR)
|
||||
LEFT JOIN correspondence_revisions rfa_corr_rev ON rfa_rev.id = rfa_corr_rev.id
|
||||
LEFT JOIN correspondences rfa_corr ON rfa_corr_rev.correspondence_id = rfa_corr.id -- 6. Joins for Circulation
|
||||
LEFT JOIN circulations circ ON wi.entity_type = 'circulation'
|
||||
AND wi.entity_id = CAST(circ.id AS CHAR) -- 7. Joins for Correspondence
|
||||
LEFT JOIN correspondence_revisions corr_rev ON wi.entity_type = 'correspondence_revision'
|
||||
AND wi.entity_id = CAST(corr_rev.id AS CHAR)
|
||||
LEFT JOIN correspondences corr_corr ON corr_rev.correspondence_id = corr_corr.id -- 8. Filter เฉพาะงานที่ยัง Active อยู่
|
||||
WHERE wi.status = 'ACTIVE';
|
||||
|
||||
-- View แสดง audit_logs พร้อมข้อมูล username และ email ของผู้กระทำ
|
||||
CREATE VIEW v_audit_log_details AS
|
||||
SELECT al.audit_id,
|
||||
al.user_id,
|
||||
u.username,
|
||||
u.email,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
al.action,
|
||||
al.entity_type,
|
||||
al.entity_id,
|
||||
al.details_json,
|
||||
al.ip_address,
|
||||
al.user_agent,
|
||||
al.created_at
|
||||
FROM audit_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.user_id;
|
||||
|
||||
-- View รวมสิทธิ์ทั้งหมด (Global + Project) ของผู้ใช้ทุกคน
|
||||
CREATE VIEW v_user_all_permissions AS -- Global Permissions
|
||||
SELECT ua.user_id,
|
||||
ua.role_id,
|
||||
r.role_name,
|
||||
rp.permission_id,
|
||||
p.permission_name,
|
||||
p.module,
|
||||
p.scope_level,
|
||||
ua.organization_id,
|
||||
NULL AS project_id,
|
||||
NULL AS contract_id,
|
||||
'GLOBAL' AS permission_scope
|
||||
FROM user_assignments ua
|
||||
INNER JOIN roles r ON ua.role_id = r.role_id
|
||||
INNER JOIN role_permissions rp ON ua.role_id = rp.role_id
|
||||
INNER JOIN permissions p ON rp.permission_id = p.permission_id -- Global scope
|
||||
WHERE p.is_active = 1
|
||||
AND ua.organization_id IS NULL
|
||||
AND ua.project_id IS NULL
|
||||
AND ua.contract_id IS NULL
|
||||
UNION ALL
|
||||
-- Organization-specific Permissions
|
||||
SELECT ua.user_id,
|
||||
ua.role_id,
|
||||
r.role_name,
|
||||
rp.permission_id,
|
||||
p.permission_name,
|
||||
p.module,
|
||||
p.scope_level,
|
||||
ua.organization_id,
|
||||
NULL AS project_id,
|
||||
NULL AS contract_id,
|
||||
'ORGANIZATION' AS permission_scope
|
||||
FROM user_assignments ua
|
||||
INNER JOIN roles r ON ua.role_id = r.role_id
|
||||
INNER JOIN role_permissions rp ON ua.role_id = rp.role_id
|
||||
INNER JOIN permissions p ON rp.permission_id = p.permission_id -- Organization scope
|
||||
WHERE p.is_active = 1
|
||||
AND ua.organization_id IS NOT NULL
|
||||
AND ua.project_id IS NULL
|
||||
AND ua.contract_id IS NULL
|
||||
UNION ALL
|
||||
-- Project-specific Permissions
|
||||
SELECT ua.user_id,
|
||||
ua.role_id,
|
||||
r.role_name,
|
||||
rp.permission_id,
|
||||
p.permission_name,
|
||||
p.module,
|
||||
p.scope_level,
|
||||
ua.organization_id,
|
||||
ua.project_id,
|
||||
NULL AS contract_id,
|
||||
'PROJECT' AS permission_scope
|
||||
FROM user_assignments ua
|
||||
INNER JOIN roles r ON ua.role_id = r.role_id
|
||||
INNER JOIN role_permissions rp ON ua.role_id = rp.role_id
|
||||
INNER JOIN permissions p ON rp.permission_id = p.permission_id -- Project scope
|
||||
WHERE p.is_active = 1
|
||||
AND ua.project_id IS NOT NULL
|
||||
AND ua.contract_id IS NULL
|
||||
UNION ALL
|
||||
-- Contract-specific Permissions
|
||||
SELECT ua.user_id,
|
||||
ua.role_id,
|
||||
r.role_name,
|
||||
rp.permission_id,
|
||||
p.permission_name,
|
||||
p.module,
|
||||
p.scope_level,
|
||||
ua.organization_id,
|
||||
ua.project_id,
|
||||
ua.contract_id,
|
||||
'CONTRACT' AS permission_scope
|
||||
FROM user_assignments ua
|
||||
INNER JOIN roles r ON ua.role_id = r.role_id
|
||||
INNER JOIN role_permissions rp ON ua.role_id = rp.role_id
|
||||
INNER JOIN permissions p ON rp.permission_id = p.permission_id -- Contract scope
|
||||
WHERE p.is_active = 1
|
||||
AND ua.contract_id IS NOT NULL;
|
||||
|
||||
-- =====================================================
|
||||
-- Additional Useful Views
|
||||
-- =====================================================
|
||||
-- View แสดงเอกสารทั้งหมดที่มีไฟล์แนบ
|
||||
CREATE VIEW v_documents_with_attachments AS
|
||||
SELECT 'CORRESPONDENCE' AS document_type,
|
||||
c.id AS document_id,
|
||||
c.uuid AS document_uuid,
|
||||
c.correspondence_number AS document_number,
|
||||
c.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
COUNT(cra.attachment_id) AS attachment_count,
|
||||
MAX(a.created_at) AS latest_attachment_date
|
||||
FROM correspondences c
|
||||
INNER JOIN projects p ON c.project_id = p.id -- [FIX] JOIN ผ่าน correspondence_revisions เพราะไฟล์ผูกกับ revision ไม่ใช่ correspondence master
|
||||
LEFT JOIN correspondence_revisions cr ON c.id = cr.correspondence_id
|
||||
AND cr.is_current = TRUE
|
||||
LEFT JOIN correspondence_revision_attachments cra ON cr.id = cra.correspondence_revision_id
|
||||
LEFT JOIN attachments a ON cra.attachment_id = a.id
|
||||
WHERE c.deleted_at IS NULL
|
||||
GROUP BY c.id,
|
||||
c.uuid,
|
||||
c.correspondence_number,
|
||||
c.project_id,
|
||||
p.uuid,
|
||||
p.project_code,
|
||||
p.project_name
|
||||
UNION ALL
|
||||
SELECT 'CIRCULATION' AS document_type,
|
||||
circ.id AS document_id,
|
||||
circ.uuid AS document_uuid,
|
||||
circ.circulation_no AS document_number,
|
||||
corr.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
COUNT(ca.attachment_id) AS attachment_count,
|
||||
MAX(a.created_at) AS latest_attachment_date
|
||||
FROM circulations circ
|
||||
INNER JOIN correspondences corr ON circ.correspondence_id = corr.id
|
||||
INNER JOIN projects p ON corr.project_id = p.id
|
||||
LEFT JOIN circulation_attachments ca ON circ.id = ca.circulation_id
|
||||
LEFT JOIN attachments a ON ca.attachment_id = a.id
|
||||
GROUP BY circ.id,
|
||||
circ.circulation_no,
|
||||
corr.project_id,
|
||||
p.project_code,
|
||||
p.project_name
|
||||
UNION ALL
|
||||
SELECT 'SHOP_DRAWING' AS document_type,
|
||||
sdr.id AS document_id,
|
||||
sdr.uuid AS document_uuid,
|
||||
sd.drawing_number AS document_number,
|
||||
sd.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
COUNT(sdra.attachment_id) AS attachment_count,
|
||||
MAX(a.created_at) AS latest_attachment_date
|
||||
FROM shop_drawing_revisions sdr
|
||||
INNER JOIN shop_drawings sd ON sdr.shop_drawing_id = sd.id
|
||||
INNER JOIN projects p ON sd.project_id = p.id
|
||||
LEFT JOIN shop_drawing_revision_attachments sdra ON sdr.id = sdra.shop_drawing_revision_id
|
||||
LEFT JOIN attachments a ON sdra.attachment_id = a.id
|
||||
WHERE sd.deleted_at IS NULL
|
||||
GROUP BY sdr.id,
|
||||
sd.drawing_number,
|
||||
sd.project_id,
|
||||
p.project_code,
|
||||
p.project_name
|
||||
UNION ALL
|
||||
SELECT 'CONTRACT_DRAWING' AS document_type,
|
||||
cd.id AS document_id,
|
||||
cd.uuid AS document_uuid,
|
||||
cd.condwg_no AS document_number,
|
||||
cd.project_id,
|
||||
p.uuid AS project_uuid,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
COUNT(cda.attachment_id) AS attachment_count,
|
||||
MAX(a.created_at) AS latest_attachment_date
|
||||
FROM contract_drawings cd
|
||||
INNER JOIN projects p ON cd.project_id = p.id
|
||||
LEFT JOIN contract_drawing_attachments cda ON cd.id = cda.contract_drawing_id
|
||||
LEFT JOIN attachments a ON cda.attachment_id = a.id
|
||||
WHERE cd.deleted_at IS NULL
|
||||
GROUP BY cd.id,
|
||||
cd.condwg_no,
|
||||
cd.project_id,
|
||||
p.project_code,
|
||||
p.project_name;
|
||||
|
||||
-- View แสดงสถิติเอกสารตามประเภทและสถานะ
|
||||
CREATE VIEW v_document_statistics AS
|
||||
SELECT p.id AS project_id,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
ct.id AS correspondence_type_id,
|
||||
ct.type_code,
|
||||
ct.type_name,
|
||||
cs.id AS status_id,
|
||||
cs.status_code,
|
||||
cs.status_name,
|
||||
COUNT(DISTINCT c.id) AS document_count,
|
||||
COUNT(DISTINCT cr.id) AS revision_count
|
||||
FROM projects p
|
||||
CROSS JOIN correspondence_types ct
|
||||
CROSS JOIN correspondence_status cs
|
||||
LEFT JOIN correspondences c ON p.id = c.project_id
|
||||
AND ct.id = c.correspondence_type_id
|
||||
LEFT JOIN correspondence_revisions cr ON c.id = cr.correspondence_id
|
||||
AND cs.id = cr.correspondence_status_id
|
||||
AND cr.is_current = TRUE
|
||||
WHERE p.is_active = 1
|
||||
AND ct.is_active = 1
|
||||
AND cs.is_active = 1
|
||||
GROUP BY p.id,
|
||||
p.project_code,
|
||||
p.project_name,
|
||||
ct.id,
|
||||
ct.type_code,
|
||||
ct.type_name,
|
||||
cs.id,
|
||||
cs.status_code,
|
||||
cs.status_name;
|
||||
|
||||
-- =====================================================
|
||||
-- Indexes for View Performance Optimization
|
||||
-- =====================================================
|
||||
-- Indexes for v_current_correspondences performance
|
||||
CREATE INDEX idx_correspondences_type_project ON correspondences (correspondence_type_id, project_id);
|
||||
|
||||
CREATE INDEX idx_corr_revisions_current_status ON correspondence_revisions (is_current, correspondence_status_id);
|
||||
|
||||
CREATE INDEX idx_corr_revisions_correspondence_current ON correspondence_revisions (correspondence_id, is_current);
|
||||
|
||||
-- Indexes for v_current_rfas performance
|
||||
CREATE INDEX idx_rfa_revisions_status ON rfa_revisions (rfa_status_code_id);
|
||||
|
||||
-- Indexes for document statistics performance
|
||||
CREATE INDEX idx_correspondences_project_type ON correspondences (project_id, correspondence_type_id);
|
||||
|
||||
CREATE INDEX idx_corr_revisions_status_current ON correspondence_revisions (correspondence_status_id, is_current);
|
||||
|
||||
CREATE INDEX IDX_AUDIT_DOC_ID ON document_number_audit (document_id);
|
||||
|
||||
CREATE INDEX IDX_AUDIT_STATUS ON document_number_audit (STATUS);
|
||||
|
||||
CREATE INDEX IDX_AUDIT_OPERATION ON document_number_audit (operation);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,218 @@
|
||||
-- =============================================================================
|
||||
-- LCBP3-DMS v1.9.0 — RFA Approval System Refactor Schema
|
||||
-- Feature Branch: 1-rfa-approval-refactor
|
||||
-- ADR-009: No TypeORM migrations — edit SQL schema directly
|
||||
-- Created: 2026-05-12
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. review_teams — ทีมตรวจสอบแยกตาม Discipline
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_teams` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(255) NULL,
|
||||
`default_for_rfa_types` TEXT NULL COMMENT 'Comma-separated RFA type codes e.g. SDW,DDW',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_teams_uuid` (`uuid`),
|
||||
KEY `idx_review_teams_project` (`project_id`, `is_active`),
|
||||
CONSTRAINT `fk_review_teams_project` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. review_team_members — สมาชิกในทีมแยกตาม Discipline
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_team_members` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`team_id` INT NOT NULL,
|
||||
`user_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`role` ENUM('REVIEWER','LEAD','MANAGER') NOT NULL DEFAULT 'REVIEWER',
|
||||
`priority_order` INT NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_team_members_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_team_user_discipline` (`team_id`, `user_id`, `discipline_id`),
|
||||
KEY `idx_rtm_team` (`team_id`),
|
||||
KEY `idx_rtm_user` (`user_id`),
|
||||
CONSTRAINT `fk_rtm_team` FOREIGN KEY (`team_id`) REFERENCES `review_teams` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rtm_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rtm_discipline` FOREIGN KEY (`discipline_id`) REFERENCES `disciplines` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. response_codes — รหัสตอบกลับมาตรฐาน (Master Approval Matrix)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `response_codes` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`code` VARCHAR(10) NOT NULL COMMENT '1A, 1B, 1C, 1D, 1E, 1F, 1G, 2, 3, 4',
|
||||
`sub_status` VARCHAR(10) NULL,
|
||||
`category` ENUM('ENGINEERING','MATERIAL','CONTRACT','TESTING','ESG') NOT NULL,
|
||||
`description_th` TEXT NOT NULL,
|
||||
`description_en` TEXT NOT NULL,
|
||||
`implications` JSON NULL COMMENT '{"affectsSchedule":bool,"affectsCost":bool,"requiresContractReview":bool}',
|
||||
`notify_roles` TEXT NULL COMMENT 'Comma-separated roles e.g. CONTRACT_MANAGER,QS_MANAGER',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`is_system` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'System default — cannot delete',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_response_codes_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_response_code_category` (`code`, `category`),
|
||||
KEY `idx_rc_category_active` (`category`, `is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. response_code_rules — กฎการใช้รหัสต่อโครงการ/ประเภทเอกสาร
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `response_code_rules` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NULL COMMENT 'NULL = global default',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NOT NULL,
|
||||
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`requires_comments` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`triggers_notification` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`parent_rule_id` INT NULL COMMENT 'For inheritance tracking',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_response_code_rules_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_rule_per_project_doctype_code` (`project_id`, `document_type_id`, `response_code_id`),
|
||||
KEY `idx_response_rules_lookup` (`project_id`, `document_type_id`, `is_enabled`),
|
||||
CONSTRAINT `fk_rcr_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`),
|
||||
CONSTRAINT `fk_rcr_parent` FOREIGN KEY (`parent_rule_id`) REFERENCES `response_code_rules` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. review_tasks — งานตรวจสอบสำหรับแต่ละ Discipline (Parallel Review)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_tasks` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`rfa_revision_id` INT NOT NULL,
|
||||
`team_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`assigned_to_user_id` INT NULL COMMENT 'NULL = auto-assign by discipline',
|
||||
`status` ENUM('PENDING','IN_PROGRESS','COMPLETED','DELEGATED','EXPIRED','CANCELLED') NOT NULL DEFAULT 'PENDING',
|
||||
`due_date` DATE NULL,
|
||||
`response_code_id` INT NULL,
|
||||
`comments` TEXT NULL,
|
||||
`attachments` JSON NULL COMMENT 'Array of attachment publicIds',
|
||||
`delegated_from_user_id` INT NULL COMMENT 'Original assignee when delegated',
|
||||
`completed_at` TIMESTAMP NULL,
|
||||
`version` INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking (ADR-002)',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_tasks_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_review_task_per_revision_discipline` (`rfa_revision_id`, `team_id`, `discipline_id`),
|
||||
KEY `idx_review_tasks_rfa_revision` (`rfa_revision_id`),
|
||||
KEY `idx_review_tasks_status` (`status`),
|
||||
KEY `idx_review_tasks_assigned` (`assigned_to_user_id`, `status`),
|
||||
CONSTRAINT `fk_rt_rfa_revision` FOREIGN KEY (`rfa_revision_id`) REFERENCES `rfa_revisions` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rt_team` FOREIGN KEY (`team_id`) REFERENCES `review_teams` (`id`),
|
||||
CONSTRAINT `fk_rt_discipline` FOREIGN KEY (`discipline_id`) REFERENCES `disciplines` (`id`),
|
||||
CONSTRAINT `fk_rt_user` FOREIGN KEY (`assigned_to_user_id`) REFERENCES `users` (`user_id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_rt_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 6. delegations — การมอบหมายงาน
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `delegations` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`delegator_user_id` INT NOT NULL COMMENT 'ผู้มอบหมาย (FK → users.user_id)',
|
||||
`delegate_user_id` INT NOT NULL COMMENT 'ผู้รับมอบหมาย (FK → users.user_id)',
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NULL COMMENT 'BullMQ job flips is_active=0 when end_date < NOW() (ADR-008)',
|
||||
`scope` ENUM('ALL','RFA_ONLY','CORRESPONDENCE_ONLY','SPECIFIC_TYPES') NOT NULL DEFAULT 'ALL',
|
||||
`document_types` TEXT NULL COMMENT 'Comma-separated doc type codes when scope=SPECIFIC_TYPES',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Managed by BullMQ scheduler — do not flip manually',
|
||||
`reason` TEXT NULL,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_delegations_uuid` (`uuid`),
|
||||
KEY `idx_delegations_active` (`delegator_user_id`, `is_active`, `start_date`, `end_date`),
|
||||
KEY `idx_delegations_delegate` (`delegate_user_id`, `is_active`),
|
||||
CONSTRAINT `fk_del_delegator` FOREIGN KEY (`delegator_user_id`) REFERENCES `users` (`user_id`),
|
||||
CONSTRAINT `fk_del_delegate` FOREIGN KEY (`delegate_user_id`) REFERENCES `users` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 7. reminder_rules — กฎการแจ้งเตือน
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `reminder_rules` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NULL COMMENT 'NULL = all types',
|
||||
`trigger_days_before_due` INT NOT NULL DEFAULT 2,
|
||||
`escalation_days_after_due` INT NOT NULL DEFAULT 1,
|
||||
`reminder_type` ENUM('DUE_SOON','ON_DUE','OVERDUE','ESCALATION_L1','ESCALATION_L2') NOT NULL,
|
||||
`recipients` TEXT NOT NULL COMMENT 'Comma-separated: ASSIGNEE,MANAGER,PROJECT_MANAGER',
|
||||
`message_template_th` TEXT NOT NULL,
|
||||
`message_template_en` TEXT NOT NULL,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_reminder_rules_uuid` (`uuid`),
|
||||
KEY `idx_reminder_rules_active` (`is_active`, `project_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 8. distribution_matrices — ตารางกระจายเอกสาร
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `distribution_matrices` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NULL COMMENT 'NULL = applies to all codes',
|
||||
`conditions` JSON NULL COMMENT '{"codes":["1A","1B"],"excludeCodes":["3","4"]}',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_distribution_matrices_uuid` (`uuid`),
|
||||
KEY `idx_distribution_lookup` (`document_type_id`, `response_code_id`, `is_active`),
|
||||
CONSTRAINT `fk_dm_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 9. distribution_recipients — ผู้รับเอกสารใน Distribution Matrix
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `distribution_recipients` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`matrix_id` INT NOT NULL,
|
||||
`recipient_type` ENUM('USER','ORGANIZATION','TEAM','ROLE') NOT NULL,
|
||||
`recipient_public_id` UUID NOT NULL COMMENT 'publicId of target: USER=users.uuid | ORGANIZATION=organizations.uuid | TEAM=review_teams.uuid | ROLE=roles.role_id (roles has no uuid — store as string of role_id, query confirmed Q4B)',
|
||||
`delivery_method` ENUM('EMAIL','IN_APP','BOTH') NOT NULL DEFAULT 'BOTH',
|
||||
`sequence` INT NULL COMMENT 'For ordered delivery',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_dr_matrix` (`matrix_id`),
|
||||
KEY `idx_dr_type_recipient` (`recipient_type`, `recipient_public_id`),
|
||||
CONSTRAINT `fk_dr_matrix` FOREIGN KEY (`matrix_id`) REFERENCES `distribution_matrices` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Polymorphic recipients — no FK on recipient_public_id (by design). ROLE type uses roles.role_id cast to UUID string until roles table gains uuid column (pending delta-11)';
|
||||
|
||||
-- =============================================================================
|
||||
-- Additional Indexes (Performance)
|
||||
-- =============================================================================
|
||||
-- (all created inline above with KEY statements)
|
||||
|
||||
-- =============================================================================
|
||||
-- END OF SCHEMA v1.9.0
|
||||
-- =============================================================================
|
||||
Reference in New Issue
Block a user