apps/web is the customer-facing governance SPA (Vite + React + Catalyst UI, Tailwind 4) served from Cloudflare Pages at app.policycodex.cloud. It has no server of its own: everything is Clerk (sessions) plus Supabase (PostgREST reads under RLS, SECURITY DEFINER RPCs for actions, two Edge Function invocations).
The web application dashboard: open violations, enforced statement counts, governed domains

C2 slice

Page map

Data-access rules the SPA obeys

  • Reads go through a typed Supabase client pinned to .schema('codex'), with the user’s Clerk JWT — RLS scopes every row to orgs the user is a member of.
  • Mutations that matter (lifecycle transitions, key minting, group changes) are SECURITY DEFINER RPCs that re-check membership and role server-side. UI hiding a button is never the security boundary.
  • Every lifecycle transition writes an audit row; the SPA never writes audit_log directly.
  • Transient feedback goes through one toast layer; errors thrown by RPCs surface as error toasts verbatim — the message a user reports is usually the exact RPC exception text, which makes them easy to grep for in supabase/migrations/.