import type { Prisma } from '@prisma/client'; import { prisma } from '../db.js'; import { env } from '../env.js'; export interface ActionContext { // Beide null fuer Vorgaenge ohne bekanntes Konto, etwa einen fehlgeschlagenen // Login auf einen Benutzernamen, den es gar nicht gibt. actorId: number | null; actorName: string | null; ip?: string | undefined; } export interface AuditEntry { action: string; targetType: string; targetId?: string | number | null; details?: Prisma.InputJsonValue; } type Client = Pick; export async function recordAudit( client: Client, ctx: ActionContext, entry: AuditEntry, ): Promise { await client.auditLog.create({ data: { actorUserId: ctx.actorId, actorName: ctx.actorName ?? null, action: entry.action, targetType: entry.targetType, targetId: entry.targetId == null ? null : String(entry.targetId), details: entry.details ?? undefined, ip: ctx.ip ?? null, }, }); } /** * Entfernt Audit-Eintraege, die aelter sind als die eingestellte Frist. Die * Guthaben-Historie bleibt unangetastet - sie ist die Quelle der Wahrheit fuer * bezahlte Ansprueche und hat eine andere Aufbewahrung als das Protokoll. */ export async function cleanupOldAuditEntries(): Promise { if (env.AUDIT_RETENTION_DAYS === 0) return 0; const cutoff = new Date(Date.now() - env.AUDIT_RETENTION_DAYS * 24 * 3600 * 1000); const result = await prisma.auditLog.deleteMany({ where: { createdAt: { lt: cutoff } } }); return result.count; }