Security & Data Model
Resoproof is built on a layered security model: tenant isolation enforced at the database, append-only evidence integrity, private storage, and no sensitive-data leakage into the event log.
Tenant isolation (Row Level Security)
Every table carries a firm_idcolumn. Supabase Row Level Security policies enforce that every SELECT, INSERT, UPDATE, and DELETE is scoped to the authenticated user's firm. There is no API path that can return another firm's data.
Append-only event log
The events table has database-level triggers that raise an exception on any UPDATE or DELETE. No application code — including staff with admin access — can alter or remove an event after it is written. This is enforced in PostgreSQL, not in application middleware.
Hash chain integrity
Each event stores the SHA-256 hash of its predecessor (prev_hash) and its own canonical hash. The verify_event_chain database function re-walks the chain and recomputes every hash server-side. If any event was altered or deleted outside the trigger system, the chain breaks and the record reports it.
Private storage & signed URLs
Client uploads go into a private Supabase Storage bucket called client-uploads. No object in this bucket is publicly accessible. Downloads are served exclusively through short-lived signed URLs generated server-side per request. The signed URL expires and becomes useless once the validity window passes.
Client portal tokens
Secure links sent to clients contain a high-entropy (32-byte) random token. Only its SHA-256 hash is stored in the database — the raw token never persists. Tokens have an expiry (default 30 days) and can be revoked by staff at any time. Each action the client takes on the portal is validated against the token server-side before any database write occurs.
Sensitive data discipline
SSNs, EINs, and other sensitive identifiers are never written to the event log or the uploads metadata table. The event log carries only structural facts: what happened, when, to which item, by which actor. Actual document content lives only in the private storage bucket.
Staff authentication
Staff log in via Supabase Auth (email + password). Sessions use rotating JWTs managed by Supabase. The middleware refreshes the session on every request and redirects unauthenticated users to the login page before any console route is served.