-- Audit module: idempotent migration for existing audit tables. -- These tables may already exist in deployments that had audit in core. -- All statements use IF NOT EXISTS to be safe for both fresh installs and upgrades. CREATE TABLE IF NOT EXISTS `system_audit_log` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `event_uuid` CHAR(36) NOT NULL, `request_id` CHAR(36) NULL, `channel` VARCHAR(20) NOT NULL DEFAULT 'web', `event_type` VARCHAR(64) NOT NULL, `outcome` VARCHAR(20) NOT NULL DEFAULT 'success', `error_code` VARCHAR(100) NULL, `actor_user_id` INT UNSIGNED NULL, `actor_tenant_id` INT UNSIGNED NULL, `target_type` VARCHAR(64) NULL, `target_id` INT UNSIGNED NULL, `target_uuid` CHAR(36) NULL, `method` VARCHAR(8) NULL, `path` VARCHAR(255) NULL, `ip_hash` CHAR(64) NULL, `user_agent_hash` CHAR(64) NULL, `metadata_json` JSON NULL, `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_sal_event_type_created` (`event_type`, `created` DESC), KEY `idx_sal_actor_user_id` (`actor_user_id`), KEY `idx_sal_created` (`created` DESC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `api_audit_log` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `request_id` CHAR(36) NOT NULL, `method` VARCHAR(8) NOT NULL, `path` VARCHAR(255) NOT NULL, `query_json` JSON NULL, `status_code` SMALLINT UNSIGNED NOT NULL, `duration_ms` INT UNSIGNED NULL, `error_code` VARCHAR(100) NULL, `user_id` INT UNSIGNED NULL, `tenant_id` INT UNSIGNED NULL, `api_token_id` INT UNSIGNED NULL, `token_tenant_id` INT UNSIGNED NULL, `ip` VARCHAR(45) NULL, `user_agent` VARCHAR(255) NULL, `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_aal_created` (`created` DESC), KEY `idx_aal_path_created` (`path`(64), `created` DESC), KEY `idx_aal_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `import_audit_runs` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `run_uuid` CHAR(36) NOT NULL, `profile_key` VARCHAR(64) NOT NULL, `status` VARCHAR(20) NOT NULL DEFAULT 'running', `source_filename` VARCHAR(255) NULL, `mapped_targets_csv` VARCHAR(500) NULL, `rows_total` INT UNSIGNED NOT NULL DEFAULT 0, `created_count` INT UNSIGNED NOT NULL DEFAULT 0, `skipped_count` INT UNSIGNED NOT NULL DEFAULT 0, `failed_count` INT UNSIGNED NOT NULL DEFAULT 0, `error_codes_json` JSON NULL, `duration_ms` INT UNSIGNED NULL, `user_id` INT UNSIGNED NULL, `current_tenant_id` INT UNSIGNED NULL, `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `finished_at` DATETIME NULL, PRIMARY KEY (`id`), KEY `idx_iar_created` (`created` DESC), KEY `idx_iar_profile_key` (`profile_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `user_lifecycle_audit_log` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `run_uuid` CHAR(36) NOT NULL, `action` VARCHAR(20) NOT NULL, `trigger_type` VARCHAR(20) NOT NULL, `status` VARCHAR(20) NOT NULL DEFAULT 'success', `reason_code` VARCHAR(100) NULL, `policy_deactivate_days` INT UNSIGNED NOT NULL DEFAULT 0, `policy_delete_days` INT UNSIGNED NOT NULL DEFAULT 0, `actor_user_id` INT UNSIGNED NULL, `target_user_id` INT UNSIGNED NULL, `target_user_uuid` CHAR(36) NULL, `target_user_email` VARCHAR(255) NULL, `snapshot_enc` MEDIUMTEXT NULL, `snapshot_version` TINYINT UNSIGNED NOT NULL DEFAULT 1, `restored_at` DATETIME NULL, `restored_by_user_id` INT UNSIGNED NULL, `restored_user_id` INT UNSIGNED NULL, `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_ulal_action_created` (`action`, `created` DESC), KEY `idx_ulal_target_user_id` (`target_user_id`), KEY `idx_ulal_created` (`created` DESC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;