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:
Sven (AAMOS AI)
2026-08-10 05:47:43 +07:00
parent f4a603e977
commit 8f20b2ef1b
27 changed files with 1169 additions and 41 deletions
+6 -1
View File
@@ -29,6 +29,7 @@ export const ANALYTICS_INVENTORY_EVENT_NAMES = [
"scan_uploaded",
"scan_processing_completed",
"scan_processing_failed",
"scan_failed",
"scan_review_opened",
"scan_item_confirmed",
"scan_item_corrected",
@@ -129,7 +130,11 @@ export const FUNNELS = {
cooking_to_updated_inventory: ["cooking_session_started", "cooking_session_completed"],
activated_to_trial: ["cooking_session_completed", "trial_started"],
trial_to_paid: ["trial_started", "subscription_started"],
single_to_two_members: ["household_invite_sent", "household_invite_accepted", "second_member_first_action"],
single_to_two_members: [
"household_invite_sent",
"household_invite_accepted",
"second_member_first_action",
],
} as const;
export type FunnelName = keyof typeof FUNNELS;
+1
View File
@@ -7,4 +7,5 @@ export * from "./locale.js";
export * from "./money.js";
export * from "./measurement.js";
export * from "./analytics.js";
export * from "./ops.js";
export * from "./release-gates.js";
+64
View File
@@ -0,0 +1,64 @@
export interface OpsAiScanBlock {
scans_24h: number;
scans_7d: number;
lyckandegrad_24h: number | null;
latens_p50_ms: number | null;
latens_p95_ms: number | null;
felfrekvens_24h: number | null;
senaste_fel: Array<{ kod: string | null; tid: string }> | null;
kostnad_usd_mikrocent_manad: number;
kostnad_usd_mikrocent_24h: number | null;
kostnad_usd_mikrocent_24h_uppskattad: boolean;
budget_andel: number | null;
as_of: string;
}
export interface OpsActivationBlock {
scan_inom_24h_andel: number | null;
lagad_maltid_inom_7d_andel: number | null;
hushall_andra_medlem_aktiv_andel: number | null;
retention_d1: number | null;
retention_d7: number | null;
retention_d30: number | null;
}
export interface OpsEngagementBlock {
lagade_maltider_24h: number;
lagade_maltider_7d: number;
rek_ctr_7d: number | null;
puffar_skickade_24h: number;
puffar_atgardsgrad_7d: number | null;
}
export interface OpsPaymentBlock {
failed_nu: number;
grace_period_nu: number;
trials_utgar_48h: number;
aterbetalningar_7d: number | null;
chargebacks_7d: number | null;
}
export interface OpsQueueBlock {
vantande: number;
aktiva: number;
misslyckade_24h: number;
aldsta_vantande_sek: number | null;
workers_ok: boolean;
}
export interface OpsSafetyBlock {
allergen_invariant_brott: number;
overifierade_visade: number;
food_safety_lint_avvisade_7d: number | null;
senaste_kontroll: string | null;
}
export interface OpsSummary {
ai_scan: OpsAiScanBlock;
aktivering: OpsActivationBlock;
engagemang: OpsEngagementBlock;
betalning: OpsPaymentBlock;
jobb: OpsQueueBlock;
sakerhet: OpsSafetyBlock;
as_of: string;
}