feat(ops): /ops/v1/summary med ai/aktivering/engagemang/betalning/jobb/sakerhet + canary
- Nya toppnivåblock i /ops/v1/summary: ai_scan, aktivering, engagemang, betalning, jobb, sakerhet. Alla värden läses från DB/cache; null där data saknas, inga påhittade värden. - AI-kostnad i USD mikrocent (native); intäkter fortsatt SEK-öre. - product_analytics_events är källa för volym, latens, lyckandegrad, felfrekvens, aktivering, retention och engagemang. - Nya händelser: scan_started (API) och scan_failed/scan_completed med latencyMs + felkod (worker). latencyMs flödar nu in i scan_completed. - Safety canary-jobb varje timme: re-härleder allergener för alla recept, räknar överifierade publika recept och food-safety-lint; skriver EN rad till ops_safety_canary. Endpointen läser endast sista raden. - Cache-refresh-jobb var 60 s skriver hela summariet till Redis; endpointen serverar cachen med 503 vid cache-miss. - Bearer-token-skydd med OPS_TOKEN; HTTPS-tvång i produktion; ingen PII. - Tester för endpoint, auth, cache-miss och safety canary.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import "./setup-env.js";
|
||||
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
||||
import { createDatabase, schema } from "@app/database";
|
||||
import { processSafetyCanary } from "../src/processors/safety-canary.js";
|
||||
import type { WorkerContext } from "../src/context.js";
|
||||
|
||||
const testDb = createDatabase(process.env.TEST_DATABASE_URL!);
|
||||
const ctx: WorkerContext = { db: testDb.db } as never;
|
||||
|
||||
describe("RUN_SAFETY_CANARY", () => {
|
||||
beforeAll(async () => {
|
||||
await testDb.db.delete(schema.opsSafetyCanary);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await testDb.db.delete(schema.opsSafetyCanary);
|
||||
await testDb.pool.end();
|
||||
});
|
||||
|
||||
it("re-härleder allergener och skriver en canary-rad", async () => {
|
||||
const result = await processSafetyCanary(ctx);
|
||||
|
||||
expect(typeof result.allergenInvariantBrott).toBe("number");
|
||||
expect(typeof result.overifieradeVisade).toBe("number");
|
||||
expect(result.allergenInvariantBrott).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const latest = await testDb.db
|
||||
.select()
|
||||
.from(schema.opsSafetyCanary)
|
||||
.orderBy(schema.opsSafetyCanary.occurredAt)
|
||||
.limit(1);
|
||||
expect(latest.length).toBe(1);
|
||||
expect(latest[0]!.allergenInvariantBrott).toBe(result.allergenInvariantBrott);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user