Security model

Defense in depth, on by default.

Security isn't a checkbox in the admin — it's the default posture of every route, every query, every CDN URL, and every cron tick.

Row Level Security on every table

Every Supabase table ships with RLS policies. Anonymous reads are scoped, write paths require an authenticated session, and admin paths require the admin role. The service-role key is segregated server-only — never reachable from the browser.

Signed CDN URLs with IP binding

Bunny token-authed URLs are HMAC-signed with short TTLs (6 hours hot, 24 hours thumbnail) and IP-bound on the hot tier. Hotlinking and credential leakage stop being someone else's problem.

Role-gated routes, top to bottom

lib/auth/require-admin.ts and lib/auth/require-uploader.ts gate every privileged route. Cron endpoints require a bearer token via lib/auth/verify-cron-bearer.ts. CSRF-safe server actions everywhere.

Rate limiting where it counts

Auth flows are rate-limited via lib/auth/auth-rate-limit.ts. License verify is unlimited on the happy path but abuse-throttled on failures. Bulk-import URLs go through a guard that blocks SSRF targets.

Audit log + env audit

Every admin mutation lands in the audit log. The env-var audit script catches drift between the .env.example contract and what your tenants are actually running.

The full inventory

Every line below is real code. Hover into the source to see how it's wired.

  • Row Level Security on every Supabase table
  • Service-role key segregated server-only
  • Signed Bunny URLs (HMAC, IP-bound on hot tier)6h hot / 24h thumbnail TTLs
  • CSRF-safe server actions
  • Auth rate limitinglib/auth/auth-rate-limit.ts
  • Cron bearer authlib/auth/verify-cron-bearer.ts
  • Admin role gatelib/auth/require-admin.ts
  • Uploader role gatelib/auth/require-uploader.ts
  • Safe-redirect guard
  • URL guard for bulk imports
  • Audit log on all admin mutations
  • Env-var audit script

Operator responsibility. We ship the controls. You configure the secrets, the firewall, the WAF, and the backup posture. The operator-tooling page covers the day-2 surface.