import { eq, and, gte, lte, desc } from "drizzle-orm"; import { kpiSnapshots } from "../../db/schema"; import type { DrizzleDB } from "../../db/config/migrations"; import type { NewKPISnapshot, KPISnapshot } from "../../db/schema"; export type KPIKey = | "mau" | "paying_users" | "mrr" | "conversion_rate" | "churn_rate" | "cac" | "ltv" | "nps" | "viral_coefficient"; export const KPI_THRESHOLDS: Record = { mau: { warning: 1000, critical: 500, direction: "higher" }, paying_users: { warning: 100, critical: 50, direction: "higher" }, mrr: { warning: 5000, critical: 2000, direction: "higher" }, conversion_rate: { warning: 2, critical: 1, direction: "higher" }, churn_rate: { warning: 5, critical: 3, direction: "lower" }, cac: { warning: 12, critical: 15, direction: "lower" }, ltv: { warning: 100, critical: 80, direction: "higher" }, nps: { warning: 40, critical: 20, direction: "higher" }, viral_coefficient: { warning: 0.3, critical: 0.1, direction: "higher" }, }; export async function recordKPI( db: DrizzleDB, kpiKey: KPIKey, value: number, periodStart: Date, periodEnd: Date, metadata?: Record ): Promise { const snapshot: NewKPISnapshot = { kpiKey, kpiValue: value, periodStart, periodEnd, metadata: metadata ? JSON.stringify(metadata) : null, }; const result = await db.insert(kpiSnapshots).values(snapshot).returning(); return result[0]!; } export async function getLatestKPI( db: DrizzleDB, kpiKey: KPIKey ): Promise { const rows = await db .select() .from(kpiSnapshots) .where(eq(kpiSnapshots.kpiKey, kpiKey)) .orderBy(desc(kpiSnapshots.createdAt)) .limit(1); return rows[0]; } export async function getKPIHistory( db: DrizzleDB, kpiKey: KPIKey, periodStart?: Date, periodEnd?: Date ): Promise { const conditions: import("drizzle-orm").SQL[] = [eq(kpiSnapshots.kpiKey, kpiKey)]; if (periodStart) { conditions.push(gte(kpiSnapshots.periodStart, periodStart)); } if (periodEnd) { conditions.push(lte(kpiSnapshots.periodEnd, periodEnd)); } return await db .select() .from(kpiSnapshots) .where(and(...conditions)) .orderBy(kpiSnapshots.periodStart); } export async function getAllLatestKPIs(db: DrizzleDB): Promise> { const result: Record = {} as Record; const keys = Object.keys(KPI_THRESHOLDS) as KPIKey[]; for (const key of keys) { result[key] = await getLatestKPI(db, key); } return result; } export function checkKPIAgainstThreshold( kpiKey: KPIKey, value: number ): { breached: boolean; severity: "warning" | "critical" | null } { const thresholds = KPI_THRESHOLDS[kpiKey]; if (!thresholds) return { breached: false, severity: null }; const { warning, critical, direction } = thresholds; const isHigher = direction === "higher"; if (isHigher) { if (value <= critical) return { breached: true, severity: "critical" }; if (value <= warning) return { breached: true, severity: "warning" }; } else { if (value >= critical) return { breached: true, severity: "critical" }; if (value >= warning) return { breached: true, severity: "warning" }; } return { breached: false, severity: null }; } export function getKPIStatus( kpiKey: KPIKey, value: number ): "healthy" | "warning" | "critical" { const { breached, severity } = checkKPIAgainstThreshold(kpiKey, value); if (!breached) return "healthy"; return severity === "critical" ? "critical" : "warning"; }