PR 3 du chantier admin. Tableau de bord metriques : snapshot de compteurs
+ series temporelles journalieres.
Schema (migration admin_metrics) :
- AnalyticsEvent (type String libre, actorType/actorId sans FK, context Json,
index [type, created_at]) + WorkerHeartbeat (cable en PR 4).
- colonnes createdAt @default(now()) sur UserProfile / Recipe / Planning /
PlanningItem (lecture admin uniquement ; lignes existantes = timestamp de
la migration).
Instrumentation (lib/analytics.service.ts, fire-and-forget) :
- analytics.recordEvent(type, {actorId?, context?}) : retourne void, insert
detache, echec loggue+avale, jamais de latence sur la requete.
- points d'appel : user.signup, recipe.created, recipe.imported,
planning.item_added, tech_step.correction_submitted, shopping_list.viewed.
API : GET /admin/metrics?days= (7-365, defaut 30, requireAdmin) ->
admin-metrics.service.ts. bucketByDay pur (zero-remplissage, teste sans
base). MetricsView dans packages/shared.
Front : DashboardPage (tuiles KPI + un graphe recharts par serie + listes
recettes-par-source / evenements), logique pure dans dashboard.ts, i18n
admin.dashboard.*. AdminApiClient.getMetrics.
reset-db.ts truncate analytics_events + worker_heartbeats.
Tests : Mocha admin-metrics.test.ts (bucketByDay pur x2 verts ; snapshot,
series zero-remplies, event user.signup fire-and-forget) ; Cypress
dashboard.cy.ts (2 verts). specs/backend-architecture.md : section admin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
22 lines
853 B
TypeScript
22 lines
853 B
TypeScript
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
|
||
import { getMetricsSchema } from "@batch-cooking/shared";
|
||
import { Router } from "express";
|
||
import { requireAdmin } from "../../middlewares/require-admin.js";
|
||
import { getMetrics } from "./admin-metrics.service.js";
|
||
|
||
/** Router mounted at `/admin/metrics` (via `admin.routes.ts`) — every route behind {@link requireAdmin}. */
|
||
export const adminMetricsRouter = Router();
|
||
|
||
/**
|
||
* Returns the admin dashboard's usage metrics — a `snapshot` of current
|
||
* totals plus `?days=` (7–365, default 30) days of daily time series (see
|
||
* {@link getMetrics}). Read-only; no side effects.
|
||
*/
|
||
adminMetricsRouter.get(
|
||
"/",
|
||
requireAdmin,
|
||
wrapAsyncHandler(async (req, res) => {
|
||
const { days } = getMetricsSchema.parse(req.query);
|
||
res.status(200).json(await getMetrics(days));
|
||
}),
|
||
);
|