Identity, tenant scope, capability, and audit all have to agree.
Clientana treats authorization as a chain of independent checks. Operations add health, metrics, backups, release verification, and support evidence without weakening that chain.
Authorization chain
Caddy/TLS, trusted-host rules, CORS, Helmet/CSP, request limits, and secure cookie settings establish the network boundary.
Supabase Auth verifies the user. Browser clients receive only public/publishable configuration; privileged keys remain server-side.
Authenticated writes require a CSRF token tied to the current cookie-based session.
The API resolves the active tenant and checks current membership before any workspace-scoped read or write.
Owner/admin/member or platform-staff permission and the current entitlement determine whether the action is allowed.
Row-level policies protect exposed tables, while the response removes fields the current user, host, or share visitor must not see.
Sensitive administrative operations produce audit/security events and no-cache responses for later review.
Session and secret boundaries
- Authentication and refresh state use HTTP-only cookies rather than JavaScript-readable tokens.
- CSRF tokens protect cookie-authenticated writes.
- Supabase service-role/secret credentials, Stripe secrets, R2 keys, TURN shared secrets, playback signing secrets, and provider API keys never enter public browser bundles.
- User-editable auth metadata is not an authorization source; workspace roles live in application-owned membership records.
- Platform Superadmin access is separate from tenant ownership and uses its own permission, reauthentication, host, audit, and no-cache controls.
Tenant isolation and RLS
- Every workspace resource carries or resolves to a tenant ID.
- API services check membership before returning tenant-owned rows.
- RLS is enabled for tables in exposed schemas, including newer workspace, recording, meeting, enterprise, and support domains.
TO authenticatedis not enough by itself; policies include ownership or membership predicates.- Update policies protect both the current row and the resulting row so callers cannot reassign ownership.
- Privileged database functions are exceptional, scoped, audited, and not placed in an exposed callable surface without explicit revocation and internal authorization.
Public share security
Public sharing is intentionally narrower than workspace access:
- The share ID identifies a public capability, not a tenant session.
- Password-protected shares withhold protected metadata until the password is validated.
- Successful password access uses an HTTP-only share-access cookie.
- Expiry, rotation, unshare, and workspace-plan downgrade can invalidate public access.
- Playback, thumbnails, HLS, downloads, comments, exports, transcript, translation, meeting metadata, branding, and CTA each follow share visibility controls.
- R2 object keys and credentials remain private; delivery uses signed or gateway-authorized URLs.
Meeting security
- Public room creation uses rate limits and proof-of-work anti-abuse.
- The public guest URL and private host URL carry different authority.
- Waiting-room admission remains host-controlled.
- WebSocket upgrade attempts are validated and rate-limited before participant state is created.
- TURN credentials are short-lived and server-generated.
- Host tokens are stored as hashes for persisted rooms.
- Caption persistence is owner-controlled and limited to intervals when capture is enabled.
- Meeting duration is enforced server-side from the creating host’s plan snapshot.
Custom-domain security
Adding a hostname does not authorize it. The flow requires workspace entitlement, admin role, normalized hostname validation, TXT ownership proof, routing verification, and purpose selection. The on-demand TLS endpoint authorizes only verified, currently entitled domains. Record-only and meet-only domains enforce public route guardrails; authenticated app surfaces stay on the primary origin.
Operational controls
Health and metrics
- /health
- /api/internal/health/ops
- /metrics
- structured Pino logs
- Prometheus metrics
- observability runbook
Backups and cleanup
- database backup
- optional R2 upload
- restore verification
- expired recording cleanup
- orphaned artifact cleanup
Release gates
- lint and tests
- secret scan
- RLS audit
- meeting dependency gate
- recording acceptance
- staging media gates
Exact-ref releases
- GitHub Actions
- versioned VPS releases
- Caddy reload
- service restart
- health verification
- rollback retention
Security commands
npm run security:secrets
npm run security:rls-audit
npm run security:checklist
npm test
npm run ops:preflightLive RLS checks and production/staging gates require correctly scoped environment and database access. Do not run them against a project you have not been authorized to test.
Release and deployment policy
- Production source of truth is pushed GitHub
origin/main. - After changes are committed and pushed to
main, production deploy usesnpm run ops:deploy-main. - Staging deploy accepts an explicitly pushed branch or SHA through
npm run ops:deploy-staging -- <branch-or-sha>. - Deployment scripts stream or fetch the exact commit archive, create a versioned release, preserve shared environment state, restart only active services, and verify health.
- Unpushed local changes are never production deployment input.