Files
ims/docs/superpowers/plans/2026-07-11-phase-5-6-usability-compliance-analytics.md
T
adminandClaude Fable 5 576557181a feat: Phase 5 & 6 — usability, compliance hardening, analytics
Phase 5 (usability + compliance):
- In-app notification bell/badge: migration 016 adds read state + per-user
  RLS + create_in_app_notification SECURITY DEFINER RPC; /api/notifications;
  wired into incident creation, CAPA assign/verify, escalation cron
- Incident closure: new POST /api/incidents/[id]/close (requires verification
  status + all CAPAs verified); migration 017 locks closed incidents at DB
  level (update/delete triggers) with append-only incident_addenda + UI panel
- Server-side pagination on HSE/supervisor incident inboxes (.range, 25/page)
- Investigation form: alcohol/urine test result + witness statement refs
  (existing schema columns, now editable)
- Type-specific intake fields: migration 018 adds incidents.type_details
  JSONB; whitelist validation; environmental/asset/security/fire field
  groups in report form; EN/MS/ZH labels; offline queue support
- JKKP 8 annual register CSV export (/api/reports/jkkp8) + dashboard button
  + January statutory deadline banner
- Admin page: user invite (service-role client), role/site/active management,
  site + zone CRUD with QR report links — replaces Phase 0 stub
- Evidence gallery thumbnails via Supabase render transform with fallback

Phase 6 (analytics):
- 12-month stacked trend chart (leading/lagging/other) + top root causes
  (lib/dashboard/trends.ts pure helpers)
- AI rising-risk zones: /api/dashboard/ai/risk-flags aggregates 90-day
  zone stats, claude-opus-4-8 forced tool_use, panel on HSE + management
  dashboards, suggestion audit-logged

Also fixes 9 pre-existing missing /ims basePath prefixes in client fetches
and download links.

132 tests passing, tsc clean, next build clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-12 10:25:08 +08:00

7.1 KiB
Raw Blame History

Phase 5 & 6 — Usability, Compliance Hardening, Analytics

Context

Phases 04 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.