feat(admin): analytics redis cache, shared ops health, ticket queue clarity
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
474de0717b
commit
58fae1f90f
38 files changed
+348
-245
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
||||
import { join, relative } from "node:path";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const ROUTES: Array<[string, string]> = [
|
||||
@@ -135,22 +135,26 @@ describe("admin operations route contract", () => {
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
it("has no requireStaff left in admin pages", () => {
|
||||
const root = "src/app/admin";
|
||||
const offenders: string[] = [];
|
||||
function walk(dir: string) {
|
||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(full);
|
||||
else if (entry.name === "page.tsx") {
|
||||
const source = readFileSync(full, "utf8");
|
||||
if (/await requireStaff\(/.test(source)) {
|
||||
offenders.push(relative(process.cwd(), full).replaceAll("\\", "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
it("caches analytics full-scans via redisCache", () => {
|
||||
for (const path of [
|
||||
"src/app/admin/analytics/page.tsx",
|
||||
"src/app/admin/analytics/activity/page.tsx",
|
||||
"src/app/admin/analytics/economy/page.tsx",
|
||||
]) {
|
||||
expect(readFileSync(path, "utf8"), path).toContain("redisCache");
|
||||
}
|
||||
walk(root);
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
it("shares ops health probe across CC / DevOps / API", () => {
|
||||
expect(existsSync("src/lib/admin/ops-health.ts")).toBe(true);
|
||||
expect(
|
||||
readFileSync("src/app/admin/commandocentrum/page.tsx", "utf8"),
|
||||
).toContain("fetchOpsHealth");
|
||||
expect(readFileSync("src/app/admin/devops/page.tsx", "utf8")).toContain(
|
||||
"fetchOpsHealth",
|
||||
);
|
||||
expect(
|
||||
readFileSync("src/app/api/admin/devops/health/route.ts", "utf8"),
|
||||
).toContain("fetchOpsHealth");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { rcon } from "@/lib/services/rcon";
|
||||
|
||||
export type OpsHealth = {
|
||||
dbOk: boolean;
|
||||
dbLatencyMs: number;
|
||||
emulatorOk: boolean;
|
||||
onlineUsers: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared DB + emulator health probe for CommandoCentrum, DevOps, and APIs.
|
||||
* Emulator = real RCON `ping` (same semantics as CommandoCentrum /public health).
|
||||
*/
|
||||
export async function fetchOpsHealth(): Promise<OpsHealth> {
|
||||
const [db, emulatorOk, onlineUsers] = await Promise.all([
|
||||
(async () => {
|
||||
try {
|
||||
const start = Date.now();
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
return { dbOk: true, dbLatencyMs: Date.now() - start };
|
||||
} catch {
|
||||
return { dbOk: false, dbLatencyMs: 0 };
|
||||
}
|
||||
})(),
|
||||
rcon.send("ping", null).catch(() => false),
|
||||
prisma.user.count({ where: { online: "1" } }).catch(() => 0),
|
||||
]);
|
||||
|
||||
return {
|
||||
dbOk: db.dbOk,
|
||||
dbLatencyMs: db.dbLatencyMs,
|
||||
emulatorOk: Boolean(emulatorOk),
|
||||
onlineUsers,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
/** Open-queue sizes for dual ticket products (CMS desk vs help-center). */
|
||||
export async function fetchTicketQueueOpenCounts(): Promise<{
|
||||
cmsOpen: number;
|
||||
helpOpen: number;
|
||||
}> {
|
||||
const [cmsOpen, helpOpen] = await Promise.all([
|
||||
prisma.websiteTicket
|
||||
.count({ where: { status: { not: "closed" } } })
|
||||
.catch(() => 0),
|
||||
prisma.websiteHelpCenterTickets
|
||||
.count({ where: { open: true } })
|
||||
.catch(() => 0),
|
||||
]);
|
||||
return { cmsOpen, helpOpen };
|
||||
}
|
||||
Reference in new issue
Block a user