Commit Graph
151 Commits
Author SHA1 Message Date
admin dbc66460c4 fix(dashboard): include all CAPAs in on-time rate, count open+not-overdue as on-time 2026-07-28 16:36:57 +08:00
admin 87251b3fc6 fix(dashboard): compute CAPA overdue count from due_date instead of status field 2026-07-28 16:31:45 +08:00
admin 1103d842d5 fix(deploy): use sudo for systemctl restart ims 2026-07-28 16:26:58 +08:00
admin 6b427b840d fix(capa): compute overdue status at render time in CAPA board page 2026-07-28 16:21:23 +08:00
admin 46d82df377 fix(capa): advance incident status to capa_pending on CAPA creation 2026-07-28 15:54:47 +08:00
adminandClaude ed2a2f65e4 fix: switch AI endpoints from tool-calling to JSON output mode
DeepSeek v4-pro reasoning model rejects tool_choice parameter.
All 4 endpoints now use system prompts with JSON schema
instructions and parse content as JSON instead of tool_calls.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-26 10:49:44 +08:00
adminandClaude 7bf3b6a409 fix: rename deepseek model from deepseek-chat to deepseek-v4-pro
DeepSeek API deprecated deepseek-chat model. Returns error:
'the supported API model names are deepseek-v4-pro or deepseek-v4-flash'

Affected all 4 AI endpoints:
- risk-flags (90-day dashboard)
- triage-suggest
- rca-draft
- quality-check

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-26 10:17:26 +08:00
admin 6a2551546d fix: log DeepSeek error in risk-flags catch block 2026-07-25 22:08:18 +08:00
adminandClaude Sonnet 4.6 9c67014bb9 fix(audit): wrap admin + capa mutations with their audit writes in single transactions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-24 06:44:05 +08:00
adminandClaude Sonnet 4.6 8acca41ca1 docs: phase 9 — update vps-cron.md, add cutover runbook
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-24 06:35:15 +08:00
adminandClaude Sonnet 4.6 b3811b3633 feat(ops): phase 8 — data migration scripts + fix password_reset_tokens in schema.sql
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-24 06:30:34 +08:00
admin 04c36f9d45 fix(sw): remove dead pathname startsWith('/') guard after basePath drop 2026-07-23 22:34:20 +08:00
adminandClaude Sonnet 4.6 0389d6091a fix(config): phase 7 follow-up — fix remaining /ims/ occurrences in sw.js, notifications, components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 22:32:11 +08:00
adminandClaude Sonnet 4.6 9d047e168f feat(config): phase 7 — drop /ims basePath, update all hardcoded paths, refresh env spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 22:27:46 +08:00
adminandClaude Sonnet 4.6 d785d86636 feat(email): phase 6 — replace Resend with Brevo transactional email
Removes resend npm dependency. Adds lib/notifications/mailer.ts with a
raw-HTTP Brevo wrapper (sendEmail + sendPasswordResetEmail). All three
notification files updated to use the new wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 22:20:12 +08:00
admin 186c732ac0 fix(storage): add X-Content-Type-Options: nosniff to evidence serve route 2026-07-23 22:16:47 +08:00
adminandClaude Sonnet 4.6 e5f74c367d feat(storage): phase 5 — replace Supabase storage with local filesystem + HMAC evidence serving
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 22:14:54 +08:00
adminandClaude Sonnet 4.6 dacc1a5265 fix(db): phase 4 group 6 — session guard, type safety, SQL filter fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 17:33:48 +08:00
adminandClaude Sonnet 4.6 f591c0be18 feat(db): phase 4 group 6 — server component pages to Drizzle
Converts all 18 server component page files from Supabase client queries
to Drizzle ORM using asAdmin. Adds getSession() + redirect to the three
pages (hse/incidents, hse/incidents/[id], hse/dashboard) that lacked it.
Maps snake_case component prop shapes explicitly where required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 17:29:22 +08:00
adminandClaude Sonnet 4.6 c2db693d9f feat(db): phase 4 group 5 — dashboard/reports/settings/notifications/users routes to Drizzle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 17:13:51 +08:00
adminandClaude Sonnet 4.6 853675118d feat(db): phase 4 group 4 — CAPA routes to Drizzle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 17:05:58 +08:00
adminandClaude 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
adminandClaude Sonnet 4.6 d234ebf916 feat(db): phase 4 group 2 — admin routes to Drizzle
Convert app/api/admin/sites, trucks, users from Supabase PostgREST to
Drizzle ORM. All data ops use asAdmin(); all audit writes use
withUser(session.sub, tx => writeAuditLog(tx, ...)). Zero supabase
imports remain in the three files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 16:44:39 +08:00
adminandClaude 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
adminandClaude 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
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 e5fd2436fa feat(db): consolidated PostgreSQL schema replacing Supabase (Phase 1)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 15:43:09 +08:00
adminandClaude Sonnet 4.6 ba3d345531 feat(ops): add new server runbook and update deploy.sh for ims.setia.com.my
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 15:30:51 +08:00
adminandClaude Sonnet 4.6 509ed90fe7 fix(capa): field-level auth split, status gate, RLS tightening, audit old_value, hide form on pending_verification
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 12:10:53 +08:00
admin 938eb7e08d feat(capa): wire owner notes form into capa-owner page and HSE detail view 2026-07-23 12:00:43 +08:00
admin 5f34dbb644 feat(capa): add CapaOwnerNotesForm component 2026-07-23 11:57:43 +08:00
adminandClaude Sonnet 4.6 96eaeb7aef feat(api): expose owner_notes in capa GET and PATCH
Adds owner_notes to the GET select query and PATCH allowed fields list to enable reading and writing owner notes for CAPA actions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 11:56:10 +08:00
admin 52171ac3ca feat(db): add owner_notes column to capa_actions 2026-07-23 11:53:41 +08:00
adminandClaude Sonnet 4.6 71cf90e1de feat(capa): add Close CAPA button for HSE after verification
Verified CAPAs now show a Close button on the detail page for
HSE/admin, transitioning status to closed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 11:41:56 +08:00
adminandClaude Sonnet 4.6 1a813d54f2 fix(middleware): exclude /api/ routes from role-prefix guard
API routes were being redirected for non-admin roles (e.g. capa_owner
calling PATCH /api/capa/[id] got redirected to /capa-owner, breaking
all API calls from role-restricted users).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WMymkhHZiaYZtUeH9MEHZQ
2026-07-22 20:00:27 +08:00
adminandClaude Sonnet 4.6 0e479b648f fix(auth,capa): restore auth callback, fix CAPA status update
- auth callback: remove debug redirect, handle both code (PKCE) and
  token_hash+type (recovery/magic link) flows correctly
- capa PATCH: use admin client to bypass RLS for status updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WMymkhHZiaYZtUeH9MEHZQ
2026-07-22 19:43:38 +08:00
adminandClaude Sonnet 4.6 4fbab33de4 fix(auth): add forgot/reset to public routes, use Link for basePath, add session guard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WMymkhHZiaYZtUeH9MEHZQ
2026-07-21 22:36:53 +08:00
admin fa88d62375 feat(auth): add reset-password page and login success banner 2026-07-21 22:31:20 +08:00
admin 211117e61a feat(auth): add forgot-password page 2026-07-21 22:29:39 +08:00
admin 4d7ab5d7da feat(auth): add forgot password link to login form 2026-07-21 22:28:26 +08:00
admin 3a5daaa987 docs: add forgot password implementation plan 2026-07-21 22:27:02 +08:00
admin a4b7761f92 docs: add forgot password flow design spec 2026-07-21 22:25:18 +08:00
admin d5803daa67 fix(admin): delete auth user on profile update failure 2026-07-18 18:00:00 +08:00
adminandClaude Sonnet 4.6 33d4dd4b27 feat(admin): remove invite-by-email, direct-add only
Strips invite-by-email mode from admin user management UI and API.
POST /api/admin/users now always requires password parameter for
direct user creation. Removes mode toggle, conditional password field,
and invite logic branches. Simplifies user creation flow to single path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkCfBY9L5y3SZ6uaKZzLCV
2026-07-18 17:48:26 +08:00
admin ac2f0724dd fix: add urine_test_result to supervisor incident detail select 2026-07-17 19:11:11 +08:00
adminandClaude Sonnet 4.6 e30d583947 feat: split alcohol and urine test into separate fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-17 19:08:27 +08:00
admin e687510d0b fix(capa): show all active users in Assigned To dropdown 2026-07-17 19:05:37 +08:00
adminandClaude Sonnet 4.6 a3ce59f2a8 fix(auth): return 503 when NEXT_PUBLIC_APP_URL unset for invite redirectTo
Prevent invite emails from falling back to localhost when NEXT_PUBLIC_APP_URL
is unset in production. Now explicitly checks and rejects with 503.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-17 19:03:58 +08:00
adminandClaude Sonnet 4.6 e682162bbc fix(auth): redirect to appUrl after invite callback
origin lacks /ims basePath; use NEXT_PUBLIC_APP_URL instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzvzV91UqHZKM9P58qtvrA
2026-07-16 21:44:12 +08:00
adminandClaude Sonnet 4.6 b08fec385d fix(capa): filter owner dropdown by capa_owner role
Was filtering by non-null department, excluding capa_owner
users who had no department set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzvzV91UqHZKM9P58qtvrA
2026-07-16 21:12:12 +08:00