- set_staff_role/remove_staff guards were NULL-unsafe: an authenticated but
unenrolled principal (possible on the shared auth pool) skipped the RAISE
and could promote or delete staff; rewritten with the null-safe form.
- Report/prescription PDFs now require a clinical role and the invoice PDF a
staff role, matching the screens that link to them; the role sets live in
lib/db/roles.js and are shared by layouts, actions, and route handlers.
- Storage policies on bsk-checkup-media scoped to clinical roles.
- Billing RPCs serialize on a per-checkup advisory lock so a line rewrite can
never commit after payment; mark_order_paid rejects deleted checkups and
zero-line invoices.
- PDF customer lookups skip soft-deleted patients; invite rate limiter fails
closed (SMTP spend is irrecoverable); patient search escapes LIKE wildcards.
- app/, components/, lib/, i18n/, tests/, proxy renamed via git mv
- types carried into JSDoc: @template generics, @typedef aliases,
/** @type */ casts where TS had as-casts or non-null assertions
- role tuple keeps its const assertion; the db-enum drift guard now
checks the tuple values against the generated enum type
- use client/use server directives and server-only imports preserved
- prettier-formatted; vitest suite unchanged