Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/services/admin/api-admin.server.ts
T

160 lines
5.5 KiB
TypeScript

import type { ApiAdminConsumerInput, ApiAdminInput } from "@hivegrid/view-models";
import { runWithRlsContext } from "@hivegrid/db/rls-context.server";
import { db } from "~/utils/db.server";
export type ApiAdminDeps = {
readonly db?: typeof db;
readonly now?: () => Date;
readonly platformLeadVisibility: {
readonly actorAdminUserId: string;
readonly canReadAll: boolean;
} | null;
};
export async function getApiAdminSnapshot(deps: ApiAdminDeps): Promise<ApiAdminInput> {
const client = deps.db ?? db;
const now = deps.now?.() ?? new Date();
const platformLeadWhere = deps.platformLeadVisibility
? ({
archivedAt: null,
...(deps.platformLeadVisibility.canReadAll
? {}
: {
assignedToAdminUserId: deps.platformLeadVisibility.actorAdminUserId,
}),
} as const)
: null;
const [failedLogs, registrationsPending, leadsNew, leadsQualified, recentRegistrations, recentLeads, tenants] = await Promise.all([
client.apiKeyLog.count({ where: { status: { gte: 400 } } }),
client.registration.count({ where: { createdTenantId: null } }),
platformLeadWhere ? client.adminLead.count({ where: { ...platformLeadWhere, status: "new" } }) : Promise.resolve(0),
platformLeadWhere ? client.adminLead.count({ where: { ...platformLeadWhere, status: "qualified" } }) : Promise.resolve(0),
client.registration.findMany({
orderBy: { createdAt: "desc" },
take: 10,
select: { id: true, email: true, company: true, createdAt: true, createdTenantId: true },
}),
platformLeadWhere
? client.adminLead.findMany({
where: platformLeadWhere,
orderBy: [{ capturedAt: "desc" }, { id: "desc" }],
take: 10,
select: {
id: true,
email: true,
company: true,
status: true,
capturedAt: true,
source: { select: { displayName: true } },
},
})
: Promise.resolve([]),
client.tenant.findMany({
orderBy: { name: "asc" },
select: {
id: true,
name: true,
slug: true,
},
}),
]);
const tenantKeyGroups = await mapWithConcurrency(tenants, 8, async (tenant) => ({
tenant,
keys: await runWithRlsContext({ tenantId: tenant.id }, () =>
client.apiKey.findMany({
orderBy: { createdAt: "desc" },
select: { id: true, active: true, expires: true, createdAt: true },
})
),
}));
const allKeys = tenantKeyGroups.flatMap(({ keys }) => keys);
const keysTotal = allKeys.length;
const keysActive = allKeys.filter((key) => key.active && (!key.expires || key.expires > now)).length;
const keysExpired = allKeys.filter((key) => key.expires && key.expires <= now).length;
const consumers = tenantKeyGroups.filter(({ keys }) => keys.length > 0).slice(0, 50);
return {
metrics: [
{
id: "keys",
value: keysTotal,
labelKey: "admin.apiAdmin.metrics.keys.label",
detailKey: "admin.apiAdmin.metrics.keys.detail",
tone: keysTotal > 0 ? "success" : "warning",
},
{
id: "activeKeys",
value: keysActive,
labelKey: "admin.apiAdmin.metrics.activeKeys.label",
detailKey: "admin.apiAdmin.metrics.activeKeys.detail",
tone: keysActive > 0 ? "success" : "neutral",
},
{
id: "expiredKeys",
value: keysExpired,
labelKey: "admin.apiAdmin.metrics.expiredKeys.label",
detailKey: "admin.apiAdmin.metrics.expiredKeys.detail",
tone: keysExpired > 0 ? "warning" : "success",
},
{
id: "failedLogs",
value: failedLogs,
labelKey: "admin.apiAdmin.metrics.failedLogs.label",
detailKey: "admin.apiAdmin.metrics.failedLogs.detail",
tone: failedLogs > 0 ? "danger" : "success",
},
{
id: "inbound",
value: registrationsPending + leadsNew,
labelKey: "admin.apiAdmin.metrics.inbound.label",
detailKey: "admin.apiAdmin.metrics.inbound.detail",
tone: registrationsPending + leadsNew > 0 ? "warning" : "success",
},
],
consumers: consumers.map<ApiAdminConsumerInput>(({ tenant, keys }) => ({
id: tenant.id,
name: tenant.name,
slug: tenant.slug,
keyCount: keys.length,
activeKeyCount: keys.filter((key) => key.active && (!key.expires || key.expires > now)).length,
lastKeyCreatedAt: keys[0]?.createdAt.toISOString() ?? null,
})),
inbound: {
registrationsPending,
leadsNew,
leadsQualified,
recentRegistrations: recentRegistrations.map((registration) => ({
id: registration.id,
email: registration.email,
company: registration.company,
createdAt: registration.createdAt.toISOString(),
createdTenantId: registration.createdTenantId,
})),
recentLeads: recentLeads.map((lead) => ({
id: lead.id,
email: lead.email,
company: lead.company,
source: lead.source.displayName,
status: lead.status,
createdAt: lead.capturedAt.toISOString(),
})),
},
};
}
async function mapWithConcurrency<T, U>(items: readonly T[], concurrency: number, operation: (item: T) => Promise<U>): Promise<U[]> {
const results = new Array<U>(items.length);
let cursor = 0;
await Promise.all(
Array.from({ length: Math.min(concurrency, items.length) }, async () => {
while (cursor < items.length) {
const index = cursor++;
results[index] = await operation(items[index]!);
}
})
);
return results;
}