feat: classify traffic audit into external vs system channels
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 8s
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 8s
This commit is contained in:
@@ -15,7 +15,7 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
|
||||
const [summaryRows, totalRows] = await Promise.all([
|
||||
const [summaryRows, actorSummaryRows, totalRows, latestEvents] = await Promise.all([
|
||||
prisma.auditEvent.groupBy({
|
||||
by: ["action"],
|
||||
where: {
|
||||
@@ -23,19 +23,91 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
_count: { _all: true },
|
||||
}),
|
||||
prisma.auditEvent.groupBy({
|
||||
by: ["actorType"],
|
||||
where: {
|
||||
createdAt: { gte: since },
|
||||
},
|
||||
_count: { _all: true },
|
||||
}),
|
||||
prisma.auditEvent.count({
|
||||
where: { createdAt: { gte: since } },
|
||||
}),
|
||||
prisma.auditEvent.findMany({
|
||||
where: {
|
||||
createdAt: { gte: since },
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
take: 80,
|
||||
select: {
|
||||
id: true,
|
||||
action: true,
|
||||
actorType: true,
|
||||
actorId: true,
|
||||
entityType: true,
|
||||
entityId: true,
|
||||
reason: true,
|
||||
metadata: true,
|
||||
createdAt: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const actionSummary = Object.fromEntries(
|
||||
summaryRows.map((row) => [row.action, row._count._all])
|
||||
);
|
||||
|
||||
const actorSummary = Object.fromEntries(
|
||||
actorSummaryRows.map((row) => [row.actorType, row._count._all])
|
||||
);
|
||||
|
||||
const channelSummary = Object.entries(actionSummary).reduce(
|
||||
(acc, [action, count]) => {
|
||||
if (action.startsWith("EXTERNAL_")) {
|
||||
acc.external += count;
|
||||
} else {
|
||||
acc.internal += count;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ external: 0, internal: 0 } as Record<string, number>
|
||||
);
|
||||
|
||||
const externalEventTypes = Object.entries(actionSummary).filter(([action]) => action.startsWith("EXTERNAL_")).map(([action, count]) => ({ action, count }));
|
||||
const internalEventTypes = Object.entries(actionSummary).filter(([action]) => !action.startsWith("EXTERNAL_")).map(([action, count]) => ({ action, count }));
|
||||
|
||||
const recentEvents = latestEvents.map((event) => {
|
||||
// metadata is JSONB in Prisma; read only known optional keys for monitoring views.
|
||||
const metadata =
|
||||
event.metadata && typeof event.metadata === "object" && !Array.isArray(event.metadata)
|
||||
? (event.metadata as Record<string, unknown>)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: event.id,
|
||||
action: event.action,
|
||||
actorType: event.actorType,
|
||||
actorId: event.actorId,
|
||||
entityType: event.entityType,
|
||||
entityId: event.entityId,
|
||||
reason: event.reason,
|
||||
createdAt: event.createdAt,
|
||||
surface: metadata?.surface,
|
||||
level: metadata?.level,
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
period_hours: 24,
|
||||
total_events: totalRows,
|
||||
action_summary: actionSummary,
|
||||
channel_summary: channelSummary,
|
||||
actor_summary: actorSummary,
|
||||
external_event_types: externalEventTypes,
|
||||
internal_event_types: internalEventTypes,
|
||||
recent_events: recentEvents,
|
||||
updated_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user