51 lines
1.2 KiB
TypeScript
51 lines
1.2 KiB
TypeScript
import { headers } from "next/headers";
|
|
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
export type AuditTrailParams = {
|
|
tenantId: string;
|
|
actorUserId?: string | null;
|
|
entityType: string;
|
|
entityId: string;
|
|
action: string;
|
|
metadata?: unknown;
|
|
ipAddress?: string | null;
|
|
userAgent?: string | null;
|
|
};
|
|
|
|
function serializeMetadata(metadata: unknown) {
|
|
if (typeof metadata === "undefined") {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return JSON.stringify(metadata);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function writeAuditTrail(params: AuditTrailParams) {
|
|
await prisma.auditLog.create({
|
|
data: {
|
|
tenantId: params.tenantId,
|
|
actorUserId: params.actorUserId,
|
|
entityType: params.entityType,
|
|
entityId: params.entityId,
|
|
action: params.action,
|
|
metadataJson: serializeMetadata(params.metadata),
|
|
ipAddress: params.ipAddress,
|
|
userAgent: params.userAgent
|
|
}
|
|
});
|
|
}
|
|
|
|
export async function getRequestAuditContext() {
|
|
const requestHeaders = await headers();
|
|
const forwardedFor = requestHeaders.get("x-forwarded-for");
|
|
const ipAddress = forwardedFor ? forwardedFor.split(",")[0]?.trim() : requestHeaders.get("x-real-ip");
|
|
const userAgent = requestHeaders.get("user-agent");
|
|
|
|
return { ipAddress, userAgent };
|
|
}
|