03. Database Design Architecture & Data Dictionary
Project: Thai Traditional Massage Queue Management System (TTMQMS Enterprise)
Database Engine: MySQL 8.0 / Percona Server (InnoDB Engine, utf8mb4_unicode_ci)
Normalization: 3rd Normal Form (3NF) Compliant
Version: 1.0.0 Production
1. Database Architecture & Design Principles
ฐานข้อมูลของระบบ TTMQMS ถูกออกแบบด้วยสถาปัตยกรรมเชิงสัมพันธ์ (Relational Database Architecture) ภายใต้มาตรฐานสากล โดยมีคุณสมบัติดังนี้:
- ACID Compliance & Transactional Integrity: ทุกตารางใช้เครื่องยนต์ InnoDB รองรับ Foreign Key Constraints และ Atomic Transactions
- Unicode utf8mb4: รองรับภาษาไทย ภาษาอังกฤษ ลายมือชื่อดิจิทัล (Base64/BLOB) และอิโมจิทางการแพทย์
- Optimized Indexing: สร้าง Index บนคอลัมน์ที่สืบค้นบ่อย (เช่น
national_id, hn, status, created_at, branch_id) เพื่อลดเวลา Execution Time ให้ต่ำกว่า 10ms
- Automated AI Allocation & Audit Logging: ฝัง Logic การคำนวณคิวด้วย Stored Procedure (
sp_assign_smart_queue) และมี Triggers เพื่ออัปเดตสถานะห้องและซิงค์ HIS อัตโนมัติ
2. Entity-Relationship Diagram (ERD Level 3)
แผนภาพความสัมพันธ์ระหว่างเอนทิตีทั้ง 13 ตารางหลักในระบบ TTMQMS
3. Comprehensive Data Dictionary (พจนานุกรมข้อมูล 13 ตาราง)
3.1 ตาราง branches (สาขาของศูนย์การแพทย์)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสอ้างอิงสาขาหลัก |
| name_th |
VARCHAR(150) |
NOT NULL |
ชื่อสาขาภาษาไทย (เช่น สาขาทองหล่อ) |
| name_en |
VARCHAR(150) |
NULL |
ชื่อสาขาภาษาอังกฤษ |
| address |
TEXT |
NULL |
ที่อยู่ตั้งสาขา |
| phone |
VARCHAR(50) |
NULL |
เบอร์โทรศัพท์ติดต่อ |
| is_active |
TINYINT(1) |
DEFAULT 1 |
สถานะเปิดใช้งาน (1=Active, 0=Inactive) |
3.2 ตาราง users (ผู้ใช้งานระบบ / เจ้าหน้าที่)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสอ้างอิงผู้ใช้งานระบบ |
| branch_id |
BIGINT UNSIGNED |
FK -> branches(id) |
สังกัดสาขา |
| national_id |
VARCHAR(13) |
UNIQUE, NOT NULL |
เลขประจำตัวประชาชน 13 หลัก (Username) |
| password_hash |
VARCHAR(255) |
NOT NULL |
รหัสผ่านที่เข้ารหัสด้วย Argon2id |
| full_name |
VARCHAR(150) |
NOT NULL |
ชื่อและนามสกุลเจ้าหน้าที่ |
| role |
ENUM(...) |
NOT NULL |
บทบาท: Admin, Reception, Therapist, Cashier |
| totp_secret |
VARCHAR(64) |
NULL |
รหัสลับสำหรับตรวจสอบ 2FA Google Authenticator |
| is_2fa_enabled |
TINYINT(1) |
DEFAULT 1 |
สถานะบังคับใช้ 2FA (1=Enabled) |
3.3 ตาราง patients (ผู้ป่วยและผู้รับบริการ)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสอ้างอิงผู้ป่วยในระบบ |
| branch_id |
BIGINT UNSIGNED |
FK -> branches(id) |
สาขาที่ลงทะเบียนครั้งแรก |
| hn |
VARCHAR(50) |
UNIQUE, NOT NULL |
Hospital Number (เชื่อมโยงระบบ HIS) |
| national_id |
VARCHAR(13) |
UNIQUE, NOT NULL |
เลขประจำตัวประชาชน 13 หลัก (จาก Smart Card) |
| first_name_th |
VARCHAR(100) |
NOT NULL |
ชื่อจริงภาษาไทย |
| last_name_th |
VARCHAR(100) |
NOT NULL |
นามสกุลภาษาไทย |
| gender |
ENUM('Male','Female','Other') |
NOT NULL |
เพศสภาพ |
| birth_date |
DATE |
NULL |
วันเดือนปีเกิด (คำนวณอายุอัตโนมัติ) |
| phone |
VARCHAR(20) |
NULL |
เบอร์โทรศัพท์เคลื่อนที่ |
| right_type |
VARCHAR(100) |
DEFAULT 'UC' |
สิทธิการรักษา (บัตรทอง, ข้าราชการ, ประกันสังคม, จ่ายเอง) |
| contraindications |
TEXT |
NULL |
โรคประจำตัว / ข้อห้ามในการนวด (เช่น ความดันสูง, ตั้งครรภ์) |
3.4 ตาราง therapists (หมอนวดและแพทย์แผนไทย)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสอ้างอิงหมอนวด |
| user_id |
BIGINT UNSIGNED |
FK -> users(id), UNIQUE |
รหัสบัญชีผู้เข้าใช้งานระบบ |
| branch_id |
BIGINT UNSIGNED |
FK -> branches(id) |
ประจำสาขา |
| license_no |
VARCHAR(50) |
UNIQUE, NULL |
เลขที่ใบประกอบวิชาชีพเวชกรรมไทย |
| specialty |
VARCHAR(150) |
NULL |
ความเชี่ยวชาญพิเศษ (เช่น นวดราชสำนัก, แก้อาการ) |
| status |
ENUM(...) |
DEFAULT 'Available' |
สถานะปัจจุบัน: Available, Busy, Off_Duty |
| max_daily_minutes |
INT UNSIGNED |
DEFAULT 480 |
ชั่งโมงทำงานสูงสุดต่อวัน (นาที) เพื่อกันเหนื่อยล้า |
3.5 ตาราง services (บริการนวดและคอร์สการรักษา)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสบริการ |
| code |
VARCHAR(50) |
UNIQUE, NOT NULL |
รหัสรหัสหัตถการ (ICD-10 TM Code Mapping) |
| name_th |
VARCHAR(150) |
NOT NULL |
ชื่อบริการ (เช่น นวดแผนไทยราชสำนัก) |
| duration_mins |
INT UNSIGNED |
NOT NULL |
ระยะเวลาให้บริการมาตรฐาน (นาที) |
| price |
DECIMAL(10,2) |
NOT NULL |
อัตราค่าบริการ (บาท) |
| required_room_type |
VARCHAR(50) |
DEFAULT 'Standard' |
ประเภทห้องที่ต้องการ: Standard, VIP Private, Foot Spa |
3.6 ตาราง rooms (ห้องนวดและเตียงบริการ)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสห้องนวด |
| branch_id |
BIGINT UNSIGNED |
FK -> branches(id) |
สาขาที่ตั้ง |
| room_no |
VARCHAR(50) |
NOT NULL |
หมายเลขห้อง / เตียง (เช่น R-101, Bed-05) |
| name_th |
VARCHAR(100) |
NOT NULL |
ชื่อเรียกห้องนวด |
| room_type |
VARCHAR(50) |
NOT NULL |
ประเภทห้อง: Standard Bed, VIP Private, Foot Spa, Aroma |
| status |
ENUM(...) |
DEFAULT 'Available' |
สถานะ: Available, In_Use, Cleaning, Maintenance |
| current_therapist_id |
BIGINT UNSIGNED |
FK -> therapists(id), NULL |
หมอนวดที่กำลังปฏิบัติงานในห้องนี้ |
3.7 ตาราง queues (การจัดสรรคิวบริการ)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสอ้างอิงรายการคิว |
| branch_id |
BIGINT UNSIGNED |
FK -> branches(id) |
สาขาที่ออกคิว |
| queue_no |
VARCHAR(20) |
NOT NULL |
หมายเลขบัตรคิว (เช่น A001, V001, E001) |
| patient_id |
BIGINT UNSIGNED |
FK -> patients(id) |
ผู้รับบริการ |
| service_id |
BIGINT UNSIGNED |
FK -> services(id) |
บริการที่เลือก |
| assigned_therapist_id |
BIGINT UNSIGNED |
FK -> therapists(id), NULL |
หมอนวดที่ถูกจัดสรรโดย AI |
| assigned_room_id |
BIGINT UNSIGNED |
FK -> rooms(id), NULL |
ห้องนวดที่ถูกจัดสรร |
| priority |
ENUM(...) |
DEFAULT 'Normal' |
ระดับความสำคัญ: Normal, VIP, Emergency |
| status |
ENUM(...) |
DEFAULT 'Waiting' |
สถานะ: Waiting, Assigned, In_Progress, Completed, Cancelled |
| est_start_time |
DATETIME |
NULL |
เวลาเริ่มรับบริการโดยประมาณ (คำนวณโดย AI) |
| actual_start_time |
DATETIME |
NULL |
เวลาเริ่มเข้าห้องนวดจริง |
| completed_time |
DATETIME |
NULL |
เวลาสิ้นสุดการนวด |
3.8 ตาราง queue_allocations (ประวัติการคำนวณด้วย Smart Queue AI)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสบันทึกการจัดสรร |
| queue_id |
BIGINT UNSIGNED |
FK -> queues(id) |
อ้างอิงรายการคิว |
| therapist_id |
BIGINT UNSIGNED |
FK -> therapists(id) |
หมอนวดที่ถูกพิจารณา |
| room_id |
BIGINT UNSIGNED |
FK -> rooms(id) |
ห้องพักที่จับคู่ |
| workload_score |
DECIMAL(8,2) |
NOT NULL |
คะแนนความเหนื่อยล้าสะสมของหมอนวด (ยิ่งต่ำยิ่งได้สิทธิ์ก่อน) |
| allocation_reason |
VARCHAR(255) |
NOT NULL |
คำอธิบายจาก AI (เช่น "จัดสรรให้หมอสมศรีเนื่องจากชั่วโมงว่างสูงสุด") |
| created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP |
เวลาที่ AI คำนวณเสร็จสิ้น |
3.9 ตาราง soap_notes (เวชระเบียนและการตรวจประเมินทางคลินิก)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสบันทึก SOAP Note |
| queue_id |
BIGINT UNSIGNED |
FK -> queues(id), UNIQUE |
อ้างอิงการรับบริการในครั้งนั้น |
| patient_id |
BIGINT UNSIGNED |
FK -> patients(id) |
อ้างอิงผู้ป่วย |
| therapist_id |
BIGINT UNSIGNED |
FK -> therapists(id) |
แพทย์แผนไทย/หมอนวดผู้ประเมิน |
| subjective |
TEXT |
NOT NULL |
S: อาการนำและประวัติการเจ็บป่วย (Chief Complaint) |
| objective_vas_pre |
INT UNSIGNED |
NOT NULL |
O: ระดับความปวดก่อนรักษา VAS Score (0-10) |
| objective_vas_post |
INT UNSIGNED |
NOT NULL |
O: ระดับความปวดหลังรักษา VAS Score (0-10) |
| objective_rom |
JSON |
NULL |
O: องศาการเคลื่อนไหว (Flexion, Extension Goniometer) |
| assessment |
TEXT |
NOT NULL |
A: การวินิจฉัยโรคตามคัมภีร์แพทย์แผนไทยและ ICD-10 TM |
| plan_treatment |
TEXT |
NOT NULL |
P: หัตถการที่ให้และการพยาบาล (เช่น นวดราชสำนัก, ประคบ) |
| signature_base64 |
LONGTEXT |
NOT NULL |
ลายมือชื่อหมอนวดผู้ให้การรักษา (Base64 PNG Format) |
| his_sync_status |
ENUM(...) |
DEFAULT 'Pending' |
สถานะซิงค์ HIS: Pending, Synced, Failed |
3.10 ตาราง billings (การคิดเงิน ออกใบเสร็จ และ PromptPay QR)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสบิล / ใบเสร็จรับเงิน |
| queue_id |
BIGINT UNSIGNED |
FK -> queues(id), UNIQUE |
อ้างอิงคิวการให้บริการ |
| patient_id |
BIGINT UNSIGNED |
FK -> patients(id) |
อ้างอิงผู้ชำระเงิน |
| receipt_no |
VARCHAR(50) |
UNIQUE, NOT NULL |
เลขที่ใบเสร็จรับเงิน (เช่น INV-20260727-0001) |
| subtotal |
DECIMAL(10,2) |
NOT NULL |
ยอดรวมค่าบริการก่อนลด (บาท) |
| discount |
DECIMAL(10,2) |
DEFAULT 0.00 |
ยอดส่วนลด |
| vat_amount |
DECIMAL(10,2) |
NOT NULL |
ภาษีมูลค่าเพิ่ม (VAT 7%) |
| grand_total |
DECIMAL(10,2) |
NOT NULL |
ยอดชำระสุทธิ (บาท) |
| payment_method |
ENUM(...) |
NOT NULL |
วิธีชำระเงิน: Cash, PromptPay, Credit, Insurance |
| promptpay_qr_payload |
TEXT |
NULL |
ข้อความ EMVCo QR Code Payload สำหรับสแกนจ่าย |
| status |
ENUM(...) |
DEFAULT 'Paid' |
สถานะใบเสร็จ: Paid, Refunded, Cancelled |
3.11 ตาราง audit_logs (บันทึกร่องรอยตรวจสอบความปลอดภัย OWASP)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัส Log |
| user_id |
BIGINT UNSIGNED |
FK -> users(id), NULL |
เจ้าหน้าที่ผู้กระทำรายการ (NULL หากเป็นระบบอัตโนมัติ) |
| action |
VARCHAR(100) |
NOT NULL |
ชื่อเหตุการณ์ (เช่น LOGIN_SUCCESS, WALK_IN_CREATE, SOAP_SIGN) |
| entity_type |
VARCHAR(50) |
NOT NULL |
ชื่อตาราง/อ็อบเจกต์ที่เกี่ยวข้อง (เช่น Patient, Queue, Billing) |
| entity_id |
BIGINT UNSIGNED |
NULL |
รหัส PK ของอ็อบเจกต์นั้นๆ |
| ip_address |
VARCHAR(45) |
NOT NULL |
IP Address ของ Client (รองรับ IPv4 และ IPv6) |
| user_agent |
TEXT |
NULL |
ข้อมูลเบราว์เซอร์และอุปกรณ์ PWA |
| details |
JSON |
NULL |
ข้อมูลการเปลี่ยนแปลง (Before/After State JSON) |
| created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP |
วันเวลาที่เกิดเหตุการณ์ (UTC+7) |
3.12 ตาราง sys_config (การตั้งค่าพารามิเตอร์ระบบและ AI SLA)
| Column Name |
Data Type |
Constraints |
Description |
| key_name |
VARCHAR(100) |
PK |
ชื่อตัวแปรตั้งค่า (เช่น sla_target_wait_mins, jwt_ttl_minutes) |
| value_str |
TEXT |
NOT NULL |
ค่าพารามิเตอร์ที่กำหนด |
| description |
VARCHAR(255) |
NULL |
คำอธิบายการตั้งค่า |
| updated_at |
TIMESTAMP |
ON UPDATE CURRENT_TIMESTAMP |
วันเวลาที่แก้ไขล่าสุด |
3.13 ตาราง api_tokens (การจัดการ Access Token และ Revocation List)
| Column Name |
Data Type |
Constraints |
Description |
| id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT |
รหัสโทเค็น |
| user_id |
BIGINT UNSIGNED |
FK -> users(id) |
อ้างอิงเจ้าของโทเค็น |
| token_hash |
VARCHAR(64) |
UNIQUE, NOT NULL |
ค่า SHA-256 Hash ของ JWT Access/Refresh Token |
| expires_at |
DATETIME |
NOT NULL |
วันเวลาหมดอายุของโทเค็น |
| is_revoked |
TINYINT(1) |
DEFAULT 0 |
สถานะยกเลิกโทเค็น (0=Valid, 1=Revoked / Logged out) |
4. Database Views & Stored Procedures Architecture
ระบบมีการสร้าง Objects บนฐานข้อมูลเพื่อรองรับการประมวลผลข้อมูลขั้นสูง:
- View
v_daily_executive_kpi: วิเคราะห์สถิติคิวบริการแบบ Realtime, คำนวณเวลารอคอยเฉลี่ย (Average Wait Time in Mins), อัตราการใช้เตียง/ห้องนวด (Occupancy Rate %) และสรุปยอดรายรับรวมประจำวันของแต่ละสาขา
- View
v_therapist_workload_balance: สรุปชั่วโมงปฏิบัติงานสะสมประจำวันของหมอนวดแต่ละคน เปรียบเทียบกับโควตา 480 นาที เพื่อให้ผู้บริหารและระบบ AI ตรวจสอบความสมดุลของภาระงานได้อย่างโปร่งใส
- Stored Procedure
sp_assign_smart_queue(in_patient_id, in_service_id, in_priority, in_branch_id): หัวใจสำคัญของ Smart Queue Engine ที่ทำหน้าที่ล็อกตาราง (Row-level Locking) เพื่อค้นหาหมอนวดที่มีชั่วโมงทำงานสะสมน้อยที่สุดและจับคู่เข้ากับห้องพักที่ว่างพร้อมใช้ภายในเสี้ยววินาที
เอกสารนี้ได้รับการตรวจสอบความสอดคล้องตามโครงสร้าง schema.sql และ Database Design Spec