Initial working state: CL3.5 complete (Plesk sync + suspend/unsuspend)

This commit is contained in:
2026-03-05 06:47:43 +00:00
commit a36d55eae5
53 changed files with 9925 additions and 0 deletions

49
SECURITY.md Normal file
View File

@@ -0,0 +1,49 @@
# Security Model (CL2)
## Tenancy model
- Tenant boundary is `agency_id`.
- Every business table row is scoped to an agency.
- RLS helper functions enforce scope using `auth.uid()` against `agency_members`:
- `public.is_agency_member(agency_id)`
- `public.is_agency_admin(agency_id)` (`owner` or `admin`)
## Role model
- `owner`: full admin permissions in agency
- `admin`: same operational permissions as owner for managed resources
- `member`: read-mostly on sensitive resources, no admin writes
## Write restrictions by table
- `agencies`
- `INSERT`: any authenticated user (supports first-time onboarding)
- `UPDATE/DELETE`: admin only
- `agency_members`
- `SELECT`: own membership rows
- `INSERT`: onboarding self-owner membership, or admin adding members
- `UPDATE/DELETE`: admin (delete also allows self-leave)
- `clients`
- member-readable and member-writable (chosen for MVP collaboration speed)
- `plesk_instances`
- member-readable, admin-writable
- `plesk_subscriptions`
- member-readable, admin-writable
- `plesk_domains`
- member-readable, admin-writable
- `actions_log`
- member-readable, admin insert/update
- `billing_accounts`
- member-readable, admin-writable
- `entitlements`
- member-readable, admin-writable
## Onboarding compatibility
Policies are designed so a newly authenticated user can:
1. insert first `agencies` row,
2. insert first `agency_members` row as `owner` for `auth.uid()`,
3. then operate normally under tenant-scoped access.
This supports the server-side auto-bootstrap flow used by `getServerAgencyContextOrRedirect()`.