Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,50 @@
<?php
/**
* Thai Traditional Massage Queue Management System (TTMQMS)
* Enterprise Production Application Configuration
*
* @package App\Config
* @version 2.0.0 (Enterprise Ready)
*/
return [
'name' => 'Thai Traditional Massage Queue Management System (TTMQMS)',
'short_name' => 'TTMQMS Enterprise',
'env' => getenv('APP_ENV') ?: 'production',
'debug' => getenv('APP_DEBUG') === 'true' ?: false,
'url' => getenv('APP_URL') ?: 'https://ttmqms.hospital.local',
'timezone' => 'Asia/Bangkok',
'locale' => 'th',
'fallback_locale' => 'en',
// Multi-Branch & Multi-Clinic Configuration
'default_branch_id' => getenv('DEFAULT_BRANCH_ID') ?: 1,
'multi_branch_enabled' => true,
// Clinical & Massage Settings
'clinical' => [
'default_service_duration' => 60, // นาที
'max_daily_therapist_minutes' => 480, // 8 ชั่วโมงงานสูงสุดต่อวันตามมาตรฐานอาชีวอนามัย
'require_soap_note' => true,
'require_digital_signature' => true,
'require_vas_pain_score' => true,
'require_rom_assessment' => true,
],
// Smart Queue AI & Workload Balancer
'smart_queue' => [
'enable_ai_estimator' => true,
'workload_balance_strategy' => 'lowest_score_first', // lowest_score_first | round_robin | specialization_match
'buffer_between_queues_mins' => 15, // เวลาทำความสะอาดและเตรียมเตียง
'emergency_priority_multiplier' => 3.0,
'vip_priority_multiplier' => 1.5,
],
// TV Queue Display & TTS Audio
'tv_display' => [
'refresh_interval_ms' => 5000, // 5 วินาที
'voice_announcement' => true,
'voice_language' => 'TH_EN', // TH, EN, TH_EN
'speech_rate' => 0.9,
],
];
@@ -0,0 +1,77 @@
<?php
/**
* TTMQMS Enterprise - Standard Database Connection File
* ไฟล์เชื่อมต่อฐานข้อมูลปกติ (จัดเก็บในโฟลเดอร์ config/)
*
* ท่านสามารถตั้งค่า Host, Username, Password และชื่อฐานข้อมูล (Database Name)
* ของ XAMPP / MAMP / MySQL Server ได้โดยตรงที่ไฟล์นี้
*/
$db_host = '127.0.0.1'; // หรือ 'localhost'
$db_port = '3306'; // พอร์ต MySQL ของ XAMPP (ค่าเริ่มต้นคือ 3306)
$db_name = 'ttm_system'; // ชื่อฐานข้อมูล (ตามที่ Import จากไฟล์ database/schema.sql)
$db_user = 'root'; // ชื่อผู้ใช้ MySQL (ค่าเริ่มต้นของ XAMPP คือ root)
$db_pass = '@Samui@1074200'; // รหัสผ่าน MySQL (ค่าเริ่มต้นของ XAMPP คือว่างเปล่า "")
try {
$dsn = "mysql:host={$db_host};port={$db_port};dbname={$db_name};charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // ป้องกัน SQL Injection 100%
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
];
$conn = new PDO($dsn, $db_user, $db_pass, $options);
// ตั้งค่า Timezone ของ MySQL ให้ตรงกับเวลาประเทศไทย (+07:00)
$conn->exec("SET time_zone = '+07:00';");
return $conn;
} catch (PDOException $e) {
error_log("Database Connection Error: " . $e->getMessage());
$isApi = (strpos($_SERVER['REQUEST_URI'] ?? '', '/api/') !== false) ||
(strpos($_SERVER['REQUEST_URI'] ?? '', 'api=') !== false) ||
(strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false) ||
isset($_GET['api']) || isset($_GET['endpoint']);
if ($isApi) {
if (!headers_sent()) {
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
}
echo json_encode([
'success' => false,
'status_code' => 500,
'error' => [
'message' => 'ไม่สามารถเชื่อมต่อฐานข้อมูล MySQL ได้: ' . $e->getMessage(),
'hint' => 'กรุณาเปิดโปรแกรม XAMPP Control Panel กด Start ที่ MySQL หรือตรวจสอบการตั้งค่าใน config/connection.php'
]
], JSON_UNESCAPED_UNICODE);
exit();
}
// แสดงหน้าจอแจ้งเตือนที่สวยงาม ชัดเจน และเข้าใจง่าย แทนที่จะเป็น HTTP 500 หน้าขาว (สำหรับหน้าเว็บปกติ)
if (php_sapi_name() !== 'cli') {
if (!headers_sent()) {
header('Content-Type: text/html; charset=utf-8');
http_response_code(500);
}
echo "<!DOCTYPE html><html lang='th'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>ข้อผิดพลาดในการเชื่อมต่อฐานข้อมูล</title>";
echo "<style>body{font-family:'Segoe UI',Tahoma,sans-serif;background:#0f172a;color:#f8fafc;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;padding:20px;box-sizing:border-box;}.card{background:#1e293b;border:1px solid #ef4444;border-radius:20px;padding:36px;max-width:580px;width:100%;box-shadow:0 15px 30px rgba(0,0,0,0.6);}h2{color:#f87171;margin-top:0;display:flex;align-items:center;gap:12px;font-size:1.5rem;}code{background:#334155;padding:3px 8px;border-radius:6px;color:#38bdf8;font-weight:600;}ol{line-height:1.8;padding-left:20px;margin:20px 0;}li{margin-bottom:8px;}.error-box{background:#020617;padding:16px;border-radius:10px;overflow-x:auto;color:#fca5a5;border:1px solid #334155;font-family:monospace;font-size:0.9rem;margin-top:16px;}</style></head>";
echo "<body><div class='card'><h2>❌ ไม่สามารถเชื่อมต่อฐานข้อมูล MySQL ได้</h2>";
echo "<p>ระบบไม่สามารถเชื่อมต่อกับฐานข้อมูล <code>{$db_name}</code> ที่โฮสต์ <code>{$db_host}:{$db_port}</code> ได้ กรุณาตรวจสอบตามขั้นตอนดังนี้:</p>";
echo "<ol>";
echo "<li>เปิดโปรแกรม <strong>XAMPP Control Panel</strong> และกดปุ่ม <strong>Start</strong> ที่บริการ <strong>MySQL</strong></li>";
echo "<li>เข้าไปที่ phpMyAdmin (<code>http://localhost/phpmyadmin</code>) ตรวจสอบว่าได้สร้างฐานข้อมูลชื่อ <code>{$db_name}</code> และ Import ไฟล์ <code>database/schema.sql</code> แล้วหรือไม่</li>";
echo "<li>หากท่านมีการตั้งรหัสผ่าน MySQL ใน XAMPP กรุณาแก้ไขตัวแปร <code>\$db_pass</code> ในไฟล์ <strong>config/connection.php</strong> ให้ถูกต้อง</li>";
echo "</ol>";
echo "<div class='error-box'><strong>รายละเอียดข้อผิดพลาด:</strong><br>" . htmlspecialchars($e->getMessage()) . "</div>";
echo "</div></body></html>";
exit();
}
throw $e;
}
@@ -0,0 +1,7 @@
<?php
/**
* TTMQMS Enterprise - Database Configuration Bridge
* เชื่อมโยงการเรียกใช้ตั้งค่าฐานข้อมูลไปยังไฟล์ config/connection.php
*/
return require __DIR__ . '/connection.php';
@@ -0,0 +1,76 @@
<?php
/**
* Thai Traditional Massage Queue Management System (TTMQMS)
* Hospital Integration Configuration (HIS, HOSxP, HL7/FHIR, Smart Card, ESC/POS, LINE OA)
*
* @package App\Config
*/
return [
// HIS / HOSxP REST API / Database Integration
'his' => [
'enabled' => getenv('HIS_ENABLED') === 'true' ?: true,
'system_type' => 'HOSxP', // HOSxP | HomC | Meditech | GenericREST
'api_base_url' => getenv('HIS_API_URL') ?: 'https://his.hospital.local/api/v1',
'api_key' => getenv('HIS_API_KEY') ?: 'demo_his_api_secret_token_2026',
'timeout_seconds' => 5,
'auto_sync_on_register' => true,
],
// HL7 / FHIR (Fast Healthcare Interoperability Resources)
'fhir' => [
'enabled' => getenv('FHIR_ENABLED') === 'true' ?: true,
'server_url' => getenv('FHIR_SERVER_URL') ?: 'https://fhir.hospital.local/r4',
'facility_id' => 'THAI_MED_CENTER_01',
'resource_types' => [
'Patient' => 'Patient',
'Encounter' => 'Encounter',
'Observation' => 'Observation', // สำหรับส่งค่า VAS Pain Score และ ROM
'Procedure' => 'Procedure', // สำหรับส่งหัตถการนวดไทย
],
],
// Smart Card Reader (Thai National ID Card via APDU / WebUSB / PC/SC Agent)
'smartcard' => [
'enabled' => true,
'agent_port' => 8443, // Local Agent Port
'auto_fill_form' => true,
'read_photo' => true,
],
// ESC/POS Thermal Printer (80mm / 58mm Receipt & Queue Ticket)
'printer' => [
'enabled' => true,
'driver' => 'network', // network | usb | browser_print
'default_ip' => '192.168.1.200',
'default_port' => 9100,
'paper_width' => '80mm',
'auto_cut' => true,
'print_logo' => true,
],
// Notification Gateways (LINE OA, SMS, Telegram, Email)
'notification' => [
'line_notify' => [
'enabled' => true,
'token' => getenv('LINE_NOTIFY_TOKEN') ?: 'DEMO_LINE_NOTIFY_TOKEN_XXXXX',
],
'line_oa' => [
'enabled' => true,
'channel_access_token' => getenv('LINE_OA_TOKEN') ?: '',
'channel_secret' => getenv('LINE_OA_SECRET') ?: '',
],
'sms' => [
'enabled' => false,
'gateway_url' => 'https://api.sms-gateway.local/send',
'sender_id' => 'TTMQMS',
],
],
// Calendar Integration (Google Calendar / Outlook ICS API)
'calendar' => [
'google_enabled' => true,
'outlook_enabled' => true,
'ics_reminder_mins' => 120, // แจ้งเตือนล่วงหน้า 2 ชั่วโมง
],
];
@@ -0,0 +1,66 @@
<?php
/**
* Thai Traditional Massage Queue Management System (TTMQMS)
* Enterprise Security Configuration (Argon2id, JWT, 2FA TOTP RFC6238, OWASP)
*
* @package App\Config
*/
return [
// Password Hashing Algorithm (Argon2id - OWASP Recommended)
'password_hash' => [
'algo' => PASSWORD_ARGON2ID,
'options' => [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4, // 4 iterations
'threads' => 1, // 1 parallel thread
],
],
// JSON Web Token (JWT) Authentication
'jwt' => [
'secret' => getenv('JWT_SECRET') ?: 'ttmqms_super_secret_enterprise_key_2026_owasp_compliance_256bit',
'algo' => 'HS256',
'access_token_ttl' => 3600, // 60 นาที (1 ชั่วโมง)
'refresh_token_ttl' => 604800, // 7 วัน
'issuer' => 'https://ttmqms.hospital.local',
'audience' => 'ttmqms_pwa_client',
],
// Two-Factor Authentication (Google Authenticator TOTP RFC6238)
'two_factor' => [
'enabled' => true,
'issuer' => 'TTMQMS Enterprise',
'time_step' => 30, // 30 วินาทีตามมาตรฐาน TOTP
'digits' => 6,
'window' => 1, // ยอมรับเวลาก่อนหน้าและหลัง 1 step ป้องกันนาฬิกาคลาดเคลื่อน
'remember_device_days' => 30,
'recovery_code_count' => 8,
],
// Rate Limiting & Brute Force Protection
'rate_limit' => [
'enabled' => true,
'max_requests_per_minute' => 60,
'login_max_attempts' => 5,
'lockout_duration_minutes' => 15,
],
// Security Headers & Content Security Policy (CSP)
'headers' => [
'X-Content-Type-Options' => 'nosniff',
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block',
'Referrer-Policy' => 'strict-origin-when-cross-origin',
'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains; preload',
'Content-Security-Policy' => "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: blob: https:; connect-src 'self' ws: wss: http: https:;",
],
// CORS Policy
'cors' => [
'allowed_origins' => ['*'], // ใน Production ควรระบุ Domain เช่น https://ttmqms.hospital.local
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
'max_age' => 86400,
],
];