251120:0800 add .

This commit is contained in:
admin
2025-11-20 08:14:27 +07:00
parent 4c961aa4ee
commit 859475b9f0
3 changed files with 1816 additions and 1656 deletions

View File

@@ -24,7 +24,7 @@ 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 PROCEDURE IF EXISTS sp_get_next_document_number;
-- 🗑️ DROP TABLE SCRIPT: LCBP3-DMS v1.4.2
-- คำเตือน: ข้อมูลทั้งหมดจะหายไป กรุณา Backup ก่อนรันบน Production
SET FOREIGN_KEY_CHECKS = 0;
@@ -36,7 +36,8 @@ 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 user_preferences;
-- [NEW v1.4.2] ตารางเก็บ Schema สำหรับ Validate JSON (Stand-alone)
DROP TABLE IF EXISTS json_schemas;
-- ============================================================
-- ส่วนที่ 2: ตาราง Junction (เชื่อมโยงข้อมูล M:N)
@@ -333,6 +334,7 @@ CREATE TABLE users (
last_login_at TIMESTAMP NULL COMMENT 'วันที่และเวลาที่ล็อกอินล่าสุด',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
deleted_at DATETIME NULL DEFAULT NULL COMMENT 'วันที่ลบ',
FOREIGN KEY (primary_organization_id) REFERENCES organizations(id) ON DELETE
SET NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บข้อมูลผู้ใช้งาน (User)';
@@ -340,8 +342,8 @@ CREATE TABLE users (
INSERT INTO users (username, password_hash, email, is_active)
VALUES (
'superadmin',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
'superadmin@example.com',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
'superadmin @example.com',
1
) ON DUPLICATE KEY
UPDATE email =
@@ -352,16 +354,16 @@ VALUES(is_active);
INSERT IGNORE INTO users (username, password_hash, email, is_active)
VALUES (
'editor01',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
'editor01@example.com',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
'editor01 @example.com',
1
);
-- Create viewer01 user (password hash placeholder, must change later)
INSERT IGNORE INTO users (username, password_hash, email, is_active)
VALUES (
'viewer01',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h/udq',
'viewer01@example.com',
'$2y$10$0kjBMxWq7E4G7P.dc8r5i.cjiPBiup553AsFpDfxUt31gKg9h',
'viewer01 @example.com',
1
);
-- ตาราง Master เก็บ "บทบาท" ของผู้ใช้ในระบบ
@@ -391,7 +393,7 @@ VALUES (
2,
'Org Admin',
'Organization',
'ผู้ดูแลองค์กร: จัดการผู้ใช้ในองค์กร, จัดการบทบาท/สิทธิ์ภายในองค์กร, และดูรายงานขององค์กร'
'ผู้ดูแลองค์กร: จัดการผู้ใช้ในองค์กร, จัดการบทบาท / สิทธิ์ภายในองค์กร, และดูรายงานขององค์กร'
);
-- 3. Document Control (Organization)
INSERT INTO roles (role_id, role_name, scope, description)
@@ -399,7 +401,7 @@ VALUES (
3,
'Document Control',
'Organization',
'ควบคุมเอกสารขององค์กร: เพิ่ม/แก้ไข/ลบเอกสาร, และกำหนดสิทธิ์เอกสารภายในองค์กร'
'ควบคุมเอกสารขององค์กร: เพิ่ม / แก้ไข / ลบเอกสาร, และกำหนดสิทธิ์เอกสารภายในองค์กร'
);
-- 4. Editor (Organization)
INSERT INTO roles (role_id, role_name, scope, description)
@@ -407,7 +409,7 @@ VALUES (
4,
'Editor',
'Organization',
'ผู้แก้ไขเอกสารขององค์กร: เพิ่ม/แก้ไขเอกสารที่ได้รับมอบหมาย'
'ผู้แก้ไขเอกสารขององค์กร: เพิ่ม / แก้ไขเอกสารที่ได้รับมอบหมาย'
);
-- 5. Viewer (Organization)
INSERT INTO roles (role_id, role_name, scope, description)
@@ -423,7 +425,7 @@ VALUES (
6,
'Project Manager',
'Project',
'ผู้จัดการโครงการ: จัดการสมาชิกในโครงการ, สร้าง/จัดการสัญญาในโครงการ, และดูรายงานโครงการ'
'ผู้จัดการโครงการ: จัดการสมาชิกในโครงการ, สร้าง / จัดการสัญญาในโครงการ, และดูรายงานโครงการ'
);
-- 7. Contract Admin (Contract)
INSERT INTO roles (role_id, role_name, scope, description)
@@ -431,7 +433,7 @@ VALUES (
7,
'Contract Admin',
'Contract',
'ผู้ดูแลสัญญา: จัดการสมาชิกในสัญญา, สร้าง/จัดการข้อมูลหลักเฉพาะสัญญา, และอนุมัติเอกสารในสัญญา'
'ผู้ดูแลสัญญา: จัดการสมาชิกในสัญญา, สร้าง / จัดการข้อมูลหลักเฉพาะสัญญา, และอนุมัติเอกสารในสัญญา'
);
-- ตาราง Master เก็บ "สิทธิ์" (Permission) หรือ "การกระทำ" ทั้งหมดในระบบ
CREATE TABLE permissions (
@@ -491,7 +493,7 @@ VALUES (
-- การจัดการผู้ใช้งาน
(18, 'user.create', 'สร้างผู้ใช้งานใหม่'),
(19, 'user.edit', 'แก้ไขข้อมูลผู้ใช้งาน'),
(20, 'user.delete', 'ลบ/ปิดการใช้งานผู้ใช้'),
(20, 'user.delete', 'ลบ / ปิดการใช้งานผู้ใช้'),
(21, 'user.view', 'ดูข้อมูลผู้ใช้งาน'),
(
22,
@@ -505,7 +507,7 @@ INSERT INTO permissions (permission_id, permission_name, description)
VALUES (
23,
'project.manage_members',
'จัดการสมาชิกในโครงการ (เชิญ/ถอดสมาชิก)'
'จัดการสมาชิกในโครงการ (เชิญ / ถอดสมาชิก)'
),
(
24,
@@ -536,7 +538,7 @@ INSERT INTO permissions (permission_id, permission_name, description)
VALUES (
29,
'document.create_draft',
'สร้างเอกสารในสถานะฉบับร่าง (Draft)'
'สร้างเอกสารในสถานะฉบับร่าง (Draft) '
),
(30, 'document.submit', 'ส่งเอกสาร (Submitted)'),
(31, 'document.view', 'ดูเอกสาร'),
@@ -544,19 +546,19 @@ VALUES (
(
33,
'document.admin_edit',
'แก้ไข/ถอน/ยกเลิกเอกสารที่ส่งแล้ว (Admin Power)'
'แก้ไข / ถอน / ยกเลิกเอกสารที่ส่งแล้ว (Admin Power) '
),
(34, 'document.delete', 'ลบเอกสาร'),
(
35,
'document.attach',
'จัดการไฟล์แนบ (อัปโหลด/ลบ)'
'จัดการไฟล์แนบ (อัปโหลด / ลบ) '
),
-- สิทธิ์เฉพาะสำหรับ Correspondence
(
36,
'correspondence.create',
'สร้างเอกสารโต้ตอบ (Correspondence)'
'สร้างเอกสารโต้ตอบ (Correspondence) '
),
-- สิทธิ์เฉพาะสำหรับ Request for Approval (RFA)
(37, 'rfa.create', 'สร้างเอกสารขออนุมัติ (RFA)'),
@@ -569,7 +571,7 @@ VALUES (
(
39,
'drawing.create',
'สร้าง/แก้ไขข้อมูลแบบ (Shop/Contract Drawing)'
'สร้าง / แก้ไขข้อมูลแบบ (Shop / Contract Drawing)'
),
-- สิทธิ์เฉพาะสำหรับ Transmittal
(
@@ -586,7 +588,7 @@ VALUES (
(
42,
'circulation.respond',
'ตอบกลับใบเวียน (Main/Action)'
'ตอบกลับใบเวียน (Main / Action)'
),
(
43,
@@ -621,7 +623,7 @@ VALUES (48, 'search.advanced', 'ใช้งานการค้นหาขั
(
49,
'report.generate',
'สร้างรายงานสรุป (รายวัน/สัปดาห์/เดือน/ปี)'
'สร้างรายงานสรุป (รายวัน / สัปดาห์ / เดือน / ปี)'
);
-- ตารางเชื่อมระหว่าง roles และ permissions (M:N)
CREATE TABLE role_permissions (
@@ -630,11 +632,11 @@ CREATE TABLE role_permissions (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง roles และ permissions (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง roles และ permissions (M :N)';
-- ==========================================================
-- Seed Role-Permissions Mapping (จับคู่สิทธิ์เริ่มต้น)
-- ==========================================================
-- Seed data for the 'role_permissions' table
-- Seed data for the 'role_permissions 'table
-- This table links roles to their specific permissions.
-- NOTE: This assumes the role_id and permission_id from the previous seed data files.
-- Superadmin (role_id = 1), Org Admin (role_id = 2), Document Control (role_id = 3), etc.
@@ -912,7 +914,7 @@ CREATE TABLE contract_organizations (
contract_id INT NOT NULL,
organization_id INT NOT NULL,
role_in_contract VARCHAR(100),
-- เช่น 'Owner', 'Designer', 'Consultant', 'Contractor'
-- เช่น 'Owner', 'Designer', 'Consultant', 'Contractor '
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
@@ -925,7 +927,7 @@ INSERT INTO project_organizations (project_id, organization_id)
SELECT (
SELECT id
FROM projects
WHERE project_code = 'LCBP3'
WHERE project_code = 'LCBP3 '
),
id
FROM organizations
@@ -939,28 +941,28 @@ WHERE organization_code IN (
'ผรม.3',
'ผรม.4',
'EN',
'CAR'
'CAR '
);
-- โครงการย่อย (LCBP3C1) จะมีเฉพาะองค์กรที่เกี่ยวข้อง
INSERT INTO project_organizations (project_id, organization_id)
SELECT (
SELECT id
FROM projects
WHERE project_code = 'LCBP3C1'
WHERE project_code = 'LCBP3C1 '
),
id
FROM organizations
WHERE organization_code IN ('กทท.', 'สคฉ.3', 'สคฉ.3-02', 'คคง.', 'ผรม.1');
WHERE organization_code IN ('กทท.', 'สคฉ.3', 'สคฉ.3 -02', 'คคง.', 'ผรม.1 ');
-- ทำเช่นเดียวกันสำหรับโครงการอื่นๆ (ตัวอย่าง)
INSERT INTO project_organizations (project_id, organization_id)
SELECT (
SELECT id
FROM projects
WHERE project_code = 'LCBP3C2'
WHERE project_code = 'LCBP3C2 '
),
id
FROM organizations
WHERE organization_code IN ('กทท.', 'สคฉ.3', 'สคฉ.3-03', 'คคง.', 'ผรม.2');
WHERE organization_code IN ('กทท.', 'สคฉ.3', 'สคฉ.3 -03', 'คคง.', 'ผรม.2 ');
-- =====================================================
-- == 5. การเชื่อมโยงสัญญากับองค์กร (contract_organizations) ==
-- =====================================================
@@ -998,7 +1000,7 @@ VALUES (
(
SELECT id
FROM contracts
WHERE contract_code = 'PSLCBP3'
WHERE contract_code = 'PSLCBP3 '
),
(
SELECT id
@@ -1011,7 +1013,7 @@ VALUES (
(
SELECT id
FROM contracts
WHERE contract_code = 'PSLCBP3'
WHERE contract_code = 'PSLCBP3 '
),
(
SELECT id
@@ -1039,7 +1041,7 @@ VALUES (
(
SELECT id
FROM contracts
WHERE contract_code = 'LCBP3-C1'
WHERE contract_code = 'LCBP3-C1 '
),
(
SELECT id
@@ -1113,7 +1115,7 @@ CREATE TABLE correspondence_types (
type_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัสประเภท (เช่น RFA, RFI)',
type_name VARCHAR(255) NOT NULL COMMENT 'ชื่อประเภท',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บประเภทเอกสารโต้ตอบ';
INSERT INTO correspondence_types (type_code, type_name, sort_order, is_active)
VALUES ('RFA', 'Request for Approval', 1, 1),
@@ -1137,7 +1139,7 @@ CREATE TABLE correspondence_status (
status_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัสสถานะหนังสือ (เช่น DRAFT, SUBOWN)',
status_name VARCHAR(255) NOT NULL COMMENT 'ชื่อสถานะหนังสือ',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บสถานะของเอกสาร';
INSERT INTO correspondence_status (status_code, status_name, sort_order, is_active)
VALUES ('DRAFT', 'Draft', 10, 1),
@@ -1208,12 +1210,12 @@ CREATE TABLE correspondence_revisions (
SET NULL,
UNIQUE KEY uq_master_revision_number (correspondence_id, revision_number),
UNIQUE KEY uq_master_current (correspondence_id, is_current)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติการแก้ไข (Revisions) ของ correspondences (1:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติการแก้ไข (Revisions) ของ correspondences (1 :N)';
-- ตารางเชื่อมผู้รับ (TO/CC) สำหรับเอกสารแต่ละฉบับ (M:N)
CREATE TABLE correspondence_recipients (
correspondence_id INT COMMENT 'ID ของเอกสาร',
recipient_organization_id INT COMMENT 'ID องค์กรผู้รับ',
recipient_type ENUM('TO', 'CC') COMMENT 'ประเภทผู้รับ (TO หรือ CC)',
recipient_type ENUM('TO', 'CC ') COMMENT 'ประเภทผู้รับ (TO หรือ CC)',
PRIMARY KEY (
correspondence_id,
recipient_organization_id,
@@ -1221,14 +1223,14 @@ CREATE TABLE correspondence_recipients (
),
FOREIGN KEY (correspondence_id) REFERENCES correspondence_revisions(correspondence_id) ON DELETE CASCADE,
FOREIGN KEY (recipient_organization_id) REFERENCES organizations(id) ON DELETE RESTRICT
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมผู้รับ (TO/CC) สำหรับเอกสารแต่ละฉบับ (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมผู้รับ (TO / CC) สำหรับเอกสารแต่ละฉบับ (M :N)';
-- ตาราง Master เก็บ Tags ทั้งหมดที่ใช้ในระบบ
CREATE TABLE tags (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
tag_name VARCHAR(100) NOT NULL UNIQUE COMMENT 'ชื่อ Tag',
description TEXT COMMENT 'คำอธิบายแท็ก',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด'
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บ Tags ทั้งหมดที่ใช้ในระบบ';
-- ตารางเชื่อมระหว่าง correspondences และ tags (M:N)
CREATE TABLE correspondence_tags (
@@ -1237,7 +1239,7 @@ CREATE TABLE correspondence_tags (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง correspondences และ tags (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง correspondences และ tags (M :N)';
-- ตารางเชื่อมการอ้างอิงระหว่างเอกสาร (M:N)
CREATE TABLE correspondence_references (
src_correspondence_id INT COMMENT 'ID เอกสารต้นทาง',
@@ -1245,7 +1247,7 @@ CREATE TABLE correspondence_references (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมการอ้างอิงระหว่างเอกสาร (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมการอ้างอิงระหว่างเอกสาร (M :N)';
-- =====================================================
-- 4. 📐 approval: RFA (เอกสารขออนุมัติ, Workflows)
-- =====================================================
@@ -1280,7 +1282,7 @@ CREATE TABLE correspondence_routing_template_steps (
template_id INT NOT NULL COMMENT 'ID ของแม่แบบ',
sequence INT NOT NULL COMMENT 'ลำดับขั้นตอน',
to_organization_id INT NOT NULL COMMENT 'ID องค์กรณ์ผู้รับในขั้นตอนนี้',
step_purpose ENUM('FOR_APPROVAL', 'FOR_REVIEW', 'FOR_INFORMATION') NOT NULL DEFAULT 'FOR_REVIEW' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้',
step_purpose ENUM('FOR_APPROVAL', 'FOR_REVIEW', 'FOR_INFORMATION ') NOT NULL DEFAULT 'FOR_REVIEW ' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้',
expected_days INT NULL,
UNIQUE KEY ux_cor_template_sequence (template_id, sequence),
CONSTRAINT fk_cwts_template FOREIGN KEY (template_id) REFERENCES correspondence_routing_templates(id) ON DELETE CASCADE,
@@ -1292,7 +1294,7 @@ CREATE TABLE correspondence_routing_template_steps (
-- เหตุผล: เก็บ Snapshot ข้อมูล ณ ขณะนั้นเพื่อใช้ตัดสินใจใน Step ถัดไป
CREATE TABLE correspondence_routings (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'ID ของขั้นตอน',
correspondence_id INT NOT NULL COMMENT 'ID ของเอกสาร(FK -> correspondence_revisions)',
correspondence_id INT NOT NULL COMMENT 'ID ของเอกสาร(FK->correspondence_revisions)',
template_id INT NULL COMMENT 'ID ของแม่แบบที่ใช้ (ถ้ามี)',
-- สำหรับอ้างอิงถึงแม่แบบ
sequence INT NOT NULL COMMENT 'ลำดับของขั้นตอนการส่งต่อ',
@@ -1302,15 +1304,17 @@ CREATE TABLE correspondence_routings (
'FOR_APPROVAL',
'FOR_REVIEW',
'FOR_INFORMATION',
'FOR_ACTION'
) NOT NULL DEFAULT 'FOR_REVIEW' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้ เช่น เพื่ออนุมัติ, เพื่อตรวจสอบ, หรือเพื่อรับทราบ',
'FOR_ACTION '
) NOT NULL DEFAULT 'FOR_REVIEW ' COMMENT 'วัตถุประสงค์ของขั้นตอนนี้ เช่น เพื่ออนุมัติ,
เพื่อตรวจสอบ,
หรือเพื่อรับทราบ',
status ENUM(
'SENT',
'RECEIVED',
'ACTIONED',
'FORWARDED',
'REPLIED'
) NOT NULL DEFAULT 'SENT' COMMENT 'สถานะการดำเนินการของเอกสารในขั้นตอนนี้',
'REPLIED '
) NOT NULL DEFAULT 'SENT ' COMMENT 'สถานะการดำเนินการของเอกสารในขั้นตอนนี้',
comments TEXT COMMENT 'หมายเหตุ หรือความคิดเห็นในการส่งต่อ',
due_date DATETIME NULL COMMENT 'วันที่ต้องตอบเอกสารในขั้นตอนนี้',
processed_by_user_id INT NULL COMMENT 'ID ของผู้ใช้ที่ดำเนินการในขั้นตอนนี้',
@@ -1334,7 +1338,7 @@ CREATE TABLE rfa_types (
type_name VARCHAR(100) NOT NULL COMMENT 'ชื่อประเภท RFA',
description TEXT COMMENT 'คำอธิบาย',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master สำหรับประเภท RFA';
INSERT INTO rfa_types (type_code, type_name, sort_order, is_active)
VALUES ('DWG', 'Shop Drawing', 10, 1),
@@ -1343,10 +1347,10 @@ VALUES ('DWG', 'Shop Drawing', 10, 1),
('CAL', 'Calculation', 22, 1),
('TRP', 'Test Report', 23, 1),
('SRY', 'Survey Report', 24, 1),
('QAQC', 'QA/QC Document', 25, 1),
('QAQC', 'QA / QC Document', 25, 1),
('MES', 'Method Statement', 30, 1),
('MAT', 'Material', 40, 1),
('ASB', 'As-Built', 50, 1),
('ASB', 'As - Built', 50, 1),
('OTH', 'Other', 99, 1);
-- ตาราง Master สำหรับสถานะ RFA
CREATE TABLE rfa_status_codes (
@@ -1355,7 +1359,7 @@ CREATE TABLE rfa_status_codes (
status_name VARCHAR(100) NOT NULL COMMENT 'ชื่อสถานะ',
description TEXT COMMENT 'คำอธิบาย',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master สำหรับสถานะ RFA';
INSERT INTO rfa_status_codes (
status_code,
@@ -1367,17 +1371,21 @@ VALUES ('DFT', 'Draft', 'ฉบับร่าง', 1),
('FAP', 'For Approve', 'เพื่อขออนุมัติ', 11),
('FRE', 'For Review', 'เพื่อตรวจสอบ', 12),
('FCO', 'For Construction', 'เพื่อก่อสร้าง', 20),
('ASB', 'AS-Built', 'แบบก่อสร้างจริง', 30),
('ASB', 'AS - Built', 'แบบก่อสร้างจริง', 30),
('OBS', 'Obsolete', 'ไม่ใช้งาน', 80),
('CC', 'Canceled', 'ยกเลิก', 99);
-- ตาราง Master สำหรับรหัสผลการอนุมัติ RFA
CREATE TABLE rfa_approve_codes (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
approve_code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสผลการอนุมัติ (เช่น 1A - Approved, 3R - Revise and Resubmit)',
approve_code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสผลการอนุมัติ (
เช่น 1A - Approved,
3R - Revise
and Resubmit
)',
approve_name VARCHAR(100) NOT NULL COMMENT 'ชื่อผลการอนุมัติ',
description TEXT COMMENT 'คำอธิบาย',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master สำหรับรหัสผลการอนุมัติ RFA';
INSERT INTO rfa_approve_codes (
approve_code,
@@ -1390,7 +1398,8 @@ VALUES ('1A', 'Approved by Authority', 10, 1),
('1N', 'Approved As Note', 12, 1),
('1R', 'Approved with Remarks', 13, 1),
('3C', 'Consultant Comments', 31, 1),
('3R', 'Revise and Resubmit', 32, 1),
('3R', 'Revise
and Resubmit', 32, 1),
('4X', 'Reject', 40, 1),
('5N', 'No Further Action', 50, 1);
-- ตาราง "แม่" ของ RFA (มีความสัมพันธ์ 1:N กับ rfa_revisions)
@@ -1403,7 +1412,7 @@ CREATE TABLE rfas (
FOREIGN KEY (rfa_type_id) REFERENCES rfa_types(id),
FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE
SET NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "แม่" ของ RFA (มีความสัมพันธ์ 1:N กับ rfa_revisions)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "แม่" ของ RFA (มีความสัมพันธ์ 1 :N กับ rfa_revisions)';
-- ตาราง "ลูก" เก็บประวัติ (Revisions) ของ rfas (1:N)
CREATE TABLE rfa_revisions (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของ Revision',
@@ -1434,7 +1443,7 @@ CREATE TABLE rfa_revisions (
SET NULL,
UNIQUE KEY uq_rr_rev_number (rfa_id, revision_number),
UNIQUE KEY uq_rr_current (rfa_id, is_current)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติ (Revisions) ของ rfas (1:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติ (Revisions) ของ rfas (1 :N)';
-- ตารางเชื่อมระหว่าง rfa_revisions (ที่เป็นประเภท DWG) กับ shop_drawing_revisions (M:N)
CREATE TABLE rfa_items (
rfarev_correspondence_id INT COMMENT 'ID ของ RFA Revision',
@@ -1445,7 +1454,7 @@ CREATE TABLE rfa_items (
),
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง rfa_revisions (ที่เป็นประเภท DWG) กับ shop_drawing_revisions (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง rfa_revisions (ที่เป็นประเภท DWG) กับ shop_drawing_revisions (M :N)';
-- ตาราง Master เก็บแม่แบบสายอนุมัติ
-- 3.1 Workflow Config for Templates
-- รองรับ: Backend Plan T3.1
@@ -1457,7 +1466,7 @@ CREATE TABLE rfa_workflow_templates (
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
workflow_config JSON NULL COMMENT 'State Machine Configuration Rules'
workflow_config JSON NULL COMMENT 'State Machine Configuration Rules '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บแม่แบบสายอนุมัติ';
-- ตารางลูก เก็บขั้นตอนในแม่แบบ
CREATE TABLE rfa_workflow_template_steps (
@@ -1466,7 +1475,7 @@ CREATE TABLE rfa_workflow_template_steps (
step_number INT NOT NULL COMMENT 'ลำดับขั้นตอน',
organization_id INT NOT NULL COMMENT 'องค์กรที่รับผิดชอบ',
role_id INT COMMENT 'บทบาทที่รับผิดชอบ',
action_type ENUM('REVIEW', 'APPROVE', 'ACKNOWLEDGE') COMMENT 'ประเภทการกระทำ',
action_type ENUM('REVIEW', 'APPROVE', 'ACKNOWLEDGE ') COMMENT 'ประเภทการกระทำ',
duration_days INT COMMENT 'ระยะเวลาที่กำหนด (วัน)',
is_optional BOOLEAN DEFAULT FALSE COMMENT 'เป็นขั้นตอนเลือกหรือไม่',
FOREIGN KEY (template_id) REFERENCES rfa_workflow_templates(id) ON DELETE CASCADE,
@@ -1483,12 +1492,12 @@ CREATE TABLE rfa_workflows (
step_number INT NOT NULL COMMENT 'ลำดับขั้นตอน',
organization_id INT NOT NULL COMMENT 'องค์กรที่รับผิดชอบ',
assigned_to INT COMMENT 'ผู้ใช้ที่ได้รับมอบหมาย',
action_type ENUM('REVIEW', 'APPROVE', 'ACKNOWLEDGE') COMMENT 'ประเภทการกระทำ',
action_type ENUM('REVIEW', 'APPROVE', 'ACKNOWLEDGE ') COMMENT 'ประเภทการกระทำ',
status ENUM(
'PENDING',
'IN_PROGRESS',
'COMPLETED',
'REJECTED'
'REJECTED '
) COMMENT 'สถานะ',
comments TEXT COMMENT 'ความคิดเห็น',
completed_at DATETIME COMMENT 'วันที่เสร็จสิ้น',
@@ -1550,7 +1559,7 @@ CREATE TABLE contract_drawing_subcat_cat_maps (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง หมวดหมู่หลัก-ย่อย (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง หมวดหมู่หลัก - ย่อย (M :N)';
-- ตาราง Master เก็บข้อมูล "แบบคู่สัญญา"
CREATE TABLE contract_drawings (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
@@ -1577,12 +1586,12 @@ CREATE TABLE shop_drawing_main_categories (
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด'
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master สำหรับ "หมวดหมู่หลัก" ของแบบก่อสร้าง';
-- ตาราง Master สำหรับ "หมวดหมู่ย่อย" ของแบบก่อสร้าง
CREATE TABLE shop_drawing_sub_categories (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
sub_category_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัสหมวดหมู่ย่อย (เช่น STR-COLUMN)',
sub_category_code VARCHAR(50) NOT NULL UNIQUE COMMENT 'รหัสหมวดหมู่ย่อย (เช่น STR - COLUMN)',
sub_category_name VARCHAR(255) NOT NULL COMMENT 'ชื่อหมวดหมู่ย่อย',
main_category_id INT NOT NULL COMMENT 'หมวดหมู่หลัก',
description TEXT COMMENT 'คำอธิบาย',
@@ -1619,7 +1628,7 @@ CREATE TABLE shop_drawing_revisions (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
FOREIGN KEY (shop_drawing_id) REFERENCES shop_drawings(id) ON DELETE CASCADE,
UNIQUE KEY ux_sd_rev_drawing_revision (shop_drawing_id, revision_number)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติ (Revisions) ของ shop_drawings (1:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "ลูก" เก็บประวัติ (Revisions) ของ shop_drawings (1 :N)';
-- ตารางเชื่อมระหว่าง shop_drawing_revisions กับ contract_drawings (M:N)
CREATE TABLE shop_drawing_revision_contract_refs (
shop_drawing_revision_id INT COMMENT 'ID ของ Shop Drawing Revision',
@@ -1627,7 +1636,7 @@ CREATE TABLE shop_drawing_revision_contract_refs (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง shop_drawing_revisions กับ contract_drawings (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง shop_drawing_revisions กับ contract_drawings (M :N)';
-- =====================================================
-- 6. 🔄 Circulations (ใบเวียนภายใน)
-- =====================================================
@@ -1637,13 +1646,13 @@ CREATE TABLE circulation_status_codes (
code VARCHAR(20) NOT NULL UNIQUE COMMENT 'รหัสสถานะการดำเนินงาน',
description VARCHAR(50) NOT NULL COMMENT 'คำอธิบายสถานะการดำเนินงาน',
sort_order INT DEFAULT 0 COMMENT 'ลำดับการแสดงผล',
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน'
is_active TINYINT(1) DEFAULT 1 COMMENT 'สถานะการใช้งาน '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง Master เก็บสถานะใบเวียน';
INSERT INTO circulation_status_codes (code, description, sort_order)
VALUES ('OPEN', 'Open', 1),
('IN_REVIEW', 'In Review', 2),
('COMPLETED', 'ปCompleted', 3),
('CANCELLED', 'Cancelled/Withdrawn', 9);
('CANCELLED', 'Cancelled / Withdrawn', 9);
-- ตาราง "แม่" ของใบเวียนเอกสารภายใน
CREATE TABLE circulations (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตารางใบเวียน',
@@ -1697,7 +1706,7 @@ CREATE TABLE circulation_routings (
'PENDING',
'IN_PROGRESS',
'COMPLETED',
'REJECTED'
'REJECTED '
) COMMENT 'สถานะ',
comments TEXT COMMENT 'ความคิดเห็น',
completed_at DATETIME COMMENT 'วันที่เสร็จสิ้น',
@@ -1717,11 +1726,11 @@ CREATE TABLE transmittals (
'FOR_APPROVAL',
'FOR_INFORMATION',
'FOR_REVIEW',
'OTHER'
'OTHER '
) COMMENT 'วัตถุประสงค์',
remarks TEXT COMMENT 'หมายเหตุ',
FOREIGN KEY (correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางข้อมูลเฉพาะของเอกสารนำส่ง (เป็นตารางลูก 1:1 ของ correspondences)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางข้อมูลเฉพาะของเอกสารนำส่ง (เป็นตารางลูก 1 :1 ของ correspondences)';
-- ตารางเชื่อมระหว่าง transmittals และเอกสารที่นำส่ง (M:N)
CREATE TABLE transmittal_items (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของรายการ',
@@ -1732,7 +1741,7 @@ CREATE TABLE transmittal_items (
FOREIGN KEY (transmittal_id) REFERENCES transmittals(correspondence_id) ON DELETE CASCADE,
FOREIGN KEY (item_correspondence_id) REFERENCES correspondences(id) ON DELETE CASCADE,
UNIQUE KEY ux_transmittal_item (transmittal_id, item_correspondence_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง transmittals และเอกสารที่นำส่ง (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อมระหว่าง transmittals และเอกสารที่นำส่ง (M :N)';
-- =====================================================
-- 8. 📎 File Management (ไฟล์แนบ)
-- =====================================================
@@ -1744,13 +1753,16 @@ CREATE TABLE attachments (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของไฟล์แนบ',
original_filename VARCHAR(255) NOT NULL COMMENT 'ชื่อไฟล์ดั้งเดิมตอนอัปโหลด',
stored_filename VARCHAR(255) NOT NULL COMMENT 'ชื่อไฟล์ที่เก็บจริงบน Server (ป้องกันชื่อซ้ำ)',
file_path VARCHAR(500) NOT NULL COMMENT 'Path ที่เก็บไฟล์ (บน QNAP /share/dms-data/)',
mime_type VARCHAR(100) NOT NULL COMMENT 'ประเภทไฟล์ (เช่น application/pdf)',
file_path VARCHAR(500) NOT NULL COMMENT 'Path ที่เก็บไฟล์ (บน QNAP / share / dms - data /)',
mime_type VARCHAR(100) NOT NULL COMMENT 'ประเภทไฟล์ (เช่น application / pdf)',
file_size INT NOT NULL COMMENT 'ขนาดไฟล์ (bytes)',
is_temporary BOOLEAN DEFAULT TRUE COMMENT 'True=ยังไม่ Commit ลง DB จริง',
temp_id VARCHAR(100) NULL COMMENT 'ID ชั่วคราวสำหรับอ้างอิงตอน Upload Phase 1' uploaded_by_user_id INT NOT NULL COMMENT 'ผู้อัปโหลดไฟล์',
is_temporary BOOLEAN DEFAULT TRUE COMMENT 'True = ยังไม่ Commit ลง DB จริง',
temp_id VARCHAR(100) NULL COMMENT 'ID ชั่วคราวสำหรับอ้างอิงตอน Upload Phase 1',
uploaded_by_user_id INT NOT NULL COMMENT 'ผู้อัปโหลดไฟล์',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่อัปโหลด',
expires_at DATETIME NULL COMMENT 'เวลาหมดอายุของไฟล์ Temp' checksum VARCHAR(64) NULL COMMENT 'SHA-256 Checksum' FOREIGN KEY (uploaded_by_user_id) REFERENCES users(user_id) ON DELETE CASCADE
expires_at DATETIME NULL COMMENT 'เวลาหมดอายุของไฟล์ Temp',
checksum VARCHAR(64) NULL COMMENT 'SHA -256 Checksum',
FOREIGN KEY (uploaded_by_user_id) REFERENCES users(user_id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
-- ตารางเชื่อม correspondences กับ attachments (M:N)
CREATE TABLE correspondence_attachments (
@@ -1760,7 +1772,7 @@ CREATE TABLE correspondence_attachments (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม correspondences กับ attachments (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม correspondences กับ attachments (M :N)';
-- ตารางเชื่อม circulations กับ attachments (M:N)
CREATE TABLE circulation_attachments (
circulation_id INT COMMENT 'ID ของใบเวียน',
@@ -1769,27 +1781,27 @@ CREATE TABLE circulation_attachments (
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม circulations กับ attachments (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม circulations กับ attachments (M :N)';
-- ตารางเชื่อม shop_drawing_revisions กับ attachments (M:N)
CREATE TABLE shop_drawing_revision_attachments (
shop_drawing_revision_id INT COMMENT 'ID ของ Shop Drawing Revision',
attachment_id INT COMMENT 'ID ของไฟล์แนบ',
file_type ENUM('PDF', 'DWG', 'SOURCE', 'OTHER') COMMENT 'ประเภทไฟล์',
file_type ENUM('PDF', 'DWG', 'SOURCE', 'OTHER ') COMMENT 'ประเภทไฟล์',
is_main_document BOOLEAN DEFAULT FALSE COMMENT '(1 = ไฟล์หลัก)',
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม shop_drawing_revisions กับ attachments (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม shop_drawing_revisions กับ attachments (M :N)';
-- ตารางเชื่อม contract_drawings กับ attachments (M:N)
CREATE TABLE contract_drawing_attachments (
contract_drawing_id INT COMMENT 'ID ของ Contract Drawing',
attachment_id INT COMMENT 'ID ของไฟล์แนบ',
file_type ENUM('PDF', 'DWG', 'SOURCE', 'OTHER') COMMENT 'ประเภทไฟล์',
file_type ENUM('PDF', 'DWG', 'SOURCE', 'OTHER ') COMMENT 'ประเภทไฟล์',
is_main_document BOOLEAN DEFAULT FALSE COMMENT '(1 = ไฟล์หลัก)',
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
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม contract_drawings กับ attachments (M:N)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเชื่อม contract_drawings กับ attachments (M :N)';
-- =====================================================
-- 9. 🔢 Document Numbering (การสร้างเลขที่เอกสาร)
-- =====================================================
@@ -1798,7 +1810,7 @@ CREATE TABLE document_number_formats (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง',
project_id INT NOT NULL COMMENT 'โครงการ',
correspondence_type_id INT NOT NULL COMMENT 'ประเภทเอกสาร',
format_template VARCHAR(255) NOT NULL COMMENT 'รูปแบบ Template (เช่น {ORG_CODE}-{TYPE_CODE}-{SEQ:4})',
format_template VARCHAR(255) NOT NULL COMMENT 'รูปแบบ Template (เช่น { ORG_CODE } - { TYPE_CODE } - { SEQ :4 })',
description TEXT COMMENT 'คำอธิบายรูปแบบนี้',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
@@ -1814,7 +1826,7 @@ CREATE TABLE document_number_counters (
project_id INT COMMENT 'โครงการ',
originator_organization_id INT COMMENT 'องค์กรผู้ส่ง',
correspondence_type_id INT COMMENT 'ประเภทเอกสาร',
current_year INT COMMENT 'ปี ค.ศ. ของตัวนับ',
current_year INT COMMENT 'ปี ค.ศ.ของตัวนับ',
version INT DEFAULT 0 NOT NULL COMMENT 'Optimistic Lock Version',
last_number INT DEFAULT 0 COMMENT 'เลขที่ล่าสุดที่ใช้ไปแล้ว',
PRIMARY KEY (
@@ -1835,7 +1847,8 @@ CREATE TABLE document_number_counters (
-- เหตุผล: เพื่อ Validate โครงสร้าง JSON Details ของเอกสารแต่ละประเภทแบบ Centralized
CREATE TABLE IF NOT EXISTS json_schemas (
id INT AUTO_INCREMENT PRIMARY KEY,
schema_code VARCHAR(100) NOT NULL UNIQUE COMMENT 'รหัส Schema เช่น RFA_DWG_V1, CORR_GENERIC',
schema_code VARCHAR(100) NOT NULL UNIQUE COMMENT 'รหัส Schema เช่น RFA_DWG_V1,
CORR_GENERIC',
version INT NOT NULL DEFAULT 1 COMMENT 'เวอร์ชันของ Schema',
schema_definition JSON NOT NULL COMMENT 'โครงสร้าง JSON Schema (Standard Format)',
is_active BOOLEAN DEFAULT TRUE,
@@ -1850,7 +1863,7 @@ CREATE TABLE IF NOT EXISTS user_preferences (
user_id INT PRIMARY KEY,
notify_email BOOLEAN DEFAULT TRUE,
notify_line BOOLEAN DEFAULT TRUE,
digest_mode BOOLEAN DEFAULT FALSE COMMENT 'รับแจ้งเตือนแบบรวม (Digest) แทน Real-time',
digest_mode BOOLEAN DEFAULT FALSE COMMENT 'รับแจ้งเตือนแบบรวม (Digest) แทน Real - time',
ui_theme VARCHAR(20) DEFAULT 'light',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_user_prefs_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
@@ -1863,9 +1876,13 @@ CREATE TABLE audit_logs (
audit_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของ Log',
request_id VARCHAR(100) NULL COMMENT 'Trace ID linking to app logs',
user_id INT COMMENT 'ผู้กระทำ',
action VARCHAR(100) NOT NULL COMMENT 'การกระทำ (เช่น rfa.create, correspondence.update, login.success)',
severity ENUM('INFO', 'WARN', 'ERROR', 'CRITICAL') DEFAULT 'INFO',
entity_type VARCHAR(50) COMMENT 'ตาราง/โมดูล (เช่น ''rfa'', ''correspondence'')',
action VARCHAR(100) NOT NULL COMMENT 'การกระทำ (
เช่น rfa.create,
correspondence.update,
login.success
)',
severity ENUM('INFO', 'WARN', 'ERROR', 'CRITICAL ') DEFAULT 'INFO',
entity_type VARCHAR(50) COMMENT 'ตาราง / โมดูล (เช่น ''rfa '', ''correspondence '')',
entity_id VARCHAR(50) COMMENT 'Primary ID ของระเบียนที่ได้รับผลกระทำ',
details_json JSON COMMENT 'ข้อมูลบริบท',
ip_address VARCHAR(45) COMMENT 'IP Address',
@@ -1880,21 +1897,22 @@ CREATE TABLE notifications (
user_id INT NOT NULL COMMENT 'ID ผู้ใช้',
title VARCHAR(255) NOT NULL COMMENT 'หัวข้อการแจ้งเตือน',
message TEXT NOT NULL COMMENT 'รายละเอียดการแจ้งเตือน',
notification_type ENUM('EMAIL', 'LINE', 'SYSTEM') NOT NULL COMMENT 'ประเภท (EMAIL, LINE, SYSTEM)',
notification_type ENUM('EMAIL', 'LINE', 'SYSTEM ') NOT NULL COMMENT 'ประเภท (EMAIL, LINE, SYSTEM)',
is_read BOOLEAN DEFAULT FALSE COMMENT 'สถานะการอ่าน',
entity_type VARCHAR(50) COMMENT 'เช่น ''rfa'', ''circulation''',
entity_type VARCHAR(50) COMMENT 'เช่น ''rfa '',
''circulation ''',
entity_id INT COMMENT 'ID ของเอนทิตีที่เกี่ยวข้อง',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางสำหรับจัดการการแจ้งเตือน (Email/Line/System)';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางสำหรับจัดการการแจ้งเตือน (Email / Line / System)';
-- ตารางสำหรับจัดการดัชนีการค้นหาขั้นสูง (Full-text Search)
CREATE TABLE search_indices (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของดัชนี',
entity_type VARCHAR(50) NOT NULL COMMENT 'ชนิดเอนทิตี (เช่น ''correspondence'', ''rfa'')',
entity_type VARCHAR(50) NOT NULL COMMENT 'ชนิดเอนทิตี (เช่น ''correspondence '', ''rfa '')',
entity_id INT NOT NULL COMMENT 'ID ของเอนทิตี',
content TEXT NOT NULL COMMENT 'เนื้อหาที่จะค้นหา',
indexed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง/อัปเดตัชนี'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางสำหรับจัดการดัชนีการค้นหาขั้นสูง (Full-text Search)';
indexed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง / อัปเดตัชนี '
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางสำหรับจัดการดัชนีการค้นหาขั้นสูง (Full - text Search)';
-- ตารางสำหรับบันทึกประวัติการสำรองข้อมูล
CREATE TABLE backup_logs (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของการสำรอง',

View File

@@ -146,6 +146,7 @@
| 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**:

View File

@@ -117,7 +117,7 @@ PORT=3000
NODE_ENV=development
# Security
JWT_SECRET=your_super_secret_key_change_it
JWT_SECRET=eebc122aa65adde8c76c6a0847d9649b2b67a06db1504693e6c912e51499b76e
```
### ขั้นตอนต่อไป (Next Steps)
@@ -374,3 +374,144 @@ JWT_EXPIRATION=8h
2. **Environment:** ควรแยก Secret ระหว่างเครื่อง `Development` และ `Production` ไม่ควรใช้ Key เดียวกัน
คุณต้องการให้ผมช่วยตั้งค่า `ConfigModule` ใน NestJS เพื่ออ่านค่า `JWT_SECRET` นี้อย่างปลอดภัยพร้อม Validate ว่าห้ามเป็นค่าว่างไหมครับ?
## ได้เลยครับ เรามาลุยงาน **T0.1 Secure Configuration Setup** ตามแผน Backend Plan กันต่อครับ
เป้าหมายของ Task นี้คือการทำให้ระบบอ่านค่า Environment Variables ได้อย่างถูกต้อง และ **"ต้องไม่ Start"** ถ้าค่า Config สำคัญๆ (เช่น Database Password, JWT Secret) หายไป หรือไม่ถูกต้อง เพื่อความปลอดภัยครับ
### 1. ติดตั้ง Library ที่จำเป็น
เราจะใช้ `@nestjs/config` สำหรับจัดการ Config และ `joi` สำหรับตรวจสอบความถูกต้อง (Validation) ครับ
รันคำสั่งนี้ใน Terminal:
```bash
pnpm add @nestjs/config joi
```
### 2. สร้าง Validation Schema
เราจะแยก Logic การตรวจสอบออกมาเป็นไฟล์เฉพาะ เพื่อให้โค้ดเป็นระเบียบครับ
สร้างไฟล์ใหม่: `src/common/config/env.validation.ts`
```typescript
// File: src/common/config/env.validation.ts
import Joi from 'joi';
// สร้าง Schema สำหรับตรวจสอบค่า Environment Variables
export const envValidationSchema = Joi.object({
// 1. Application Environment
NODE_ENV: Joi.string()
.valid('development', 'production', 'test', 'provision')
.default('development'),
PORT: Joi.number().default(3000),
// 2. Database Configuration (MariaDB)
// ห้ามเป็นค่าว่าง (required)
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().default(3306),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_DATABASE: Joi.string().required(),
// 3. Security (JWT)
// ต้องมีค่า และควรยาวพอ (ตรวจสอบความยาวได้ถ้าระบุ min)
JWT_SECRET: Joi.string().required().min(32).message('JWT_SECRET must be at least 32 characters long for security.'),
JWT_EXPIRATION: Joi.string().default('8h'),
});
```
### 3. อัปเดต `AppModule` ให้ใช้ Validation
กลับไปแก้ไขไฟล์ `src/app.module.ts` เพื่อนำ Schema ที่เราสร้างมาใช้งานครับ
```typescript
// File: src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { envValidationSchema } from './common/config/env.validation.js'; // สังเกต .js สำหรับ ESM
@Module({
imports: [
// 1. Setup Config Module พร้อม Validation
ConfigModule.forRoot({
isGlobal: true, // เรียกใช้ได้ทั่วทั้ง App ไม่ต้อง import ซ้ำ
envFilePath: '.env', // อ่านไฟล์ .env (สำหรับ Dev)
validationSchema: envValidationSchema, // ใช้ Schema ที่เราสร้างเพื่อตรวจสอบ
validationOptions: {
// ถ้ามีค่าไหนไม่ผ่าน Validation ให้ Error และหยุดทำงานทันที
abortEarly: true,
},
}),
// 2. Setup TypeORM (MariaDB)
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'mariadb',
host: configService.get<string>('DB_HOST'),
port: configService.get<number>('DB_PORT'),
username: configService.get<string>('DB_USERNAME'),
password: configService.get<string>('DB_PASSWORD'),
database: configService.get<string>('DB_DATABASE'),
autoLoadEntities: true,
// synchronize: true เฉพาะตอน Dev เท่านั้น ห้ามใช้บน Prod
synchronize: configService.get<string>('NODE_ENV') === 'development',
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
```
### 4\. สร้างไฟล์ Template สำหรับ Docker Override (ตามแผน T0.1)
ตามแผนงาน เราต้องเตรียมไฟล์ `docker-compose.override.yml.example` เพื่อให้นักพัฒนาคนอื่นรู้ว่าต้อง Inject Secrets อย่างไร โดยไม่เปิดเผยความลับใน `docker-compose.yml` หลัก
สร้างไฟล์: `docker-compose.override.yml.example` ที่ root project:
```yaml
version: '3.8'
services:
# Override ค่า Config ของ Service Backend (เมื่อเราสร้าง Container Backend ในอนาคต)
backend:
environment:
# ใส่ Secrets จริงในไฟล์ override นี้ (และห้าม commit ไฟล์นี้)
- DB_PASSWORD=secret_password_here
- JWT_SECRET=very_long_and_secure_secret_here
- NODE_ENV=development
# Override สำหรับ Database (Local Dev)
mariadb:
environment:
- MYSQL_ROOT_PASSWORD=secret_password_here
- MYSQL_PASSWORD=secret_password_here
```
### 5\. ทดสอบความปลอดภัย (Validation Check)
ลองทดสอบว่าระบบ Validation ทำงานถูกต้องหรือไม่ โดยการ **ลบ** หรือ **เปลี่ยนชื่อ** ตัวแปรสำคัญในไฟล์ `.env` (เช่น ลบ `JWT_SECRET`) แล้วลองรัน:
```bash
pnpm start:dev
```
**ผลลัพธ์ที่ควรได้:**
App **ต้อง Crash** และแสดง Error Message ชัดเจน เช่น:
`Config validation error: "JWT_SECRET" is required`
ถ้าขึ้นแบบนี้แสดงว่าระบบ **Secure Configuration** ของเราทำงานถูกต้องตามแผน T0.1 แล้วครับ\! 🎉
-----
**ขั้นตอนถัดไป:**
เราจะไปต่อที่ **T0.2 Redis & Queue Infrastructure** เพื่อเตรียมระบบ Caching และ Background Job ไหมครับ?