Skip to main content

The active company is in-memory only

useCompanyContext (src/hooks/useCompanyContext.tsx) holds activeCompanyId in a plain useStatenot persisted to localStorage, URL, or the session. On a page refresh it resets to null.

This tiny decision combines with others to produce outsized effects:

  • Audit logging silently stops. case_audit_events inserts in useChecklistOperations are guarded by if (companyId); after a refresh companyId is null, so the user keeps working while nothing is logged (audit not court-grade).
  • The /admin route changes identity. For a super-admin with no active company, Dashboard returns <Companies /> instead of the dashboard; the same URL renders different pages depending on lost in-memory state.
  • Super-admins are bounced. AdminLayout force-redirects a super-admin with no active company to /admin for any route outside a hardcoded allow-list (["/admin", "/admin/companies", "/admin/settings"]).

Regular users don't feel it because they fall back to primaryCompanyId, but that has its own hazard (role is global-max).

The tacit assumption: the SPA is never reloaded mid-session.

Rebuild implication

Persist the active-tenant selection (URL segment is best — it makes tenancy explicit, bookmarkable, and server-checkable) and never make audit or authorization depend on transient client state.