Skip to content

Supabase Auth Rollout

Document the current Supabase auth implementation across the emergent apps and the next rollout steps that are already agreed.

  • emergent is a self-hosted Supabase app. auth.users, GoTrue session handling, Supabase auth hooks, and Supabase recovery and invite flows are first-class dependencies.
  • public.person and public.person_profile are materialized from auth.users rather than maintained as a separate identity system.
  • public.person_role_grant remains the authorization source of truth.
  • Active grants are projected into auth.users.raw_app_meta_data.authorization, and frontend, API, and RLS code consume structured AuthorizationClaims rather than coarse role arrays.
  • Project-owned auth.* helper tables and replacement token flows are out of scope unless Supabase behavior forces a gap.
  • packages/domain owns the cross-app Supabase browser auth primitives: required public env resolution, cached browser client bindings, auth snapshot helpers, access-token loading, and error normalization.
  • packages/ui owns the shared React auth layer: createSupabaseAuthBindings, AuthLoginScreen, AuthResetPasswordRequestScreen, AuthSetPasswordScreen, and the shared useSupabaseSetPasswordFlow recovery hook.
  • apps/learner-web, apps/teacher-portal, and apps/admin-console keep only app-local theme, access-policy, and route-guard concerns on top of those shared layers.
  • All three apps now use the same shared provider factory, the same shared login and reset-password request screens, and the same shared /set-password recovery-completion flow.
  • apps/admin-console now includes the shared portal invite UI. It sends Supabase invites for teacher-portal staff roles (teacher, assistant, observer, mentor) plus admin-console roles (organization_admin, platform_admin), lets platform admins choose or manually enter organization scope when they are not pinned to a single organization, and supports offering-scoped teacher-role invites when access needs to be limited below the organization level.
  • apps/learner-web keeps self-serve signup.
  • apps/teacher-portal and apps/admin-console remain invite-only. Their login and reset request routes exist, but they do not expose self-serve account creation.
  • Password reset emails now redirect back into each app’s public /set-password route, which restores the Supabase recovery session and completes password changes through auth.updateUser(...).
  • packages/db migrations preserve the Supabase-auth-centered model: auth-hook materialization, authorization claim projection, and claim-aware RLS on mutable sync tables.
  • apps/api verifies bearer tokens against Supabase, preserves app_metadata, and builds request claims from the projected authorization structure.
  • apps/api now exposes an authenticated /workflow/invites path for the shared portal invite flow. It uses the Supabase admin invite API, supports organization-scoped and offering-scoped teacher-role invites plus organization-admin and platform-admin invites, validates that offering-scoped invites stay attached to the selected organization, and immediately creates the matching person_role_grant row so claim projection can populate raw_app_meta_data.authorization.
  • Mutation ingress continues to use the Supabase-hosted functions path and forwards claim-enriched auth into the pgxsinkit artifact-mode write path.
  • Auth email rendering is handled through the existing send-email hook surface in apps/api/src/email/templates.ts for signup, recovery, invite, magic link, and change-email flows.
  • packages/domain: auth contracts and browser auth helpers
  • packages/ui: shared auth providers and screens
  • packages/db: Supabase auth hook migrations, claim projection, and claim-aware RLS
  • apps/api: Supabase token verification and auth email templates
  • apps/learner-web: learner signup and learner-specific post-login routing
  • apps/teacher-portal: teacher access-policy checks and invite-only gating
  • apps/admin-console: admin access-policy checks and invite-only gating
  1. Add integration coverage for the default Supabase-backed /workflow/invites path so offering-scoped invites are exercised against real public.offering data and grant projection, not only route-level mocks.
  2. Replace the current claim-derived and manual organization/offering inputs with canonical admin-console catalog pickers once that directory data is available in the portal.
  3. Revisit pgxsinkit generalization only after the emergent Supabase-first flow is stable and validated.