admin and Claude Sonnet 4.6
98f5c4e421
feat(db): phase 4 group 3 — incident routes to Drizzle
...
Convert all 11 incident API routes from Supabase PostgREST to Drizzle
ORM with withUser/asAdmin/writeAuditLog patterns and RLS enforcement.
Only uploadEvidenceFile retains supabase client (Phase 5 storage work).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-23 16:57:01 +08:00
admin and Claude Sonnet 4.6
25f923f530
feat(db): phase 4 group 1 — lib/ settings + notifications to Drizzle
...
Convert lib/settings.ts, lib/notifications/{in-app,email,capa-escalation,
effectiveness-recheck}.ts from Supabase PostgREST to Drizzle asAdmin queries.
Drop supabase arg from all call sites in app/api/ and cron routes. Rewrite
notification unit tests to mock @/lib/db/with-user instead of SupabaseClient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-23 16:37:51 +08:00
admin and Claude Sonnet 4.6
d18d29168a
feat(auth): phase 3 — replace Supabase GoTrue with bcryptjs+jose
...
Custom auth stack: bcryptjs password hashing (cost 10, GoTrue-compatible),
jose JWT session cookies (edge-safe, 8hr TTL), new API routes for
login/logout/reset/change-password, middleware rewritten to JWT-only
verification with no DB access. All 38 protected pages and API routes
migrated from supabase.auth.getUser() to getSession(). Supabase .from()
queries retained for Phase 4. lib/db/index.ts refactored to lazy Proxy
singleton to avoid module-level throw during Next.js build.
tsc: clean, build: clean, tests: 4/4 passed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-23 16:20:04 +08:00
admin and Claude Sonnet 4.6
690485f74e
feat: delete + deactivate for sites, zones, and trucks; harden incident API error handling
...
- zones: add active column (migration 20260713000005)
- sites/zones API: PATCH (toggle active) + DELETE (blocked when incidents reference it)
- trucks API: PATCH + DELETE with same pattern
- admin page: select active for sites + zones
- site-zone-manager + truck-manager: deactivate toggle + delete button per row with busyId
- incidents API: reject reports on deactivated zone/site; wrap handler in top-level try-catch so unhandled errors return JSON (not HTML)
- report-form: parse JSON separately so HTTP status code surfaces instead of generic "Something went wrong"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-13 16:05:36 +08:00
admin and Claude Sonnet 4.6
f90bf4ed03
feat: transport incidents with truck number support
...
- DB: trucks table + incidents.truck_id FK + transport enum value
- Validation: transport type requires truck_id
- Create API: validates truck exists/active, persists truck_id
- Report form: truck dropdown shown when type=transport (required)
- Admin: TruckManager CRUD + /api/admin/trucks route
- Detail: trucks join surfaced in incident-detail + detail page query
- Inbox (HSE + supervisor): truck filter, transport in TYPE_OPTIONS,
fixed stale enum values (dropped dangerous_occurrence/mhe_asset/occupational_disease)
- List: transport label + truck number badge in rows
- i18n: transport + truckLabel/truckPlaceholder in en/ms/zh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-13 10:56:07 +08:00
admin and Claude Sonnet 4.6
d10c690c12
feat: switch embeddings from Voyage AI to Google Gemini text-embedding-004
...
- embedText: call Gemini REST API (768-dim) instead of Voyage (1024-dim)
- Migration: drop+recreate incidents.embedding as vector(768), update
match_incidents function, swap VOYAGE_API_KEY → GOOGLE_AI_API_KEY in app_settings
- Settings UI: relabel to "Google AI API Key (Embeddings)"
- All call sites updated (incidents POST, similar GET)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-13 06:50:35 +08:00
admin and Claude Sonnet 4.6
16dd62df11
fix: P1 API security hardening — rate limits, auth guards, duplicate prevention
...
- verify/route.ts: setDate → setUTCDate to avoid timezone off-by-one on recheck date
- triage-suggest, rca-draft, quality-check: 60s per-user rate limit via audit_log
- quality-check: add write_audit_log (was missing, CLAUDE.md violation)
- investigation POST: 409 if investigation already exists for incident
- incidents POST: 60s per-user rate limit via audit_log
- addenda GET: restrict to hse/admin/supervisor roles
- dashboard/stats GET: restrict to hse/admin/management roles
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-12 20:47:32 +08:00
admin and Claude 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
admin and Claude Sonnet 4.6
a47f3aabc9
feat: WhatsApp notifications — new incident alert and CAPA overdue escalation
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 18:50:25 +08:00
admin and Claude Sonnet 4.6
b9ab94c9da
feat: API key settings page — store ANTHROPIC/VOYAGE keys in DB with admin UI
...
- Migration: app_settings table with admin-only RLS (ANTHROPIC_API_KEY, VOYAGE_API_KEY)
- lib/settings.ts: getApiKey() reads DB first, falls back to env var
- lib/claude/client.ts: factory createAnthropicClient(apiKey) replaces singleton
- lib/claude/embed.ts: optional apiKey param, falls back to env
- 3 Claude AI routes + similar route: fetch key from settings before calling AI
- incidents/route.ts: fire-and-forget embed reads VOYAGE key from settings
- GET/POST /api/settings: admin-only masked key management endpoint
- /hse/settings page + ApiKeyForm client component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 17:46:40 +08:00
admin and Claude Sonnet 4.6
547cc6e817
feat: pgvector similar-incident retrieval + SimilarIncidentsPanel
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 16:31:02 +08:00
admin and Claude Sonnet 4.6
ed14885253
fix: replace any casts with typed casts for Supabase join results
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
2026-07-11 07:52:53 +08:00
admin
2239b6e2df
feat: email notifications via Resend on new incident
2026-07-10 13:24:44 +08:00
admin
3f8da5bd91
feat: incident report form, API route, middleware shared-route + redirect
2026-07-10 13:19:45 +08:00