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
7.1 KiB
7.1 KiB
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_logtable exists (supabase/migrations/20260709000006_notifications_audit.sql) — no UIapp/(protected)/admin/page.tsxis a stubapp/api/incidents/[id]/route.tshas no PATCH; no closure lockapp/api/incidents/[id]/jkkp-pdf/route.tssupports jkkp6/jkkp7 only;lib/incidents/dosh.ts:45already computesrequires_jkkp8components/incidents/report-form.tsxbranches only oninjury_involved- Investigation schema has
alcohol_test_result,witness_statement_refs(migrations/...004:27-28) — no UI app/(protected)/hse/incidents/page.tsx:18hard.limit(100), no paginationlib/supabase/storage.tsstores SHA-256file_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"}, forcedtool_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
/imsbasePath - 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_logif needed (addread_at TIMESTAMPTZ, index on recipient+read) app/api/notifications/route.ts— GET unread list (RLS: own rows), POST mark-readcomponents/notifications/bell.tsx— badge count, dropdown list; mount inapp/(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/zonestables (migration 001) - All mutations audit-logged
Task 3: Incident closure lock + addenda
- Migration:
incident_addendatable (incident_id, author, body, created_at) with RLS - Add PATCH guard in
app/api/incidents/[id]/route.tsand triage/investigation/capa routes: reject mutation whenclosed_at IS NOT NULL(DB trigger preferred — belt and braces) - Addenda UI on
components/incidents/incident-detail.tsxfor closed incidents
Task 4: JKKP 8 annual register export
lib/pdf/jkkp8.ts(or Excel via existing export route patternapp/api/dashboard/export/route.ts) — annual register of all reportable incidents for a chosen yearapp/api/reports/jkkp8/route.ts— HSE/admin only; reuselib/incidents/dosh.tsflags- 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.tsxwired to existingalcohol_test_result,witness_statement_refscolumns - Witness statement file uploads reuse
components/incidents/file-upload.tsxwith 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 (
getPublicUrlwithtransform: {width}) for image types incomponents/incidents/evidence-gallery.tsx; icon fallback for video/pdf/doc - No new infra if Supabase transform available on plan; else client-side
next/imagesizing 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_logper convention
Verification
npm test— all existing 61 tests plus new unit tests per task (escalation-style pattern intests/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 memoryphases.mdon 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_notificationSECURITY DEFINER RPC (reporters are not covered by the elevated INSERT policy). - Fixed 9 pre-existing missing
/imsbasePath 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.