import { query } from '../db/pool.js'; /* * The audit service records every administrative mutation so the team can trace * when configuration changed and what the previous value was. Each row captures * the entity type (e.g. "image_rules"), the entity identifier, the action name, * and JSON snapshots of the old and new values. */ export async function logAuditEvent({ entityType, entityCode, action, oldValue = null, newValue = null }) { await query( ` INSERT INTO audit_log (entity_type, entity_code, action, old_value_json, new_value_json) VALUES (?, ?, ?, ?, ?) `, [ entityType, entityCode, action, oldValue ? JSON.stringify(oldValue) : null, newValue ? JSON.stringify(newValue) : null ] ); } export async function getAuditLog({ entityType, entityCode, limit = 50 } = {}) { let sql = 'SELECT id, entity_type, entity_code, action, old_value_json, new_value_json, created_at FROM audit_log'; const params = []; const clauses = []; if (entityType) { clauses.push('entity_type = ?'); params.push(entityType); } if (entityCode) { clauses.push('entity_code = ?'); params.push(entityCode); } if (clauses.length) { sql += ` WHERE ${clauses.join(' AND ')}`; } sql += ' ORDER BY id DESC LIMIT ?'; params.push(limit); const rows = await query(sql, params); return rows.map((row) => ({ id: row.id, entityType: row.entity_type, entityCode: row.entity_code, action: row.action, oldValue: safeParseJson(row.old_value_json), newValue: safeParseJson(row.new_value_json), createdAt: row.created_at })); } function safeParseJson(value) { if (value == null) { return null; } if (typeof value === 'object') { return value; } try { return JSON.parse(value); } catch { return null; } }