# Phase 5 & 6 — Usability, Compliance Hardening, Analytics ## Context Phases 0–4 complete. Gap audit against PRD (`docs/01_PRD_HSE_Incident_Management_System.md`) found 10 specced features missing or partial. User approved all four gap groups: core usability, compliance hardening, evidence UX, and analytics. Split into **Phase 5** (usability + compliance + evidence) and **Phase 6** (analytics/AI), matching the existing phase-plan convention in `docs/superpowers/plans/`. Verified current state (Explore audit, 2026-07-11): - `notifications_log` table exists (`supabase/migrations/20260709000006_notifications_audit.sql`) — no UI - `app/(protected)/admin/page.tsx` is a stub - `app/api/incidents/[id]/route.ts` has no PATCH; no closure lock - `app/api/incidents/[id]/jkkp-pdf/route.ts` supports jkkp6/jkkp7 only; `lib/incidents/dosh.ts:45` already computes `requires_jkkp8` - `components/incidents/report-form.tsx` branches only on `injury_involved` - Investigation schema has `alcohol_test_result`, `witness_statement_refs` (`migrations/...004:27-28`) — no UI - `app/(protected)/hse/incidents/page.tsx:18` hard `.limit(100)`, no pagination - `lib/supabase/storage.ts` stores SHA-256 `file_hash`; no thumbnails - Dashboard has type/site breakdown + zone heatmap; no time-series, no root-cause trend ## Conventions to follow (established, do not deviate) - Every DB mutation writes `audit_log`; RLS at DB level for all new tables/columns - AI routes: `claude-opus-4-8`, `thinking: {type:"adaptive"}`, forced `tool_choice`, validate tool output, 503 on model failure; `getApiKey(supabase, key)` (`lib/settings.ts`) before client construction (`lib/claude/client.ts`) - Notifications: reuse `lib/notifications/email.ts`, `lib/notifications/whatsapp.ts` - i18n: add strings to `lib/i18n/locales.ts` (EN/MS/ZH) - Client fetches prefixed `/ims` basePath - TDD per repo practice; tests in `tests/` mirroring lib paths (61 passing currently) --- ## Phase 5 — Usability & Compliance Completion ### Task 1: In-app notification bell + badge - Migration: extend `notifications_log` if needed (add `read_at TIMESTAMPTZ`, index on recipient+read) - `app/api/notifications/route.ts` — GET unread list (RLS: own rows), POST mark-read - `components/notifications/bell.tsx` — badge count, dropdown list; mount in `app/(protected)/layout.tsx` - Write in-app rows at the same points email/WhatsApp fire (new incident, CAPA assign/escalate, verification) ### Task 2: Admin user + site/zone management - Replace stub `app/(protected)/admin/page.tsx` - User list: invite (Supabase admin API server-side), role assign, deactivate — admin-only RLS + server-side role check via `lib/auth/roles.ts` - Site/zone CRUD against `sites`/`zones` tables (migration 001) - All mutations audit-logged ### Task 3: Incident closure lock + addenda - Migration: `incident_addenda` table (incident_id, author, body, created_at) with RLS - Add PATCH guard in `app/api/incidents/[id]/route.ts` and triage/investigation/capa routes: reject mutation when `closed_at IS NOT NULL` (DB trigger preferred — belt and braces) - Addenda UI on `components/incidents/incident-detail.tsx` for closed incidents ### Task 4: JKKP 8 annual register export - `lib/pdf/jkkp8.ts` (or Excel via existing export route pattern `app/api/dashboard/export/route.ts`) — annual register of all reportable incidents for a chosen year - `app/api/reports/jkkp8/route.ts` — HSE/admin only; reuse `lib/incidents/dosh.ts` flags - Download button on HSE dashboard; reminder banner in January while register unsubmitted ### Task 5: Type-specific intake forms - Extend `components/incidents/report-form.tsx`: conditional field groups per type — environmental (spill volume/substance/containment), MHE/asset (equipment id, LOTO applied), security, fire; near-miss stays minimal by design - Store in existing JSONB detail column if present, else migration adds one - Validate in `lib/incidents/validate.ts`; translate new labels ### Task 6: Witness statement + alcohol test UI - Add fields to `components/incidents/investigation-form.tsx` wired to existing `alcohol_test_result`, `witness_statement_refs` columns - Witness statement file uploads reuse `components/incidents/file-upload.tsx` with stage tag ### Task 7: Incident list pagination - Server-side range pagination in `app/(protected)/hse/incidents/page.tsx` + `components/incidents/incident-list.tsx` (searchParams page/pageSize, `.range()`, count) - Same for supervisor incident list ### Task 8: Evidence thumbnails - Supabase Storage image transform (`getPublicUrl` with `transform: {width}`) for image types in `components/incidents/evidence-gallery.tsx`; icon fallback for video/pdf/doc - No new infra if Supabase transform available on plan; else client-side `next/image` sizing of signed URL ### Task 9: Housekeeping - Delete stray duplicates `lib/notifications/whatsapp 2.ts`, `tests/lib/notifications/whatsapp.test 2.ts` (verify identical/stale vs canonical first) --- ## Phase 6 — Analytics & Predictive Safety ### Task 1: Dashboard time-series - Extend `app/api/dashboard/stats/route.ts`: monthly incident counts by type (12 mo), leading vs lagging trend, CAPA on-time trend - Chart components on `app/(protected)/hse/dashboard/page.tsx` (lightweight — no heavy chart lib unless one already present) ### Task 2: Top root cause trended - Aggregate `root_cause_category` (phase-2 RCA data) by month; top-5 table + trend on dashboard ### Task 3: AI rising-risk heatmap - `app/api/dashboard/ai/risk-flags/route.ts` — server-side Claude call per AI-route conventions; input: 90d near-miss + incident + zone aggregates; output: flagged zones/shifts with rationale (forced tool_use schema) - Panel on management + HSE dashboards, clearly labelled as AI suggestion; log suggestion to `audit_log` per convention --- ## Verification - `npm test` — all existing 61 tests plus new unit tests per task (escalation-style pattern in `tests/lib/`) - Manual: run app, walk lifecycle — report (each type) → triage → investigate (witness/alcohol) → CAPA → verify → close → confirm lock + addenda; bell badge increments; admin creates user + zone; JKKP 8 downloads; pagination past 100 rows (seed if needed) - `graphify update .` after code changes - Update `docs/superpowers/plans/` with phase-5/6 plan docs and memory `phases.md` on completion --- ## Completion Record (2026-07-12) All Phase 5 and Phase 6 tasks implemented on branch `phase-5-6`. 112 tests passing (23 files), `tsc --noEmit` clean, `next build` clean. Notable deviations/additions vs plan: - Incident **close endpoint did not exist at all** — added `POST /api/incidents/[id]/close` (verification status + all CAPAs verified required) alongside the lock. - In-app notification inserts go through `create_in_app_notification` SECURITY DEFINER RPC (reporters are not covered by the elevated INSERT policy). - Fixed 9 pre-existing missing `/ims` basePath prefixes across fetch calls and download links (similar-incidents-panel, investigation-form ×3, triage-form ×2, verify-form, JKKP PDF links ×2, dashboard/management export links). - New migrations: 20260712000016_in_app_notifications, 20260712000017_closure_lock_addenda, 20260712000018_type_details.