spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1/** Admin data-quality dashboard: overview, flag list, resolve / dismiss. */2import type { FastifyInstance } from "fastify";3import { z } from "zod";4import { envelope, notFound, parseBody, parseQuery } from "../../lib/http.js";5import { intParam, pageParam, strParam } from "../../lib/params.js";6import { listFlags, qualityOverview, setFlagStatus } from "../../repositories/admin/quality.js";78export async function qualityAdminRoutes(app: FastifyInstance): Promise<void> {9 app.get("/quality", { schema: { summary: "Data-quality overview (QualityOverview): open flags by severity / code, largest published values, review queue, alerts" } }, async () => envelope(await qualityOverview(), { methodology: "Counts are over open quality_flags, claims by status and live (not hidden / merged) projects. 'Largest' lists are plain ORDER BY on published figures; pipeline MW per operator / metro is containment-aware (campus vs buildings never both) plus site-scoped project MW." }));1011 app.get("/quality/flags", { schema: { summary: "Quality flags (QualityFlagDTO[]) ?status=open|resolved|dismissed|all&code=&entity_type=&min_priority=&page=&per_page=" } }, async (req) => {12 const q = parseQuery(z.object({ status: strParam, code: strParam, entity_type: strParam, min_priority: intParam, page: pageParam, per_page: intParam }), req.query);13 const res = await listFlags({ status: q.status ?? "open", code: q.code, entityType: q.entity_type, minPriority: q.min_priority, page: q.page, perPage: q.per_page });14 return envelope(res.items, { total: res.total, page: res.page, perPage: res.perPage });15 });1617 app.post("/quality/flags/:id/resolve", { schema: { summary: "Resolve a quality flag {resolution}" } }, async (req) => {18 const { id } = req.params as { id: string };19 const body = parseBody(z.object({ resolution: z.string().min(1).max(500) }), req.body);20 const flag = await setFlagStatus(id, "resolved", body.resolution);21 if (!flag) throw notFound("quality flag");22 return envelope(flag);23 });2425 app.post("/quality/flags/:id/dismiss", { schema: { summary: "Dismiss a quality flag {reason?}" } }, async (req) => {26 const { id } = req.params as { id: string };27 const body = parseBody(z.object({ reason: z.string().max(500).optional() }), req.body ?? {});28 const flag = await setFlagStatus(id, "dismissed", body.reason ?? null);29 if (!flag) throw notFound("quality flag");30 return envelope(flag);31 });32}33