{
"tool_response": {
"type": "text",
"file": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Infrastructure\/Audit\/AuditService.php",
"content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Infrastructure\\Audit;\n\n\/\/ @responsibility: Zentrales Audit-Logging für kritische Operationen\n\nuse PDO;\n\n\/**\n * Audit service for logging critical operations.\n *\n * Logs to ki_dev.audit_log table with structured data for:\n * - Ontology\/Taxonomy changes\n * - Entity merges\n * - DSGVO deletions\n * - Schema migrations\n * - Pipeline configuration changes\n *\/\nfinal class AuditService\n{\n private const TABLE = 'ki_dev.audit_log';\n\n \/**\n * @param PDO $pdo Database connection to ki_dev\n *\/\n public function __construct(private PDO $pdo)\n {\n }\n\n \/**\n * Log an audit event.\n *\n * @param string $event Event name (e.g., 'entity.merge', 'ontology.update')\n * @param string $targetTable Target table name (e.g., 'entities', 'ontology_classes')\n * @param int|null $targetId Target entity\/record ID\n * @param array<string, mixed> $oldValue Previous state (will be JSON encoded)\n * @param array<string, mixed> $newValue New state (will be JSON encoded)\n * @param string|null $reason Optional reason for the change\n * @param string $actor Who performed the action (username or 'system')\n * @param string $actorType Actor type: 'user', 'system', 'pipeline'\n * @param string $level Log level: 'debug', 'info', 'warning', 'error'\n *\/\n public function log(\n string $event,\n string $targetTable,\n ?int $targetId = null,\n array $oldValue = [],\n array $newValue = [],\n ?string $reason = null,\n string $actor = 'system',\n string $actorType = 'system',\n string $level = 'info'\n ): void {\n $correlationId = $this->getCorrelationId();\n\n $stmt = $this->pdo->prepare(\n 'INSERT INTO ' . self::TABLE . '\n (correlation_id, event, entity_type, entity_id, context, level,\n actor, actor_type, target_table, target_id, old_value, new_value, reason,\n ip_address, created_at)\n VALUES\n (:correlation_id, :event, :entity_type, :entity_id, :context, :level,\n :actor, :actor_type, :target_table, :target_id, :old_value, :new_value, :reason,\n :ip_address, NOW())'\n );\n\n $stmt->execute([\n 'correlation_id' => $correlationId,\n 'event' => $event,\n 'entity_type' => $targetTable,\n 'entity_id' => $targetId,\n 'context' => json_encode(['target_table' => $targetTable, 'target_id' => $targetId]),\n 'level' => $level,\n 'actor' => $actor,\n 'actor_type' => $actorType,\n 'target_table' => $targetTable,\n 'target_id' => $targetId,\n 'old_value' => $oldValue !== [] ? json_encode($oldValue) : null,\n 'new_value' => $newValue !== [] ? json_encode($newValue) : null,\n 'reason' => $reason,\n 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',\n ]);\n }\n\n \/**\n * Log an entity creation.\n *\n * @param string $table Table name\n * @param int $id Created entity ID\n * @param array<string, mixed> $data Created data\n * @param string $actor Who created it\n * @param string $actorType Actor type\n *\/\n public function logCreate(\n string $table,\n int $id,\n array $data,\n string $actor = 'system',\n string $actorType = 'system'\n ): void {\n $this->log(\n event: $table . '.create',\n targetTable: $table,\n targetId: $id,\n newValue: $data,\n actor: $actor,\n actorType: $actorType\n );\n }\n\n \/**\n * Log an entity update.\n *\n * @param string $table Table name\n * @param int $id Updated entity ID\n * @param array<string, mixed> $oldData Previous state\n * @param array<string, mixed> $newData New state\n * @param string $actor Who updated it\n * @param string $actorType Actor type\n *\/\n public function logUpdate(\n string $table,\n int $id,\n array $oldData,\n array $newData,\n string $actor = 'system',\n string $actorType = 'system'\n ): void {\n $this->log(\n event: $table . '.update',\n targetTable: $table,\n targetId: $id,\n oldValue: $oldData,\n newValue: $newData,\n actor: $actor,\n actorType: $actorType\n );\n }\n\n \/**\n * Log an entity deletion.\n *\n * @param string $table Table name\n * @param int $id Deleted entity ID\n * @param array<string, mixed> $data Deleted data (for recovery)\n * @param string|null $reason Reason for deletion (e.g., 'DSGVO request')\n * @param string $actor Who deleted it\n * @param string $actorType Actor type\n *\/\n public function logDelete(\n string $table,\n int $id,\n array $data,\n ?string $reason = null,\n string $actor = 'system',\n string $actorType = 'system'\n ): void {\n $this->log(\n event: $table . '.delete',\n targetTable: $table,\n targetId: $id,\n oldValue: $data,\n reason: $reason,\n actor: $actor,\n actorType: $actorType,\n level: 'warning'\n );\n }\n\n \/**\n * Log an entity merge operation.\n *\n * @param int $sourceId Source entity ID (merged into target)\n * @param int $targetId Target entity ID (kept)\n * @param array<string, mixed> $sourceData Source entity data\n * @param array<string, mixed> $targetData Target entity data after merge\n * @param string $actor Who performed the merge\n *\/\n public function logMerge(\n int $sourceId,\n int $targetId,\n array $sourceData,\n array $targetData,\n string $actor = 'system'\n ): void {\n $this->log(\n event: 'entity.merge',\n targetTable: 'entities',\n targetId: $targetId,\n oldValue: ['source_id' => $sourceId, 'source_data' => $sourceData],\n newValue: ['target_id' => $targetId, 'merged_data' => $targetData],\n reason: \"Merged entity #{$sourceId} into #{$targetId}\",\n actor: $actor,\n actorType: 'user',\n level: 'warning'\n );\n }\n\n \/**\n * Get or generate correlation ID for request tracing.\n *\/\n private function getCorrelationId(): string\n {\n \/\/ Check for existing correlation ID from middleware\n if (isset($_SERVER['HTTP_X_CORRELATION_ID'])) {\n return $_SERVER['HTTP_X_CORRELATION_ID'];\n }\n\n \/\/ Check session\n if (isset($_SESSION['correlation_id'])) {\n return $_SESSION['correlation_id'];\n }\n\n \/\/ Generate new one\n return bin2hex(random_bytes(16));\n }\n}\n",
"numLines": 220,
"startLine": 1,
"totalLines": 220
}
}
}