Commit Graph
29 Commits
Author SHA1 Message Date
adminandClaude Sonnet 4.6 a95273b182 feat(db): Drizzle DAL with withUser/asAdmin GUC wrapper (Phase 2)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 15:50:57 +08:00
adminandClaude Sonnet 4.6 6c1ad71643 feat: validate transport incident requires truck_id
Add 'transport' to INCIDENT_TYPES; add truck_id field to IncidentInput;
reject transport submissions missing truck_id.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-13 10:50:13 +08:00
adminandClaude 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
adminandClaude Sonnet 4.6 614c792225 fix(security): VULN-009 magic-byte MIME validation + UTC date fix
- uploadEvidenceFile: validate file type via file-type magic bytes, reject
  client-supplied MIME, derive extension from detected type, upload ArrayBuffer
- getEscalationThreshold: use setUTCHours instead of setHours so date-only ISO
  strings (always UTC midnight) compare consistently in any timezone
- Tests: mock file-type, update upload expectation to ArrayBuffer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-13 06:37:59 +08:00
adminandClaude Sonnet 4.6 b2891a433d feat: switch AI provider from Anthropic to DeepSeek
- lib/claude/client.ts: replace Anthropic SDK with openai package pointed at DeepSeek baseURL
- 4 AI routes: port tool definitions, tool_choice, and output parsing to OpenAI function-calling format
- Drop thinking:{type:'adaptive'} (no DeepSeek equivalent); model string → deepseek-chat
- settings/route.ts: add DEEPSEEK_API_KEY to ALLOWED_KEYS
- migration: seed DEEPSEEK_API_KEY placeholder row in app_settings
- tests: update 3 AI route tests to mock createDeepSeekClient + OpenAI response shape

Voyage AI embedding path untouched (DeepSeek has no embeddings endpoint).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-12 21:51:15 +08:00
adminandClaude Fable 5 81282fbd8a refactor: make generate-qr testable with injectable deps + entry guard
Extracts buildQrUrl and generateZoneQrs with injectable I/O deps and adds
tests/scripts/generate-qr.test.ts (20 tests). Refactor + tests originated
from a concurrent working session; this commit adds on top:
- import.meta entry guard — the unconditional top-level main() executed on
  test import and wrote (sometimes truncated) PNGs into public/qr
- typed vi.fn generics in makeDeps so strict tsc passes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPf5Rc8QPx6V8KLEEgfKEQ
2026-07-12 10:40:38 +08:00
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
admin c048878600 feat: PWA offline capture — IndexedDB queue, service worker cache, auto-sync on reconnect 2026-07-11 19:07:35 +08:00
adminandClaude Sonnet 4.6 87264a5497 feat: i18n — EN/MS/ZH translations with cookie-based locale switching, report form translated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 19:01:44 +08:00
adminandClaude Sonnet 4.6 b9def9c957 feat: CAPA effectiveness re-check cron — 30/60/90-day email + WhatsApp notifications
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 18:55:27 +08:00
admin 76d9363c3c test: RCA draft route test 2026-07-11 18:54:53 +08:00
adminandClaude 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 121433ddf8 Revert "feat: WhatsApp notification helper + phase 4 migration (recheck_round, WhatsApp settings)"
This reverts commit b6845f5bb5.
2026-07-11 18:47:08 +08:00
admin b6845f5bb5 feat: WhatsApp notification helper + phase 4 migration (recheck_round, WhatsApp settings) 2026-07-11 18:43:57 +08:00
adminandClaude 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
adminandClaude Sonnet 4.6 3473cf8ab7 feat: dashboard — leading/lagging, zone heatmap, CAPA on-time rate, DOSH filing status
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 16:38:57 +08:00
adminandClaude Sonnet 4.6 f10fa071f9 feat: AI triage suggestion — severity + DOSH flags pre-fill
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 16:27:29 +08:00
adminandClaude Sonnet 4.6 3bec95aaf8 feat: AI report quality check before submission
Adds POST /api/incidents/ai/quality-check using Claude tool_use to score incident descriptions 1-10. Report form blocks submission when score < 6, shows amber feedback with suggestions, and offers a 'Submit anyway' override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 16:18:39 +08:00
adminandClaude Sonnet 4.6 ebaa98d9f4 feat: Claude client + Voyage AI embed helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 16:10:26 +08:00
adminandClaude Opus 4.8 54332d0297 feat: JKKP 6/7 PDF generation via pdf-lib, download from incident detail
Also excludes node_modules.nosync from vitest test discovery to fix pre-existing bleed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 15:24:18 +08:00
adminandClaude Opus 4.8 75fa2605bf feat: CAPA overdue escalation cron — 4 thresholds, once-per-threshold via notifications_log
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
2026-07-11 15:20:15 +08:00
admin 8b00c72014 feat: DOSH obligation pure function with NADOPOD 2004 rules 2026-07-11 14:51:35 +08:00
adminandClaude Sonnet 4.6 b281420810 feat: HSE dashboard with incident stats by type and site
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
2026-07-11 07:40:22 +08:00
adminandClaude Sonnet 4.6 713556631b feat: incident detail page with evidence gallery for HSE and supervisor roles
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
2026-07-11 07:40:06 +08:00
adminandClaude Sonnet 4.6 2f2018f27a feat: incident inbox pages with filter/search for HSE and supervisor roles
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
2026-07-11 07:39:43 +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
admin a40a0f7c59 fix: signed URLs for private bucket, 10MB server-side limit, safe auth destructuring 2026-07-10 12:00:52 +08:00
admin 8a9758c8a6 feat: Phase 1 foundation - incident components, storage, and migrations 2026-07-10 10:48:56 +08:00