forked from syntaxbullet/AuroraBot-discord
feat: implement visual analytics and activity charts
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
||||
import { users, transactions, moderationCases, inventory } from "@db/schema";
|
||||
import { desc, sql, and, gte } from "drizzle-orm";
|
||||
import type { RecentEvent } from "./dashboard.types";
|
||||
import type { RecentEvent, ActivityData } from "./dashboard.types";
|
||||
import { TransactionType } from "@shared/lib/constants";
|
||||
|
||||
export const dashboardService = {
|
||||
/**
|
||||
@@ -149,6 +150,57 @@ export const dashboardService = {
|
||||
console.error("Failed to emit system event:", e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get hourly activity aggregation for the last 24 hours
|
||||
*/
|
||||
getActivityAggregation: async (): Promise<ActivityData[]> => {
|
||||
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
|
||||
// Postgres aggregation
|
||||
// We treat everything as a transaction.
|
||||
// We treat everything except TRANSFER_IN as a 'command' (to avoid double counting transfers)
|
||||
const result = await DrizzleClient
|
||||
.select({
|
||||
hour: sql<string>`date_trunc('hour', ${transactions.createdAt})`,
|
||||
transactions: sql<string>`COUNT(*)`,
|
||||
commands: sql<string>`COUNT(*) FILTER (WHERE ${transactions.type} != ${TransactionType.TRANSFER_IN})`
|
||||
})
|
||||
.from(transactions)
|
||||
.where(gte(transactions.createdAt, twentyFourHoursAgo))
|
||||
.groupBy(sql`1`)
|
||||
.orderBy(sql`1`);
|
||||
|
||||
// Map into a record for easy lookups
|
||||
const dataMap = new Map<string, { commands: number, transactions: number }>();
|
||||
result.forEach(row => {
|
||||
if (!row.hour) return;
|
||||
const dateStr = new Date(row.hour).toISOString();
|
||||
dataMap.set(dateStr, {
|
||||
commands: Number(row.commands),
|
||||
transactions: Number(row.transactions)
|
||||
});
|
||||
});
|
||||
|
||||
// Generate the last 24 hours of data
|
||||
const activity: ActivityData[] = [];
|
||||
const current = new Date();
|
||||
current.setHours(current.getHours(), 0, 0, 0);
|
||||
|
||||
for (let i = 23; i >= 0; i--) {
|
||||
const h = new Date(current.getTime() - i * 60 * 60 * 1000);
|
||||
const iso = h.toISOString();
|
||||
const existing = dataMap.get(iso);
|
||||
|
||||
activity.push({
|
||||
hour: iso,
|
||||
commands: existing?.commands || 0,
|
||||
transactions: existing?.transactions || 0
|
||||
});
|
||||
}
|
||||
|
||||
return activity;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user