/** * Water Log — small audit + alert helpers. * * Every mutating action in `actions/water-log/*` calls `logAuditEvent()` * so a regulator or curious admin can answer "who deleted that headgate * on Tuesday" without trawling server logs. */ import "server-only"; import { query } from "@/lib/db"; import { withBrand } from "@/db/client"; export type WaterAuditEvent = { brandId: string; actorLabel: string; actorId?: string | null; action: string; entityType: "headgate" | "user" | "entry" | "settings" | "session"; entityId?: string | null; details?: Record | null; }; /** * Fire-and-forget audit insert. The withBrand wrapper sets the brand * context so RLS lets the write through. We swallow errors so a broken * audit log never blocks the user-facing action — but we always log to * the console as a backstop. */ export async function logAuditEvent(ev: WaterAuditEvent): Promise { try { await withBrand(ev.brandId, async () => { await query( `INSERT INTO water_audit_log (brand_id, actor_id, actor_label, action, entity_type, entity_id, details) VALUES ($1, $2, $3, $4, $5, $6, $7)`, [ ev.brandId, ev.actorId ?? null, ev.actorLabel, ev.action, ev.entityType, ev.entityId ?? null, ev.details ? JSON.stringify(ev.details) : null, ], ); }); } catch (err) { // Audit must not break the user flow. Surface to console. console.error("[water-log] audit insert failed", err, ev); } } /** * Log a high/low water alert. Currently this is a passive record — the * scheduled job that actually sends SMS/WhatsApp can pick rows where * `sent_at IS NULL`. Phase 2 wires up the sender. */ export async function logAlert(args: { brandId: string; headgateId: string | null; alertType: "high" | "low"; reading: number; threshold: number; headgateName: string; }): Promise { try { await withBrand(args.brandId, async () => { await query( `INSERT INTO water_alert_log (brand_id, alert_type, headgate_id, message) VALUES ($1, $2, $3, $4)`, [ args.brandId, args.alertType, args.headgateId, `${args.alertType.toUpperCase()} alert on ${args.headgateName}: reading ${args.reading} crossed threshold ${args.threshold}`, ], ); }); } catch (err) { console.error("[water-log] alert insert failed", err, args); } }