# GovOPlaN RBAC And Resource-Access Model **Updated:** 2026-07-11 ## Authorization Equation An operation is permitted only when every applicable layer allows it: ```text effective role/API-key capability AND resource ownership/share access AND workflow state AND active governance/policy constraints ``` RBAC answers what an actor may do. ACLs answer which resource the actor may do it to. Workflow state and policy decide whether the operation is currently valid. ## Identity And Scope ```text Account global login identity +- User membership tenant-local identity +- direct tenant roles +- active group memberships | +- inherited tenant roles +- tenant-local API keys Account +- direct system-role assignments ``` A browser session has one active tenant membership. System privileges do not silently grant tenant data access. API keys remain tenant-local and receive the intersection of their configured scopes and their owner's live tenant scopes on every request. ## Wildcards ```text tenant:* every canonical tenant permission system:* every canonical system permission * legacy alias interpreted as tenant:* only ``` Tenant wildcards never grant system permissions. ## Canonical Tenant Permissions Campaigns: ```text campaign:read campaign:create campaign:update campaign:copy campaign:archive campaign:delete campaign:share campaign:validate campaign:build campaign:review campaign:send_test campaign:queue campaign:control campaign:send campaign:retry campaign:reconcile ``` Recipients: ```text recipients:read recipients:write recipients:import recipients:export ``` Files: ```text files:read files:download files:upload files:organize files:share files:delete files:admin ``` Reports and audit: ```text reports:read reports:export reports:send audit:read ``` Mail servers: ```text mail_servers:read mail_servers:use mail_servers:test mail_servers:write mail_servers:manage_credentials ``` Tenant administration: ```text admin:users:read admin:users:create admin:users:update admin:users:suspend admin:groups:read admin:groups:write admin:groups:manage_members admin:roles:read admin:roles:write admin:roles:assign admin:api_keys:read admin:api_keys:create admin:api_keys:revoke admin:settings:read admin:settings:write admin:policies:read admin:policies:write ``` ## Canonical System Permissions ```text system:tenants:read system:tenants:create system:tenants:update system:tenants:suspend system:accounts:read system:accounts:create system:accounts:update system:accounts:suspend system:roles:read system:roles:write system:roles:assign system:access:read system:access:assign system:audit:read system:settings:read system:settings:write system:governance:read system:governance:write ``` `system:access:*` remains a read/assignment boundary for cross-tenant and system access handling. It is not a separate primary UI area. ## Default Tenant Roles - **Owner:** `tenant:*`. At least one active operational owner must remain. - **Tenant administrator:** settings, policies, users, groups, roles, API keys, and read access to campaigns/files/reports/audit. Real delivery remains separately delegable. - **Administrator:** all tenant permissions for upgraded installations. - **Access administrator:** membership and assignment management within delegation limits. - **Campaign manager:** prepare, validate, and build campaigns; no review approval or real delivery by default. - **Reviewer:** inspect and approve prepared campaign messages. - **Sender:** mock-test, queue, control, send, retry, and reconcile prepared campaigns; can use/test approved mail profiles. - **File manager:** managed file operations without campaign delivery rights. - **Viewer:** read campaigns, recipients, files, and reports. - **Auditor:** read campaigns, recipient evidence, reports, and audit records; export detailed evidence. ## Default System Roles - **System owner:** `system:*`, protected. At least one active account must retain it. - **System administrator:** all specific system permissions, editable and not protected. - **System auditor:** read-only system registry/settings/governance/audit role, editable. ## Delegation Ceiling For role definition, assignment, and API-key creation: ```text requested scopes subset of actor delegateable scopes ``` Rules: 1. Tenant roles may contain tenant scopes only. 2. System roles may contain system scopes only. 3. Definition rights and assignment rights are separate. 4. Group definition and group membership management are separate. 5. API-key scopes are intersected with the owner's current effective scopes on every request. 6. Suspended accounts, users, tenants, or groups stop contributing access immediately. 7. Administrative updates are field-sensitive; a user with only status authority cannot change role assignments. ## Campaign Ownership And ACLs A campaign has exactly one owner: ```text owner user OR owner group ``` Additional active shares may target users or groups with `read` or `write`. Resolution: - owner user: read and write; - member of owner group: read and write; - explicit read share: read; - explicit write share: read and write; - `tenant:*`: tenant-wide ACL bypass; - ordinary campaign permission without ownership/share: no object access. ACLs do not add capabilities. A write share still needs the specific permission for update, validation, review, send, report, retry, or reconciliation. ## Files The current file access model distinguishes tenant-level file capabilities from space/folder/file ownership: | Scope | Meaning | | --- | --- | | `files:read` | browse/read visible file spaces and metadata | | `files:download` | download file content when ACL permits | | `files:upload` | create files in writable spaces | | `files:organize` | create folders, move files, and update metadata where ACL permits | | `files:share` | share files/spaces according to owner and policy rules | | `files:delete` | delete or retire files where ACL permits | | `files:admin` | tenant-wide administration of user/group file spaces | External file connections and spaces are additionally constrained by connector policy and owner/group assignment in the files module. ## Resource Access Explanations The access module exposes a diagnostic endpoint for explaining why a principal can see or operate on a concrete resource: ```text GET /api/v1/admin/access/resource-explanation ``` Required query values: | Field | Meaning | | --- | --- | | `user_id` | Tenant membership to explain. The current module UIs pass the signed-in user. | | `resource_type` | Module-owned type such as `file`, `folder`, or `campaign`. | | `resource_id` | Stable module resource identifier. | | `action` | Permission/action being explained, for example `files:file:read`. | | `tenant_id` | Optional tenant override for system/admin contexts. | The access module always contributes effective-scope provenance for the action. Installed modules may add resource provenance by exposing a `ResourceAccessExplanationProvider` through a capability consumed by access. Providers should return only facts they own, using these provenance kinds: | Kind | Meaning | | --- | --- | | `resource` | The concrete resource or an explicit not-found result. | | `owner` | Matching user/group ownership. | | `share` | Matching explicit user/group/tenant share. | | `policy` | Administrative bypass or policy-derived grant. | | `role` / `right` | Scope and role provenance from access itself. | Files currently registers `files.access` and explains file assets plus folders. Persisted folders use their database ID. Folder rows inferred from file paths use a deterministic virtual ID: ```text virtual-folder:v1:::: ``` The files provider validates virtual folder IDs before returning provenance: the tenant and owner must match the resource ID, and at least one active file must exist below the normalized folder path. This keeps virtual folder explanations stable without forcing every inferred tree node to become a stored folder row. Campaign currently registers `campaigns.access` and explains the campaign ownership/sharing object itself. Finer-grained campaign sub-objects are tracked separately in `govoplan-campaign#50` until their resource identifiers and access rules are decided. Cross-user resource explanation is a policy feature, not a module-local UI detail. Until `govoplan-policy#6` is resolved, module UIs should default to current-user explanation and avoid importing access-admin user-picking components. ## Mail Servers | Scope | Meaning | | --- | --- | | `mail_servers:read` | profile metadata and effective policy visibility | | `mail_servers:use` | use an allowed profile for a campaign or message flow | | `mail_servers:test` | run connectivity tests without revealing secrets | | `mail_servers:write` | create/update profile metadata where policy allows | | `mail_servers:manage_credentials` | create/replace SMTP/IMAP secrets or lower-level credentials where policy allows | Reusable encrypted profiles exist. Effective usability is also constrained by hierarchical mail-profile policy, ownership, allowed/forced profile sets, credential inheritance mode, lower-level override switches, and allow/deny patterns. ## Compatibility Aliases Compatibility aliases may exist in backend code for upgraded installations, but new UI and docs should use canonical scopes. Current alias direction: ```text * -> tenant:* system:tenants:write -> create/update/suspend tenant scopes system:access:write -> system access assignment/write scopes ``` A separate `retention:*` family is not currently canonical because retention is managed through system settings and tenant policy scopes. Add it only if retention operation duties need separation from general policy/settings administration.