import { and, eq } from 'drizzle-orm' import { Hono } from 'hono' import { z } from 'zod' import { updateRootCauseSchema } from '../../shared/schemas.ts' import { requireRole } from '../auth/middleware.ts' import type { SessionUser } from '../auth/sessions.ts' import type { Db } from '../db/client.ts' import { incidents, investigations, rootCauses } from '../db/schema.ts' import { diff } from '../lib/audit.ts' import { currentUser, fail, validate, type AppEnv } from '../lib/http.ts' import { auditIncident, loadDetail } from '../lib/incidents.ts' const idParam = z.object({ id: z.uuid() }) async function findRootCause(db: Db, user: SessionUser, id: string) { const [row] = await db .select({ cause: rootCauses, incidentId: incidents.id, number: incidents.number }) .from(rootCauses) .innerJoin(investigations, eq(investigations.id, rootCauses.investigationId)) .innerJoin(incidents, eq(incidents.id, investigations.incidentId)) .where(and(eq(rootCauses.id, id), eq(incidents.organizationId, user.organizationId))) if (!row) throw fail(404, 'Root cause not found') return row } export const rootCauseRoutes = new Hono() .patch('/:id', requireRole('supervisor'), validate('param', idParam), validate('json', updateRootCauseSchema), async (c) => { const me = currentUser(c) const db = c.get('db') const { cause, incidentId, number } = await findRootCause(db, me, c.req.valid('param').id) const input = c.req.valid('json') const changes = diff(cause, input) if (Object.keys(changes).length > 0) { await db.update(rootCauses).set(input).where(eq(rootCauses.id, cause.id)) await auditIncident(db, me, me.organizationId, incidentId, 'root_cause.update', changes) } return c.json({ incident: await loadDetail(db, me, number) }) }) .delete('/:id', requireRole('supervisor'), validate('param', idParam), async (c) => { const me = currentUser(c) const db = c.get('db') const { cause, incidentId, number } = await findRootCause(db, me, c.req.valid('param').id) await db.delete(rootCauses).where(eq(rootCauses.id, cause.id)) await auditIncident(db, me, me.organizationId, incidentId, 'root_cause.remove', { category: cause.category, description: cause.description }) return c.json({ incident: await loadDetail(db, me, number) }) })