8 Commits
Author SHA1 Message Date
tiennm99 deec3d69c0 feat: add data migration from the original Java BSK SQLite database
npm run db:migrate-upstream imports a BSK.db file into the bsk schema via
node:sqlite: re-keys all ids, maps shift 0/1 to morning/afternoon, converts
RTF template content to field labels, keeps pre-1970 birth dates, folds
suggestion/service-notes/ultrasound-doctor into visit notes, and warns on
every dropped or unmappable value. Pure transforms live in
scripts/upstream-transforms.mjs with a unit suite. Also grants service_role
the table privileges PostgREST needs for this and the existing seed scripts.
2026-08-18 20:41:31 +07:00
tiennm99 2b1298eeb8 build: replace TypeScript toolchain with strict checkJs JS setup
- one strict checkJs jsconfig.json replaces tsconfig.json (keeps
  noUncheckedIndexedAccess); typecheck script now tsc -p jsconfig.json
- next.config.ts -> next.config.mjs; vitest/playwright configs -> .js
- db scripts run under plain node as .mjs; tsx devDep removed
- generated Supabase types move to types/supabase-bsk.d.ts and
  db:gen-types redirects there
- eslint drops eslint-config-next/typescript, adds eslint-plugin-jsdoc;
  factory-boundary no-restricted-imports globs now target .js
2026-08-17 23:12:25 +07:00
tiennm99 a44c9a9745 build: move from pnpm to npm
Replace pnpm-lock.yaml with package-lock.json. Four of the five overrides move
across unchanged, ranges intact.

postcss needed a different shape: npm rejects an override that disagrees with a
direct dependency (EOVERRIDE), and postcss was a devDependency at ^8.5.15 while
the override floored it at >=8.5.18. The devDependency now sits at the advisory
floor and the override references it as $postcss, so transitive copies follow
the same resolution the pnpm override produced.

brace-expansion is still deliberately not overridden. It resolves to 1.1.18 for
eslint's minimatch 3.x chain and 5.0.9 elsewhere; 1.1.18 is a patched 1.x, which
did not exist when the exception was written, so eslint runs clean and the
advisory is gone.

.npmrc held only pnpm-specific settings (verify-deps-before-run,
ignored-build-scripts-status-warn-only) and is removed. db:push, the Playwright
webServer command, and the secret-leak pathspec all referenced pnpm and would
have broken.
2026-08-17 13:42:18 +07:00
tiennm99 7b51fee404 fix(ci): apply Prettier formatting and pin line endings
CI has been red on every push: the workflow runs `pnpm format:check`, which I
never included in local validation (I only gated typecheck/lint/build), so 54
files were committed unformatted.

- ran `pnpm format` — all changes are Prettier line-reflow, no logic touched
  (verified: `git diff -w` flags exactly the same 54 files CI reported)
- added .gitattributes (`* text=auto eol=lf` + binary rules for fonts/images):
  with core.autocrlf and no attributes file, `format:check` counted 141 files
  locally vs 54 in CI, which is what let this slip through

All six CI gates now pass locally in workflow order: secret-leak, format:check,
test (97), lint, typecheck, build.
2026-07-25 15:43:23 +07:00
tiennm99 4273cba2bb feat(patients): patient management with VN geo + accent search (Phase 2 slice)
- bsk.customers (soft-delete) + provinces/wards geo tables; RLS: enrolled
  read, clinical-role write; geo read-only
- accent-insensitive search via unaccent wrapper + search_customers RPC
  (SECURITY INVOKER so RLS applies); name/phone contains
- patients list+search, create, edit; shared form with cascading
  province -> ward dropdown; clinical-role route gate; nav + vi/en
- audit-logged mutations; seed-geo script (db:seed-geo) for the geo dataset
2026-07-25 11:33:40 +07:00
tiennm99 0a08f80450 feat(phase-1): db schema init (bsk_init migration + roles)
- supabase/migrations/20260525163300_bsk_init.sql: bsk schema, app_role
  enum, app_users enrollment table, current_role() SECURITY DEFINER
  STABLE helper, RLS enabled with two SELECT policies (own row + admin)
- types/supabase-bsk.ts: hand-written placeholder mirroring canonical
  supabase gen output; regenerate via pnpm db:gen-types after migration
  applied
- lib/db/roles.ts: appRoles tuple + AppRole union + satisfies guard
  against generated enum + isAppRole type guard
- package.json: db:gen-types script
- README: one-line note on regenerating types after db:push
- plans/: include phase 02/04/06 detail files alongside the existing
  01/03/05 (planner output that wasn't committed with the trim)
2026-05-25 17:23:08 +07:00
tiennm99 eeda68c34a chore(ci): add NEXT_PUBLIC_*=sb_secret_* leak guard
Defense-in-depth check that fails the build (and the local pre-push
workflow) if a server secret value is assigned to a NEXT_PUBLIC_*
variable — those get bundled into the browser by Next.js.

- scripts/check-no-secret-leak.mjs: git grep for the assignment shape,
  excluding lockfiles and the script itself
- package.json: pnpm check:no-secret-leak
- .github/workflows/ci.yml: run the guard right after install, before
  format/lint/typecheck/build
- docs/threat-model.md: close the last Unresolved item
2026-05-25 16:19:43 +07:00
tiennm99 0393ddf6ec docs(infra): add shared-supabase config, restore runbook, threat model, db preflight
- docs/supabase-shared-config.md: registry of project-wide Supabase
  settings (auth, JWT, email, keys, storage, realtime) shared across
  sibling apps; change-coordination protocol
- docs/runbooks/restore-from-bad-migration.md: per-schema recovery via
  pg_dump --schema=bsk that avoids project-wide PITR (which would also
  wipe sibling apps)
- docs/threat-model.md: trust model, sibling-app invite-only policy
  (mitigates auth.users blast radius), R1-R8 residual risks, unresolved
  questions for Phase 1
- scripts/preflight-supabase.ts: refuses 'supabase db push' unless the
  linked project ref is in ALLOWED_PROJECT_REFS; wired via pnpm db:push
- package.json: tsx devDep, db:preflight + db:push scripts
- pnpm-workspace.yaml: allowBuilds esbuild=true (required for tsx)
2026-05-25 15:57:10 +07:00