CREATE DATABASE IF NOT EXISTS eventcollector
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

USE eventcollector;

CREATE TABLE IF NOT EXISTS agents (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    hostname VARCHAR(255) NOT NULL,
    api_key_hash CHAR(64) NOT NULL,
    first_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    last_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    last_ip VARCHAR(64) NOT NULL DEFAULT '',
    is_enabled TINYINT(1) NOT NULL DEFAULT 1,
    PRIMARY KEY (id),
    UNIQUE KEY ux_agents_hostname (hostname),
    KEY ix_agents_last_seen (last_seen)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS event_logs (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    agent_id BIGINT UNSIGNED NOT NULL,
    hostname VARCHAR(255) NOT NULL,
    channel_name VARCHAR(128) NOT NULL,
    event_id INT UNSIGNED NOT NULL,
    source VARCHAR(255) NOT NULL,
    computer VARCHAR(255) NOT NULL DEFAULT '',
    provider_name VARCHAR(255) NOT NULL DEFAULT '',
    level_value INT UNSIGNED NOT NULL DEFAULT 0,
    task_value INT UNSIGNED NOT NULL DEFAULT 0,
    opcode_value INT UNSIGNED NOT NULL DEFAULT 0,
    keywords VARCHAR(255) NOT NULL DEFAULT '',
    target_user VARCHAR(255) NOT NULL DEFAULT '',
    target_domain VARCHAR(255) NOT NULL DEFAULT '',
    subject_user VARCHAR(255) NOT NULL DEFAULT '',
    subject_domain VARCHAR(255) NOT NULL DEFAULT '',
    workstation VARCHAR(255) NOT NULL DEFAULT '',
    src_ip VARCHAR(64) NOT NULL DEFAULT '',
    src_port VARCHAR(32) NOT NULL DEFAULT '',
    logon_type VARCHAR(32) NOT NULL DEFAULT '',
    process_name VARCHAR(512) NOT NULL DEFAULT '',
    authentication_package VARCHAR(128) NOT NULL DEFAULT '',
    logon_process VARCHAR(128) NOT NULL DEFAULT '',
    status_text VARCHAR(64) NOT NULL DEFAULT '',
    sub_status_text VARCHAR(64) NOT NULL DEFAULT '',
    failure_reason VARCHAR(512) NOT NULL DEFAULT '',
    ts DATETIME(6) NOT NULL,
    received_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    msg LONGTEXT NOT NULL,
    msg_sha256 CHAR(64) NOT NULL,
    PRIMARY KEY (id),
    KEY ix_event_logs_ts (ts),
    KEY ix_event_logs_received_at (received_at),
    KEY ix_event_logs_agent_ts (agent_id, ts),
    KEY ix_event_logs_eventid_ts (event_id, ts),
    KEY ix_event_logs_hostname_ts (hostname, ts),
    KEY ix_event_logs_channel_event_ts (channel_name, event_id, ts),
    KEY ix_event_logs_target_user_ts (target_user, ts),
    KEY ix_event_logs_src_ip_ts (src_ip, ts),
    KEY ix_event_logs_target_user_src_ip_ts (target_user, src_ip, ts),
    KEY ix_event_logs_eventid_srcip_ts (event_id, src_ip, ts),
    KEY ix_event_logs_eventid_targetuser_ts (event_id, target_user, ts),
    KEY ix_event_logs_eventid_logontype_ts (event_id, logon_type, ts),
    CONSTRAINT fk_event_logs_agent
        FOREIGN KEY (agent_id) REFERENCES agents(id)
        ON DELETE RESTRICT
        ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS detections (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    rule_name VARCHAR(128) NOT NULL,
    severity VARCHAR(32) NOT NULL,
    hostname VARCHAR(255) NOT NULL,
    channel_name VARCHAR(128) NOT NULL DEFAULT '',
    event_id INT UNSIGNED NOT NULL DEFAULT 0,
    score DOUBLE NOT NULL DEFAULT 0,
    window_start DATETIME(6) NOT NULL,
    window_end DATETIME(6) NOT NULL,
    summary VARCHAR(512) NOT NULL,
    details_json JSON NOT NULL,
    created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    PRIMARY KEY (id),
    UNIQUE KEY ux_detection_dedupe (rule_name, hostname, channel_name, event_id, window_start, window_end),
    KEY ix_detections_created (created_at),
    KEY ix_detections_rule_host_time (rule_name, hostname, created_at),
    KEY ix_detections_severity_time (severity, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE detection_rules (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL UNIQUE,
    description TEXT,
    severity VARCHAR(16) NOT NULL DEFAULT 'medium',

    channel VARCHAR(255) NOT NULL DEFAULT 'Security',
    event_ids VARCHAR(255) NOT NULL,

    match_field VARCHAR(255) DEFAULT '',
    match_operator VARCHAR(16) DEFAULT '',
    match_value TEXT,

    threshold_count INT NOT NULL DEFAULT 1,
    threshold_window_seconds INT NOT NULL DEFAULT 0,

    suppress_for_seconds INT NOT NULL DEFAULT 3600,
    enabled TINYINT(1) NOT NULL DEFAULT 1,

    created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);

CREATE INDEX idx_detection_rules_enabled
ON detection_rules (enabled);

CREATE INDEX idx_event_logs_dynamic_rules
ON event_logs (channel_name, event_id, ts, hostname);

INSERT INTO detection_rules
(
    name,
    description,
    severity,
    channel,
    event_ids,
    match_field,
    match_operator,
    match_value,
    threshold_count,
    threshold_window_seconds,
    suppress_for_seconds,
    enabled
)
VALUES

-- ============================================================
-- Kritische Manipulationen / Spurenverwischung
-- ============================================================

(
    'v1_security_log_cleared',
    'Security Log wurde gelöscht. Das ist fast immer sicherheitsrelevant.',
    'high',
    'Security',
    '1102',
    '',
    '',
    '',
    1,
    0,
    86400,
    1
),

(
    'v1_audit_policy_changed',
    'Audit Policy wurde geändert.',
    'high',
    'Security',
    '4719',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_system_audit_policy_changed',
    'System Audit Policy wurde geändert.',
    'high',
    'Security',
    '4902,4904,4905,4906,4907,4908,4912',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_special_logon',
    'Anmeldung mit speziellen Rechten erkannt.',
    'medium',
    'Security',
    '4672',
    '',
    '',
    '',
    20,
    300,
    1800,
    1
),

(
    'v1_privileged_service_called',
    'Privilegierter Dienst wurde aufgerufen.',
    'medium',
    'Security',
    '4673,4674',
    '',
    '',
    '',
    10,
    300,
    1800,
    1
),

-- ============================================================
-- Benutzerverwaltung
-- ============================================================

(
    'v1_user_created',
    'Neuer AD-Benutzer wurde erstellt.',
    'medium',
    'Security',
    '4720',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_user_enabled',
    'AD-Benutzer wurde aktiviert.',
    'medium',
    'Security',
    '4722',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_user_disabled',
    'AD-Benutzer wurde deaktiviert.',
    'low',
    'Security',
    '4725',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_user_deleted',
    'AD-Benutzer wurde gelöscht.',
    'medium',
    'Security',
    '4726',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_user_changed',
    'AD-Benutzerobjekt wurde geändert.',
    'low',
    'Security',
    '4738',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_password_changed_by_user',
    'Benutzer hat eigenes Passwort geändert.',
    'low',
    'Security',
    '4723',
    '',
    '',
    '',
    1,
    0,
    900,
    1
),

(
    'v1_password_reset',
    'Passwort wurde durch Admin oder berechtigten Benutzer zurückgesetzt.',
    'medium',
    'Security',
    '4724',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_account_lockout',
    'Benutzerkonto wurde gesperrt.',
    'low',
    'Security',
    '4740',
    '',
    '',
    '',
    1,
    0,
    900,
    1
),

(
    'v1_account_lockout_spike',
    'Viele Account Lockouts innerhalb kurzer Zeit.',
    'medium',
    'Security',
    '4740',
    '',
    '',
    '',
    5,
    300,
    1800,
    1
),

-- ============================================================
-- Gruppenverwaltung allgemein
-- ============================================================

(
    'v1_security_group_created',
    'Security-Gruppe wurde erstellt.',
    'medium',
    'Security',
    '4727,4731,4754',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_security_group_deleted',
    'Security-Gruppe wurde gelöscht.',
    'medium',
    'Security',
    '4730,4734,4758',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_security_group_changed',
    'Security-Gruppe wurde geändert.',
    'medium',
    'Security',
    '4735,4737,4755',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_group_member_added',
    'Mitglied wurde zu einer Security-Gruppe hinzugefügt.',
    'medium',
    'Security',
    '4728,4732,4756',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_group_member_removed',
    'Mitglied wurde aus einer Security-Gruppe entfernt.',
    'medium',
    'Security',
    '4729,4733,4757',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

-- ============================================================
-- Privilegierte Gruppen
-- Achtung: target_user ist hier normalerweise der Gruppenname.
-- ============================================================

(
    'v1_privileged_group_member_added',
    'Mitglied wurde zu einer privilegierten AD-Gruppe hinzugefügt.',
    'high',
    'Security',
    '4728,4732,4756',
    'target_user',
    'in',
    'Domain Admins,Enterprise Admins,Schema Admins,Administrators,Account Operators,Server Operators,Backup Operators,Print Operators,DNSAdmins,Group Policy Creator Owners,Cert Publishers,Key Admins,Enterprise Key Admins',
    1,
    0,
    3600,
    1
),

(
    'v1_privileged_group_member_removed',
    'Mitglied wurde aus einer privilegierten AD-Gruppe entfernt.',
    'medium',
    'Security',
    '4729,4733,4757',
    'target_user',
    'in',
    'Domain Admins,Enterprise Admins,Schema Admins,Administrators,Account Operators,Server Operators,Backup Operators,Print Operators,DNSAdmins,Group Policy Creator Owners,Cert Publishers,Key Admins,Enterprise Key Admins',
    1,
    0,
    3600,
    1
),

(
    'v1_domain_admins_changed',
    'Änderung an Domain Admins erkannt.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Domain Admins',
    1,
    0,
    3600,
    1
),

(
    'v1_enterprise_admins_changed',
    'Änderung an Enterprise Admins erkannt.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Enterprise Admins',
    1,
    0,
    3600,
    1
),

(
    'v1_schema_admins_changed',
    'Änderung an Schema Admins erkannt.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Schema Admins',
    1,
    0,
    3600,
    1
),

(
    'v1_dnsadmins_changed',
    'Änderung an DNSAdmins erkannt. DNSAdmins können in vielen Umgebungen kritisch sein.',
    'high',
    'Security',
    '4728,4729,4732,4733,4756,4757',
    'target_user',
    'eq',
    'DNSAdmins',
    1,
    0,
    3600,
    1
),

-- ============================================================
-- Computer-Konten
-- ============================================================

(
    'v1_computer_account_created',
    'Computer-Konto wurde erstellt.',
    'low',
    'Security',
    '4741',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_computer_account_changed',
    'Computer-Konto wurde geändert.',
    'low',
    'Security',
    '4742',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_computer_account_deleted',
    'Computer-Konto wurde gelöscht.',
    'medium',
    'Security',
    '4743',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

-- ============================================================
-- Kerberos / Authentifizierung
-- ============================================================

(
    'v1_kerberos_preauth_failure',
    'Kerberos PreAuth Fehler erkannt.',
    'low',
    'Security',
    '4771',
    '',
    '',
    '',
    1,
    0,
    300,
    1
),

(
    'v1_kerberos_preauth_spike',
    'Viele Kerberos PreAuth Fehler. Möglicher Password-Spray oder Bruteforce.',
    'high',
    'Security',
    '4771',
    '',
    '',
    '',
    20,
    300,
    1800,
    1
),

(
    'v1_kerberos_tgt_failed_spike',
    'Viele fehlgeschlagene Kerberos-TGT-Anfragen.',
    'medium',
    'Security',
    '4768',
    '',
    '',
    '',
    30,
    300,
    1800,
    1
),

(
    'v1_kerberos_service_ticket_spike',
    'Viele Kerberos-Service-Ticket-Anfragen. Kann auf Kerberoasting oder ungewöhnliche Service-Nutzung hindeuten.',
    'medium',
    'Security',
    '4769',
    '',
    '',
    '',
    100,
    300,
    1800,
    1
),

(
    'v1_ntlm_authentication_spike',
    'Viele NTLM-Authentifizierungen erkannt.',
    'medium',
    'Security',
    '4776',
    '',
    '',
    '',
    50,
    300,
    1800,
    1
),

(
    'v1_logon_failed_spike',
    'Viele fehlgeschlagene Logons.',
    'medium',
    'Security',
    '4625',
    '',
    '',
    '',
    25,
    300,
    1800,
    1
),

(
    'v1_explicit_credentials_used',
    'Anmeldung mit expliziten Anmeldeinformationen erkannt.',
    'medium',
    'Security',
    '4648',
    '',
    '',
    '',
    1,
    0,
    900,
    1
),

(
    'v1_many_explicit_credentials_used',
    'Viele Anmeldungen mit expliziten Anmeldeinformationen.',
    'high',
    'Security',
    '4648',
    '',
    '',
    '',
    20,
    300,
    1800,
    1
),

-- ============================================================
-- Dienste, Tasks, Persistenz
-- ============================================================

(
    'v1_service_installed_security',
    'Neuer Dienst laut Security Log installiert.',
    'high',
    'Security',
    '4697',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_service_installed_system',
    'Neuer Dienst laut System Log installiert.',
    'high',
    'System',
    '7045',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_scheduled_task_created',
    'Geplanter Task wurde erstellt.',
    'high',
    'Security',
    '4698',
    '',
    '',
    '',
    1,
    0,
    3600,
    1
),

(
    'v1_scheduled_task_updated',
    'Geplanter Task wurde geändert.',
    'medium',
    'Security',
    '4702',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_scheduled_task_deleted',
    'Geplanter Task wurde gelöscht.',
    'medium',
    'Security',
    '4699',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_scheduled_task_enabled_disabled',
    'Geplanter Task wurde aktiviert oder deaktiviert.',
    'medium',
    'Security',
    '4700,4701',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

-- ============================================================
-- Prozess / PowerShell / Script Logging
-- Nur aktivieren, wenn diese Events bei dir tatsächlich gesammelt werden.
-- ============================================================

(
    'v1_process_created',
    'Neuer Prozess wurde erstellt. Nur sinnvoll bei aktiviertem Process Creation Auditing.',
    'low',
    'Security',
    '4688',
    '',
    '',
    '',
    1,
    0,
    300,
    0
),

(
    'v1_suspicious_powershell_process',
    'Verdächtiger PowerShell-Aufruf im Prozess-Event.',
    'high',
    'Security',
    '4688',
    'msg',
    'contains',
    'powershell',
    1,
    0,
    1800,
    0
),

(
    'v1_powershell_script_block',
    'PowerShell Script Block Logging Event erkannt.',
    'medium',
    'Windows PowerShell,Microsoft-Windows-PowerShell/Operational',
    '4104',
    '',
    '',
    '',
    1,
    0,
    900,
    0
),

(
    'v1_suspicious_powershell_encodedcommand',
    'PowerShell EncodedCommand erkannt.',
    'high',
    'Windows PowerShell,Microsoft-Windows-PowerShell/Operational,Security',
    '4104,4688',
    'msg',
    'contains',
    'EncodedCommand',
    1,
    0,
    1800,
    0
),

(
    'v1_suspicious_powershell_downloadstring',
    'PowerShell DownloadString erkannt.',
    'high',
    'Windows PowerShell,Microsoft-Windows-PowerShell/Operational,Security',
    '4104,4688',
    'msg',
    'contains',
    'DownloadString',
    1,
    0,
    1800,
    0
),

(
    'v1_suspicious_powershell_iex',
    'PowerShell Invoke-Expression / IEX erkannt.',
    'high',
    'Windows PowerShell,Microsoft-Windows-PowerShell/Operational,Security',
    '4104,4688',
    'msg',
    'contains',
    'Invoke-Expression',
    1,
    0,
    1800,
    0
),

-- ============================================================
-- GPO / AD Objektänderungen
-- Hinweis: 5136/5137/5141 kommen aus Directory Service Changes.
-- Dafür muss das passende Auditing auf DCs aktiv sein.
-- ============================================================

(
    'v1_directory_object_modified',
    'AD-Objekt wurde geändert.',
    'medium',
    'Security',
    '5136',
    '',
    '',
    '',
    1,
    0,
    900,
    0
),

(
    'v1_directory_object_created',
    'AD-Objekt wurde erstellt.',
    'medium',
    'Security',
    '5137',
    '',
    '',
    '',
    1,
    0,
    900,
    0
),

(
    'v1_directory_object_deleted',
    'AD-Objekt wurde gelöscht.',
    'medium',
    'Security',
    '5141',
    '',
    '',
    '',
    1,
    0,
    1800,
    0
),

(
    'v1_gpo_changed',
    'Mögliche GPO-Änderung erkannt.',
    'high',
    'Security',
    '5136',
    'msg',
    'contains',
    'CN=Policies,CN=System',
    1,
    0,
    3600,
    0
),

(
    'v1_adminsdholder_changed',
    'AdminSDHolder wurde geändert. Sehr sicherheitsrelevant.',
    'high',
    'Security',
    '5136',
    'msg',
    'contains',
    'CN=AdminSDHolder',
    1,
    0,
    86400,
    0
),

(
    'v1_domain_root_changed',
    'Domain-Root-Objekt wurde geändert.',
    'high',
    'Security',
    '5136',
    'msg',
    'contains',
    'DC=',
    1,
    0,
    3600,
    0
),

-- ============================================================
-- Objektzugriff / ACL
-- Hinweis: 4662/4670 brauchen passende SACLs.
-- ============================================================

(
    'v1_object_permissions_changed',
    'Berechtigungen eines Objekts wurden geändert.',
    'high',
    'Security',
    '4670',
    '',
    '',
    '',
    1,
    0,
    3600,
    0
),

(
    'v1_directory_service_object_access',
    'Directory-Service-Objektzugriff erkannt.',
    'medium',
    'Security',
    '4662',
    '',
    '',
    '',
    10,
    300,
    1800,
    0
),

-- ============================================================
-- Share / SMB / SYSVOL / administrative Zugriffe
-- Hinweis: Kann sehr laut werden.
-- ============================================================

(
    'v1_network_share_accessed',
    'Netzwerkfreigabe wurde genutzt.',
    'low',
    'Security',
    '5140',
    '',
    '',
    '',
    50,
    300,
    900,
    0
),

(
    'v1_network_share_object_checked',
    'Detaillierter Netzwerkfreigabezugriff erkannt.',
    'low',
    'Security',
    '5145',
    '',
    '',
    '',
    100,
    300,
    900,
    0
),

(
    'v1_sysvol_access_spike',
    'Viele Zugriffe auf SYSVOL erkannt.',
    'low',
    'Security',
    '5140,5145',
    'msg',
    'contains',
    'SYSVOL',
    100,
    300,
    900,
    0
),

(
    'v1_admin_share_access',
    'Zugriff auf administrative Freigabe erkannt.',
    'medium',
    'Security',
    '5140,5145',
    'msg',
    'contains',
    'ADMIN$',
    1,
    0,
    1800,
    0
),

(
    'v1_c_share_access',
    'Zugriff auf C$ erkannt.',
    'medium',
    'Security',
    '5140,5145',
    'msg',
    'contains',
    'C$',
    1,
    0,
    1800,
    0
),

-- ============================================================
-- System / Neustart / Agent-Kontext
-- ============================================================

(
    'v1_system_startup',
    'System wurde gestartet.',
    'low',
    'System',
    '6005',
    '',
    '',
    '',
    1,
    0,
    300,
    0
),

(
    'v1_system_shutdown',
    'System wurde heruntergefahren.',
    'low',
    'System',
    '6006',
    '',
    '',
    '',
    1,
    0,
    300,
    0
),

(
    'v1_planned_shutdown_or_restart',
    'Geplanter Shutdown oder Neustart erkannt.',
    'low',
    'System',
    '1074',
    '',
    '',
    '',
    1,
    0,
    900,
    1
),

(
    'v1_unexpected_shutdown',
    'Unerwarteter Shutdown erkannt.',
    'medium',
    'System',
    '6008',
    '',
    '',
    '',
    1,
    0,
    1800,
    1
),

(
    'v1_reboot_spike_dynamic',
    'Viele Neustart-/Shutdown-Events in kurzer Zeit.',
    'medium',
    'System',
    '1074,6005,6006,6008',
    '',
    '',
    '',
    3,
    900,
    1800,
    0
),

-- ============================================================
-- Windows Defender / Security Center
-- Event IDs können je nach Version/Quelle variieren.
-- ============================================================

(
    'v1_defender_malware_detected',
    'Microsoft Defender hat Malware erkannt.',
    'high',
    'Microsoft-Windows-Windows Defender/Operational',
    '1116',
    '',
    '',
    '',
    1,
    0,
    3600,
    0
),

(
    'v1_defender_malware_remediated',
    'Microsoft Defender hat Malware bereinigt.',
    'medium',
    'Microsoft-Windows-Windows Defender/Operational',
    '1117',
    '',
    '',
    '',
    1,
    0,
    1800,
    0
),

(
    'v1_defender_action_failed',
    'Microsoft Defender Aktion fehlgeschlagen.',
    'high',
    'Microsoft-Windows-Windows Defender/Operational',
    '1118,1119',
    '',
    '',
    '',
    1,
    0,
    3600,
    0
),

(
    'v1_defender_disabled_or_config_changed',
    'Defender-Konfiguration wurde geändert oder Schutz deaktiviert.',
    'high',
    'Microsoft-Windows-Windows Defender/Operational',
    '5007,5013',
    '',
    '',
    '',
    1,
    0,
    3600,
    0
),

-- ============================================================
-- Zertifikatsdienste / AD CS
-- Nur aktivieren, wenn AD CS vorhanden und Events gesammelt werden.
-- ============================================================

(
    'v1_certificate_request_issued',
    'Zertifikat wurde ausgestellt.',
    'medium',
    'Security',
    '4886,4887',
    '',
    '',
    '',
    1,
    0,
    1800,
    0
),

(
    'v1_certificate_template_changed',
    'Zertifikatstemplate wurde geändert.',
    'high',
    'Security',
    '4898,4899,4900',
    '',
    '',
    '',
    1,
    0,
    86400,
    0
),

(
    'v1_cert_services_config_changed',
    'AD-CS-Konfiguration wurde geändert.',
    'high',
    'Security',
    '4882,4885,4890,4891,4892',
    '',
    '',
    '',
    1,
    0,
    86400,
    0
);

UPDATE detection_rules
SET description = ''
WHERE description IS NULL;

UPDATE detection_rules
SET match_field = ''
WHERE match_field IS NULL;

UPDATE detection_rules
SET match_operator = ''
WHERE match_operator IS NULL;

UPDATE detection_rules
SET match_value = ''
WHERE match_value IS NULL;

ALTER TABLE detection_rules
MODIFY description TEXT NULL,
MODIFY match_value TEXT NULL,
MODIFY match_field VARCHAR(64) NOT NULL DEFAULT '',
MODIFY match_operator VARCHAR(16) NOT NULL DEFAULT '';



CREATE TABLE baseline_event_stats (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    hostname VARCHAR(255) NOT NULL,
    channel_name VARCHAR(255) NOT NULL,
    event_id INT NOT NULL,

    hour_of_day TINYINT NOT NULL,
    day_of_week TINYINT NOT NULL,

    avg_count DOUBLE NOT NULL DEFAULT 0,
    m2_count DOUBLE NOT NULL DEFAULT 0,
    stddev_count DOUBLE NOT NULL DEFAULT 0,
    sample_count INT NOT NULL DEFAULT 0,

    last_updated TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),

    UNIQUE KEY uniq_baseline_event (
        hostname,
        channel_name,
        event_id,
        hour_of_day,
        day_of_week
    )
);

CREATE INDEX idx_baseline_event_lookup
ON baseline_event_stats (
    hostname,
    channel_name,
    event_id,
    hour_of_day,
    day_of_week,
    sample_count
);

ALTER TABLE detections
ADD COLUMN status VARCHAR(32) NOT NULL DEFAULT 'open',
ADD COLUMN analyst_note TEXT NULL,
ADD COLUMN reviewed_by VARCHAR(128) NULL,
ADD COLUMN reviewed_at TIMESTAMP(6) NULL,
ADD COLUMN is_false_positive TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN is_legitimate TINYINT(1) NOT NULL DEFAULT 0;

CREATE INDEX idx_detections_status_created
ON detections (status, created_at);

CREATE INDEX idx_detections_rule_status
ON detections (rule_name, status);

CREATE TABLE detection_suppressions (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    rule_name VARCHAR(128) NOT NULL,
    hostname VARCHAR(255) DEFAULT '',
    channel_name VARCHAR(255) DEFAULT '',
    event_id INT DEFAULT 0,
    reason TEXT NULL,
    created_by VARCHAR(128) DEFAULT '',
    created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    expires_at TIMESTAMP(6) NULL,
    enabled TINYINT(1) NOT NULL DEFAULT 1
);

CREATE INDEX idx_suppressions_lookup
ON detection_suppressions (enabled, rule_name, hostname, channel_name, event_id);

CREATE TABLE baseline_exclusions (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    hostname VARCHAR(255) NOT NULL DEFAULT '',
    channel_name VARCHAR(255) NOT NULL DEFAULT '',
    event_id INT NOT NULL DEFAULT 0,
    reason TEXT NULL,
    created_by VARCHAR(128) NOT NULL DEFAULT '',
    created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    expires_at TIMESTAMP(6) NULL,
    enabled TINYINT(1) NOT NULL DEFAULT 1
);

CREATE INDEX idx_baseline_exclusions_lookup
ON baseline_exclusions (enabled, hostname, channel_name, event_id, expires_at);

CREATE TABLE host_risk_scores (
    hostname VARCHAR(255) PRIMARY KEY,
    risk_score DOUBLE NOT NULL DEFAULT 0,
    severity VARCHAR(16) NOT NULL DEFAULT 'info',
    open_detections INT NOT NULL DEFAULT 0,
    high_detections INT NOT NULL DEFAULT 0,
    critical_detections INT NOT NULL DEFAULT 0,
    confirmed_incidents INT NOT NULL DEFAULT 0,
    last_detection_at TIMESTAMP(6) NULL,
    updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);

CREATE TABLE IF NOT EXISTS ueba_user_baseline (
    username VARCHAR(255) NOT NULL,
    hostname VARCHAR(255) NOT NULL,
    src_ip VARCHAR(64) NOT NULL,
    workstation VARCHAR(255) NOT NULL,
    first_seen DATETIME(6) NOT NULL DEFAULT UTC_TIMESTAMP(6),
    last_seen DATETIME(6) NOT NULL DEFAULT UTC_TIMESTAMP(6),
    seen_count BIGINT NOT NULL DEFAULT 1,
    PRIMARY KEY (username, hostname, src_ip, workstation)
);

CREATE INDEX idx_ueba_user_baseline_user
ON ueba_user_baseline (username, last_seen);

CREATE INDEX idx_host_risk_score
ON host_risk_scores (risk_score, severity);

INSERT INTO detection_rules
(
    name,
    description,
    severity,
    channel,
    event_ids,
    match_field,
    match_operator,
    match_value,
    threshold_count,
    threshold_window_seconds,
    suppress_for_seconds,
    enabled
)
VALUES

-- ============================================================
-- KRITISCHE MANIPULATIONEN
-- ============================================================

(
    'v2_security_log_cleared',
    'Security Log wurde gelöscht. Sehr wahrscheinlich Spurenverwischung.',
    'high',
    'Security',
    '1102',
    '', '', '',
    1, 0, 86400,
    1
),

(
    'v2_audit_policy_changed',
    'Audit Policy wurde geändert.',
    'high',
    'Security',
    '4719',
    '', '', '',
    1, 0, 3600,
    1
),

(
    'v2_system_audit_policy_changed',
    'System Audit Policy wurde geändert.',
    'high',
    'Security',
    '4902,4904,4905,4906,4907,4908,4912',
    '', '', '',
    1, 0, 3600,
    1
),

-- ============================================================
-- PRIVILEGIERTE GRUPPEN (WICHTIGSTER BLOCK!)
-- ============================================================

(
    'v2_privileged_group_member_added',
    'Mitglied wurde zu privilegierter AD-Gruppe hinzugefügt.',
    'high',
    'Security',
    '4728,4732,4756',
    'target_user',
    'in',
    'Domain Admins,Enterprise Admins,Schema Admins,Administrators,DNSAdmins',
    1, 0, 3600,
    1
),

(
    'v2_privileged_group_member_removed',
    'Mitglied wurde aus privilegierter AD-Gruppe entfernt.',
    'medium',
    'Security',
    '4729,4733,4757',
    'target_user',
    'in',
    'Domain Admins,Enterprise Admins,Schema Admins,Administrators,DNSAdmins',
    1, 0, 3600,
    1
),

(
    'v2_domain_admins_changed',
    'Änderung an Domain Admins.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Domain Admins',
    1, 0, 3600,
    1
),

(
    'v2_enterprise_admins_changed',
    'Änderung an Enterprise Admins.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Enterprise Admins',
    1, 0, 3600,
    1
),

(
    'v2_schema_admins_changed',
    'Änderung an Schema Admins.',
    'high',
    'Security',
    '4728,4729,4735,4737',
    'target_user',
    'eq',
    'Schema Admins',
    1, 0, 3600,
    1
),

(
    'v2_dnsadmins_changed',
    'Änderung an DNSAdmins erkannt.',
    'high',
    'Security',
    '4728,4729,4732,4733,4756,4757',
    'target_user',
    'eq',
    'DNSAdmins',
    1, 0, 3600,
    1
),

-- ============================================================
-- USER MANAGEMENT
-- ============================================================

(
    'v2_user_created',
    'Neuer AD-Benutzer wurde erstellt.',
    'medium',
    'Security',
    '4720',
    '', '', '',
    1, 0, 1800,
    1
),

(
    'v2_user_enabled',
    'AD-Benutzer wurde aktiviert.',
    'medium',
    'Security',
    '4722',
    '', '', '',
    1, 0, 1800,
    1
),

(
    'v2_user_deleted',
    'AD-Benutzer wurde gelöscht.',
    'medium',
    'Security',
    '4726',
    '', '', '',
    1, 0, 3600,
    1
),

(
    'v2_password_reset',
    'Passwort wurde zurückgesetzt.',
    'medium',
    'Security',
    '4724',
    '', '', '',
    1, 0, 1800,
    1
),

-- ============================================================
-- AUTHENTIFIZIERUNG (ANOMALIEN)
-- ============================================================

(
    'v2_account_lockout_spike',
    'Viele Account Lockouts.',
    'medium',
    'Security',
    '4740',
    '', '', '',
    5, 300, 1800,
    1
),

(
    'v2_kerberos_preauth_spike',
    'Viele Kerberos PreAuth Fehler.',
    'high',
    'Security',
    '4771',
    '', '', '',
    20, 300, 1800,
    1
),

(
    'v2_kerberos_service_ticket_spike',
    'Viele Kerberos Service Tickets (Kerberoasting möglich).',
    'medium',
    'Security',
    '4769',
    '', '', '',
    100, 300, 1800,
    1
),

(
    'v2_ntlm_authentication_spike',
    'Viele NTLM Authentifizierungen.',
    'medium',
    'Security',
    '4776',
    '', '', '',
    50, 300, 1800,
    1
),

(
    'v2_logon_failed_spike',
    'Viele fehlgeschlagene Logons.',
    'medium',
    'Security',
    '4625',
    '', '', '',
    25, 300, 1800,
    1
),

(
    'v2_many_explicit_credentials_used',
    'Viele Logons mit expliziten Credentials.',
    'high',
    'Security',
    '4648',
    '', '', '',
    20, 300, 1800,
    1
),

-- ============================================================
-- PERSISTENZ / LATERAL MOVEMENT
-- ============================================================

(
    'v2_service_installed_security',
    'Neuer Dienst (Security Log).',
    'high',
    'Security',
    '4697',
    '', '', '',
    1, 0, 3600,
    1
),

(
    'v2_service_installed_system',
    'Neuer Dienst (System Log).',
    'high',
    'System',
    '7045',
    '', '', '',
    1, 0, 3600,
    1
),

(
    'v2_scheduled_task_created',
    'Scheduled Task erstellt.',
    'high',
    'Security',
    '4698',
    '', '', '',
    1, 0, 3600,
    1
),

(
    'v2_scheduled_task_updated',
    'Scheduled Task geändert.',
    'medium',
    'Security',
    '4702',
    '', '', '',
    1, 0, 1800,
    1
),

(
    'v2_scheduled_task_deleted',
    'Scheduled Task gelöscht.',
    'medium',
    'Security',
    '4699',
    '', '', '',
    1, 0, 1800,
    1
),

(
    'v2_scheduled_task_enabled_disabled',
    'Scheduled Task aktiviert/deaktiviert.',
    'medium',
    'Security',
    '4700,4701',
    '', '', '',
    1, 0, 1800,
    1
),

-- ============================================================
-- SYSTEM EVENTS
-- ============================================================

(
    'v2_unexpected_shutdown',
    'Unerwarteter Shutdown erkannt.',
    'medium',
    'System',
    '6008',
    '', '', '',
    1, 0, 1800,
    1
);

UPDATE detection_rules
SET enabled = 0
WHERE name LIKE 'v1_%';

CREATE TABLE user_host_baseline (
    username VARCHAR(128),
    hostname VARCHAR(128),
    first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (username, hostname)
);

CREATE TABLE IF NOT EXISTS user_privilege_baseline (
    username VARCHAR(255) NOT NULL PRIMARY KEY,
    first_seen DATETIME(6) NOT NULL DEFAULT UTC_TIMESTAMP(6),
    last_seen DATETIME(6) NOT NULL DEFAULT UTC_TIMESTAMP(6),
    seen_count BIGINT NOT NULL DEFAULT 1
);

CREATE TABLE IF NOT EXISTS privileged_users (
    username VARCHAR(255) PRIMARY KEY,
    reason TEXT NULL,
    enabled TINYINT(1) NOT NULL DEFAULT 1,
    created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);

CREATE INDEX idx_privileged_users_enabled
ON privileged_users (enabled);

INSERT INTO privileged_users (username, reason, enabled)
VALUES
('administrator', 'Built-in Administrator', 1),
('admin', 'Generic admin account', 1)
ON DUPLICATE KEY UPDATE
reason = VALUES(reason);

CREATE TABLE IF NOT EXISTS user_source_ip_seen (
    username VARCHAR(255) NOT NULL,
    src_ip VARCHAR(64) NOT NULL,
    hostname VARCHAR(255) NOT NULL,
    first_seen DATETIME(6) NOT NULL,
    last_seen DATETIME(6) NOT NULL,
    seen_count BIGINT NOT NULL DEFAULT 1,
    PRIMARY KEY (username, src_ip, hostname)
);

###

ALTER TABLE detections
  ADD INDEX idx_detections_created_at (created_at),
  ADD INDEX idx_detections_status_created (status, created_at),
  ADD INDEX idx_detections_severity_created (severity, created_at),
  ADD INDEX idx_detections_host_created (hostname, created_at),
  ADD INDEX idx_detections_rule_created (rule_name, created_at),
  ADD INDEX idx_detections_host_rule_created (hostname, rule_name, created_at),
  ADD INDEX idx_detections_host_status_created (hostname, status, created_at),
  ADD INDEX idx_detections_risk_window (created_at, status, hostname, severity),
  ADD INDEX idx_detections_window_lookup (hostname, window_start, window_end);

ALTER TABLE ueba_user_baseline
  ADD UNIQUE KEY uq_ueba_user_context (username, hostname, src_ip, workstation),
  ADD INDEX idx_ueba_user_last_seen (username, last_seen),
  ADD INDEX idx_ueba_host_last_seen (hostname, last_seen);

ALTER TABLE user_source_ip_seen
  ADD UNIQUE KEY uq_user_source_ip_host (username, src_ip, hostname),
  ADD INDEX idx_user_source_ip_last_seen (username, src_ip, last_seen);

ALTER TABLE user_privilege_baseline
  ADD UNIQUE KEY uq_user_privilege_username (username);

ALTER TABLE baseline_event_stats
  ADD UNIQUE KEY uq_baseline_bucket (
    hostname,
    channel_name,
    event_id,
    hour_of_day,
    day_of_week
  );

ALTER TABLE detection_suppressions
  ADD INDEX idx_detection_suppressions_lookup (
    enabled,
    rule_name,
    hostname,
    channel_name,
    event_id,
    expires_at
  );

ALTER TABLE baseline_exclusions
  ADD INDEX idx_baseline_exclusions_lookup (
    enabled,
    hostname,
    channel_name,
    event_id,
    expires_at
  );

ALTER TABLE detections
  ADD INDEX idx_detections_status_created2 (status, created_at),
  ADD INDEX idx_detections_severity_created2 (severity, created_at);

###

  CREATE TABLE IF NOT EXISTS event_log_raw (
    event_log_id BIGINT UNSIGNED NOT NULL,
    msg MEDIUMTEXT NOT NULL,
    msg_sha256 CHAR(64) NOT NULL,
    created_at DATETIME(6) NOT NULL DEFAULT (UTC_TIMESTAMP(6)),
    PRIMARY KEY (event_log_id),
    INDEX idx_event_log_raw_sha256 (msg_sha256),
    INDEX idx_event_log_raw_created_at (created_at)
);

ALTER TABLE event_log_raw
  ADD CONSTRAINT fk_event_log_raw_event
  FOREIGN KEY (event_log_id)
  REFERENCES event_logs(id)
  ON DELETE CASCADE;

######################## MIGRATION ############################
INSERT INTO event_log_raw (event_log_id, msg, msg_sha256, created_at)
SELECT id, msg, msg_sha256, COALESCE(received_at, UTC_TIMESTAMP(6))
FROM event_logs
WHERE msg IS NOT NULL
  AND msg <> ''
ON DUPLICATE KEY UPDATE
    msg = VALUES(msg),
    msg_sha256 = VALUES(msg_sha256);
######################## MIGRATION ############################


######################## TEST #################################
SELECT COUNT(*) AS raw_rows FROM event_log_raw;
SELECT COUNT(*) AS event_rows_with_msg FROM event_logs WHERE msg IS NOT NULL AND msg <> '';
######################## TEST #################################

######################## MIGRATION ############################
UPDATE event_logs
SET msg = ''
WHERE msg IS NOT NULL
  AND msg <> ''
LIMIT 10000;
######################## MIGRATION ############################

######################## TEST #################################
SELECT COUNT(*) FROM event_logs WHERE msg IS NOT NULL AND msg <> '';
######################## TEST #################################