146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import { z } from "zod";
|
|
import { createTRPCRouter, controllerProcedure } from "../trpc.js";
|
|
import {
|
|
auditLogByEntityInputSchema,
|
|
auditLogListInputSchema,
|
|
auditLogTimelineInputSchema,
|
|
} from "./audit-log-inputs.js";
|
|
import {
|
|
formatAuditDetailEntry,
|
|
formatAuditListEntry,
|
|
getAuditActivitySummary,
|
|
getAuditEntriesByEntity,
|
|
getAuditEntryById,
|
|
getAuditTimeline,
|
|
listAuditEntries,
|
|
toAuditListInput,
|
|
toAuditTimelineInput,
|
|
} from "./audit-log-support.js";
|
|
|
|
// ─── Router ───────────────────────────────────────────────────────────────────
|
|
|
|
export const auditLogRouter = createTRPCRouter({
|
|
/**
|
|
* Paginated, filterable list of audit log entries.
|
|
* Cursor-based pagination using createdAt + id.
|
|
*/
|
|
list: controllerProcedure
|
|
.input(auditLogListInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
return listAuditEntries(ctx.db, toAuditListInput({
|
|
entityType: input.entityType,
|
|
entityId: input.entityId,
|
|
userId: input.userId,
|
|
action: input.action,
|
|
source: input.source,
|
|
startDate: input.startDate,
|
|
endDate: input.endDate,
|
|
search: input.search,
|
|
limit: input.limit,
|
|
cursor: input.cursor,
|
|
}));
|
|
}),
|
|
|
|
listDetail: controllerProcedure
|
|
.input(auditLogListInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
const result = await listAuditEntries(ctx.db, toAuditListInput({
|
|
entityType: input.entityType,
|
|
entityId: input.entityId,
|
|
userId: input.userId,
|
|
action: input.action,
|
|
source: input.source,
|
|
startDate: input.startDate,
|
|
endDate: input.endDate,
|
|
search: input.search,
|
|
limit: input.limit,
|
|
cursor: input.cursor,
|
|
}));
|
|
return {
|
|
items: result.items.map(formatAuditListEntry),
|
|
nextCursor: result.nextCursor ?? null,
|
|
};
|
|
}),
|
|
|
|
/**
|
|
* Get a single audit entry with full changes JSONB (for expand/detail view).
|
|
*/
|
|
getById: controllerProcedure
|
|
.input(z.object({ id: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
return getAuditEntryById(ctx.db, input.id);
|
|
}),
|
|
|
|
getByIdDetail: controllerProcedure
|
|
.input(z.object({ id: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
const entry = await getAuditEntryById(ctx.db, input.id);
|
|
return formatAuditDetailEntry(entry);
|
|
}),
|
|
|
|
/**
|
|
* Get all audit entries for a specific entity (e.g. a project or resource).
|
|
*/
|
|
getByEntity: controllerProcedure
|
|
.input(auditLogByEntityInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
return getAuditEntriesByEntity(ctx.db, input);
|
|
}),
|
|
|
|
getByEntityDetail: controllerProcedure
|
|
.input(auditLogByEntityInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
const entries = await getAuditEntriesByEntity(ctx.db, input);
|
|
return {
|
|
entityType: input.entityType,
|
|
entityId: input.entityId,
|
|
entityName: entries[0]?.entityName ?? null,
|
|
itemCount: entries.length,
|
|
items: entries.map(formatAuditDetailEntry),
|
|
};
|
|
}),
|
|
|
|
/**
|
|
* Timeline view: entries grouped by date (YYYY-MM-DD).
|
|
*/
|
|
getTimeline: controllerProcedure
|
|
.input(auditLogTimelineInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
return getAuditTimeline(ctx.db, toAuditTimelineInput({
|
|
startDate: input.startDate,
|
|
endDate: input.endDate,
|
|
limit: input.limit,
|
|
}));
|
|
}),
|
|
|
|
getTimelineDetail: controllerProcedure
|
|
.input(auditLogTimelineInputSchema)
|
|
.query(async ({ ctx, input }) => {
|
|
const timeline = await getAuditTimeline(ctx.db, toAuditTimelineInput({
|
|
startDate: input.startDate,
|
|
endDate: input.endDate,
|
|
limit: input.limit,
|
|
}));
|
|
return Object.fromEntries(
|
|
Object.entries(timeline).map(([dateKey, entries]) => [
|
|
dateKey,
|
|
entries.map(formatAuditDetailEntry),
|
|
]),
|
|
);
|
|
}),
|
|
|
|
/**
|
|
* Activity summary: counts by entity type, action, and user for a date range.
|
|
*/
|
|
getActivitySummary: controllerProcedure
|
|
.input(
|
|
z.object({
|
|
startDate: z.date().optional(),
|
|
endDate: z.date().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return getAuditActivitySummary(ctx.db, input);
|
|
}),
|
|
});
|