-- Momentry 監控系統數據庫表 -- 使用方式: psql -U accusys -h localhost -d momentry -f schema.sql -- ============================================================ -- Layer 2: Service 監控 -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_services ( id SERIAL PRIMARY KEY, service_name VARCHAR(50) NOT NULL, service_type VARCHAR(20), port INTEGER, status VARCHAR(20) CHECK (status IN ('up', 'down', 'degraded', 'unknown')), response_time_ms INTEGER, error_message TEXT, checked_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_monitor_services_name ON monitor_services(service_name); CREATE INDEX idx_monitor_services_time ON monitor_services(checked_at); -- ============================================================ -- Layer 3: n8n Workflow 監控 -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_workflows ( id SERIAL PRIMARY KEY, workflow_id VARCHAR(50) NOT NULL, workflow_name VARCHAR(255), workflow_type VARCHAR(50), is_active BOOLEAN DEFAULT FALSE, last_executed_at TIMESTAMP, execution_count INTEGER DEFAULT 0, success_count INTEGER DEFAULT 0, failure_count INTEGER DEFAULT 0, avg_duration_ms INTEGER, has_schedule BOOLEAN DEFAULT FALSE, has_webhook BOOLEAN DEFAULT FALSE, idle_days INTEGER, suggestion VARCHAR(100), checked_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_monitor_workflows_id ON monitor_workflows(workflow_id); CREATE INDEX idx_monitor_workflows_active ON monitor_workflows(is_active); CREATE INDEX idx_monitor_workflows_idle ON monitor_workflows(idle_days); -- ============================================================ -- Layer 4: WordPress Portal 監控 -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_portal_pages ( id SERIAL PRIMARY KEY, page_url VARCHAR(500) NOT NULL, page_type VARCHAR(20), is_accessible BOOLEAN, response_time_ms INTEGER, http_status INTEGER, error_message TEXT, checked_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS monitor_portal_users ( id SERIAL PRIMARY KEY, user_id BIGINT, username VARCHAR(100), email VARCHAR(255), role VARCHAR(50), is_active BOOLEAN, last_login TIMESTAMP, created_at TIMESTAMP, detected_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_monitor_portal_pages_url ON monitor_portal_pages(page_url); CREATE INDEX idx_monitor_portal_users_username ON monitor_portal_users(username); -- ============================================================ -- Layer 5: Database 監控 -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_databases ( id SERIAL PRIMARY KEY, db_type VARCHAR(20) NOT NULL CHECK (db_type IN ('postgresql', 'redis', 'qdrant', 'mariadb', 'mongodb')), db_name VARCHAR(50), metric_name VARCHAR(50) NOT NULL, metric_value JSONB, checked_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_monitor_databases_type ON monitor_databases(db_type); CREATE INDEX idx_monitor_databases_time ON monitor_databases(checked_at); -- PostgreSQL 表結構快照 CREATE TABLE IF NOT EXISTS monitor_pg_tables ( id SERIAL PRIMARY KEY, database_name VARCHAR(50), schema_name VARCHAR(50), table_name VARCHAR(100), table_type VARCHAR(20), row_count BIGINT, table_size_bytes BIGINT, index_size_bytes BIGINT, snapshot_at TIMESTAMP DEFAULT NOW() ); -- 表結構變更記錄 CREATE TABLE IF NOT EXISTS monitor_pg_schema_changes ( id SERIAL PRIMARY KEY, database_name VARCHAR(50), schema_name VARCHAR(50), table_name VARCHAR(100), change_type VARCHAR(20) CHECK (change_type IN ('table_created', 'table_dropped', 'column_added', 'column_removed', 'column_type_changed')), column_name VARCHAR(100), old_value TEXT, new_value TEXT, detected_at TIMESTAMP DEFAULT NOW() ); -- Qdrant Collection 監控 CREATE TABLE IF NOT EXISTS monitor_qdrant_collections ( id SERIAL PRIMARY KEY, collection_name VARCHAR(100), vectors_count BIGINT, points_count BIGINT, disk_size_bytes BIGINT, status VARCHAR(20), snapshot_at TIMESTAMP DEFAULT NOW() ); -- ============================================================ -- Layer 6: 使用者監控 -- ============================================================ -- 連線會話追蹤 CREATE TABLE IF NOT EXISTS monitor_sessions ( id SERIAL PRIMARY KEY, session_type VARCHAR(20) CHECK (session_type IN ('ssh', 'web', 'db', 'sftp', 'rdp')), service_name VARCHAR(50), username VARCHAR(100), source_ip VARCHAR(45), source_port INTEGER, connected_at TIMESTAMP, last_activity_at TIMESTAMP, disconnected_at TIMESTAMP, bytes_sent BIGINT, bytes_received BIGINT, status VARCHAR(20) CHECK (status IN ('active', 'disconnected', 'timeout')) ); -- 登入歷史 CREATE TABLE IF NOT EXISTS monitor_logins ( id SERIAL PRIMARY KEY, user_type VARCHAR(20) CHECK (user_type IN ('system', 'wordpress', 'n8n', 'gitea', 'sftpgo', 'database')), username VARCHAR(100), source_ip VARCHAR(45), user_agent TEXT, login_method VARCHAR(20), success BOOLEAN, failure_reason VARCHAR(200), login_at TIMESTAMP DEFAULT NOW() ); -- sudo 命令記錄 CREATE TABLE IF NOT EXISTS monitor_sudo_history ( id SERIAL PRIMARY KEY, username VARCHAR(100), command TEXT, run_as VARCHAR(100), tty VARCHAR(50), source_ip VARCHAR(45), exit_code INTEGER, executed_at TIMESTAMP DEFAULT NOW() ); -- 資源使用追蹤 CREATE TABLE IF NOT EXISTS monitor_resource_usage ( id SERIAL PRIMARY KEY, user_type VARCHAR(20), username VARCHAR(100), service_name VARCHAR(50), cpu_percent DECIMAL(5,2), memory_mb INTEGER, disk_io_read_mb BIGINT, disk_io_write_mb BIGINT, network_rx_mb BIGINT, network_tx_mb BIGINT, recorded_at TIMESTAMP DEFAULT NOW() ); -- 異常檢測記錄 CREATE TABLE IF NOT EXISTS monitor_anomalies ( id SERIAL PRIMARY KEY, anomaly_type VARCHAR(50) CHECK (anomaly_type IN ('brute_force', 'privilege_escalation', 'unusual_access', 'unusual_time', 'excessive_queries', 'idle_session', 'schema_change')), severity VARCHAR(20) CHECK (severity IN ('low', 'medium', 'high', 'critical')), source_type VARCHAR(20), username VARCHAR(100), source_ip VARCHAR(45), description TEXT, details JSONB, detected_at TIMESTAMP DEFAULT NOW(), resolved BOOLEAN DEFAULT FALSE, resolved_at TIMESTAMP ); CREATE INDEX idx_monitor_sessions_type ON monitor_sessions(session_type); CREATE INDEX idx_monitor_sessions_username ON monitor_sessions(username); CREATE INDEX idx_monitor_logins_type ON monitor_logins(user_type); CREATE INDEX idx_monitor_logins_time ON monitor_logins(login_at); CREATE INDEX idx_monitor_anomalies_type ON monitor_anomalies(anomaly_type); CREATE INDEX idx_monitor_anomalies_severity ON monitor_anomalies(severity); CREATE INDEX idx_monitor_anomalies_time ON monitor_anomalies(detected_at); -- ============================================================ -- Layer 7: Storage 監控 -- ============================================================ -- 檔案註冊表 CREATE TABLE IF NOT EXISTS file_registry ( file_uuid UUID PRIMARY KEY DEFAULT gen_random_uuid(), file_name VARCHAR(255) NOT NULL, file_path TEXT NOT NULL, file_path_hash VARCHAR(64) NOT NULL, file_size BIGINT NOT NULL, file_hash VARCHAR(64), mime_type VARCHAR(100), user_cluster VARCHAR(50) CHECK (user_cluster IN ('family', 'work', 'wordpress', 'shared', 'system')), owner_id VARCHAR(100), storage_tier VARCHAR(20) DEFAULT 'hot' CHECK (storage_tier IN ('hot', 'warm', 'cold')), storage_location VARCHAR(500), status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'temporary', 'archived', 'deleted')), is_registered BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), last_accessed_at TIMESTAMP, access_count INTEGER DEFAULT 0, archived_at TIMESTAMP, archive_location VARCHAR(500), retention_until TIMESTAMP, UNIQUE(file_path_hash) ); -- 存儲使用統計 CREATE TABLE IF NOT EXISTS storage_usage_stats ( id SERIAL PRIMARY KEY, user_cluster VARCHAR(50), storage_tier VARCHAR(20), file_count BIGINT, total_size_bytes BIGINT, record_time TIMESTAMP DEFAULT NOW() ); -- 文件訪問日誌 CREATE TABLE IF NOT EXISTS storage_access_logs ( id SERIAL PRIMARY KEY, user_cluster VARCHAR(50), owner_id VARCHAR(100), file_path TEXT, access_type VARCHAR(20) CHECK (access_type IN ('read', 'write', 'delete', 'download', 'move')), access_time TIMESTAMP DEFAULT NOW(), client_ip VARCHAR(45), access_method VARCHAR(20) ); -- 文件生命週期 CREATE TABLE IF NOT EXISTS file_lifecycle ( id SERIAL PRIMARY KEY, file_uuid UUID REFERENCES file_registry(file_uuid), file_path TEXT, user_cluster VARCHAR(50), storage_tier VARCHAR(20), created_at TIMESTAMP, last_accessed_at TIMESTAMP, last_modified_at TIMESTAMP, access_count INTEGER DEFAULT 0, current_status VARCHAR(20) DEFAULT 'active', tier_migration_count INTEGER DEFAULT 0, migrated_at TIMESTAMP ); CREATE INDEX idx_file_registry_cluster ON file_registry(user_cluster); CREATE INDEX idx_file_registry_tier ON file_registry(storage_tier); CREATE INDEX idx_file_registry_status ON file_registry(status); CREATE INDEX idx_storage_usage_cluster ON storage_usage_stats(user_cluster); CREATE INDEX idx_storage_usage_time ON storage_usage_stats(record_time); -- ============================================================ -- 外部監控 (Layer 1) -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_external ( id SERIAL PRIMARY KEY, target_name VARCHAR(50) NOT NULL, target_type VARCHAR(20) CHECK (target_type IN ('ddns', 'gateway', 'internet', 'api')), target_host VARCHAR(255), is_reachable BOOLEAN, response_time_ms INTEGER, dns_resolved_ip VARCHAR(45), error_message TEXT, checked_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_monitor_external_name ON monitor_external(target_name); CREATE INDEX idx_monitor_external_time ON monitor_external(checked_at); -- ============================================================ -- 監控配置表 -- ============================================================ CREATE TABLE IF NOT EXISTS monitor_config ( id SERIAL PRIMARY KEY, config_key VARCHAR(50) UNIQUE NOT NULL, config_value TEXT, description VARCHAR(255), updated_at TIMESTAMP DEFAULT NOW() ); -- 插入默認配置 INSERT INTO monitor_config (config_key, config_value, description) VALUES ('check_interval', '300', '監控檢查間隔(秒)'), ('retention_days', '30', '歷史數據保留天數'), ('idle_threshold_days', '30', 'Workflow 閒置天數閾值'), ('alert_threshold_bruteforce', '5', '暴力破解嘗試次數閾值'), ('alert_threshold_slow_response', '3000', '響應時間閾值(毫秒)') ON CONFLICT (config_key) DO NOTHING; -- ============================================================ -- 視圖定義 -- ============================================================ -- 服務健康狀態視圖 CREATE OR REPLACE VIEW v_service_health AS SELECT service_name, status, COUNT(*) as check_count, COUNT(*) FILTER (WHERE status = 'up') as up_count, COUNT(*) FILTER (WHERE status = 'down') as down_count, AVG(response_time_ms) as avg_response_time, MAX(checked_at) as last_check FROM monitor_services WHERE checked_at > NOW() - INTERVAL '24 hours' GROUP BY service_name, status; -- 最近異常視圖 CREATE OR REPLACE VIEW v_recent_anomalies AS SELECT anomaly_type, severity, username, source_ip, description, detected_at FROM monitor_anomalies WHERE detected_at > NOW() - INTERVAL '24 hours' ORDER BY detected_at DESC; -- 閒置 Workflow 視圖 CREATE OR REPLACE VIEW v_idle_workflows AS SELECT workflow_name, idle_days, suggestion, last_executed_at FROM monitor_workflows WHERE idle_days > 30 AND is_active = TRUE ORDER BY idle_days DESC; -- 存儲使用概況視圖 CREATE OR REPLACE VIEW v_storage_overview AS SELECT user_cluster, storage_tier, COUNT(*) as file_count, SUM(file_size) as total_size FROM file_registry WHERE status = 'active' GROUP BY user_cluster, storage_tier; -- ============================================================ -- 備份監控 (Layer 7 Extension) -- ============================================================ -- 備份註冊表 CREATE TABLE IF NOT EXISTS backup_registry ( id SERIAL PRIMARY KEY, service_name VARCHAR(50) NOT NULL, backup_file VARCHAR(500) NOT NULL, backup_size_bytes BIGINT, backup_type VARCHAR(20) CHECK (backup_type IN ('daily', 'weekly', 'monthly', 'archive', 'full', 'incremental')), backup_method VARCHAR(20) CHECK (backup_method IN ('pg_dump', 'mysqldump', 'tar', 'snapshot', 'dump')), status VARCHAR(20) CHECK (status IN ('pending', 'running', 'completed', 'failed', 'verified')), compression_ratio DECIMAL(5,2), verification_result BOOLEAN, error_message TEXT, started_at TIMESTAMP DEFAULT NOW(), completed_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); -- 備份存儲統計 CREATE TABLE IF NOT EXISTS backup_storage_stats ( id SERIAL PRIMARY KEY, tier VARCHAR(20) CHECK (tier IN ('daily', 'weekly', 'monthly', 'archive', 'total')), file_count BIGINT, total_size_bytes BIGINT, record_time TIMESTAMP DEFAULT NOW() ); -- 備份歷史 CREATE TABLE IF NOT EXISTS backup_history ( id SERIAL PRIMARY KEY, service_name VARCHAR(50) NOT NULL, operation VARCHAR(20) CHECK (operation IN ('backup', 'restore', 'tier_migration', 'cleanup', 'verify')), backup_file VARCHAR(500), backup_tier VARCHAR(20), source_tier VARCHAR(20), dest_tier VARCHAR(20), file_count BIGINT, size_bytes BIGINT, duration_seconds INTEGER, status VARCHAR(20) CHECK (status IN ('success', 'failed', 'partial')), error_message TEXT, executed_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_backup_registry_service ON backup_registry(service_name); CREATE INDEX idx_backup_registry_time ON backup_registry(created_at); CREATE INDEX idx_backup_storage_stats_tier ON backup_storage_stats(tier); CREATE INDEX idx_backup_storage_stats_time ON backup_storage_stats(record_time); CREATE INDEX idx_backup_history_service ON backup_history(service_name); CREATE INDEX idx_backup_history_time ON backup_history(executed_at); -- ============================================================ -- Node.js 版本基線監控 -- ============================================================ CREATE TABLE IF NOT EXISTS node_version_baseline ( id SERIAL PRIMARY KEY, runtime_name VARCHAR(50) NOT NULL, required_version VARCHAR(20) NOT NULL, current_version VARCHAR(20), process_name VARCHAR(100), process_path TEXT, is_compliant BOOLEAN, locked_path VARCHAR(500), checked_at TIMESTAMP DEFAULT NOW() ); -- Node.js 進程追蹤 CREATE TABLE IF NOT EXISTS node_process_tracking ( id SERIAL PRIMARY KEY, process_name VARCHAR(100) NOT NULL, pid INTEGER, command VARCHAR(500), node_version VARCHAR(20), is_managed BOOLEAN DEFAULT FALSE, started_at TIMESTAMP, checked_at TIMESTAMP DEFAULT NOW() ); -- ============================================================ -- Python 版本基線監控 -- ============================================================ CREATE TABLE IF NOT EXISTS python_version_baseline ( id SERIAL PRIMARY KEY, runtime_name VARCHAR(50) NOT NULL, required_version VARCHAR(20) NOT NULL, current_version VARCHAR(20), interpreter_path VARCHAR(500), is_compliant BOOLEAN, checked_at TIMESTAMP DEFAULT NOW() ); -- Python 腳本追蹤 CREATE TABLE IF NOT EXISTS python_script_tracking ( id SERIAL PRIMARY KEY, script_path TEXT NOT NULL, shebang_version VARCHAR(20), actual_version VARCHAR(20), is_compliant BOOLEAN DEFAULT FALSE, last_run_at TIMESTAMP, exit_code INTEGER, error_output TEXT, checked_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_node_version_name ON node_version_baseline(runtime_name); CREATE INDEX idx_node_process_name ON node_process_tracking(process_name); CREATE INDEX idx_python_version_name ON python_version_baseline(runtime_name); CREATE INDEX idx_python_script_path ON python_script_tracking(script_path);