115 lines
3.6 KiB
Markdown
115 lines
3.6 KiB
Markdown
# CRM Authorization Boundaries
|
|
|
|
## Source of Truth
|
|
|
|
Resolved CRM access is the source of truth for CRM authorization.
|
|
|
|
The effective model is:
|
|
|
|
1. Authenticated user
|
|
2. Active organization membership
|
|
3. CRM role assignments
|
|
4. Resolved permission union
|
|
5. Resolved branch scope
|
|
6. Resolved product scope
|
|
7. Resolved ownership scope
|
|
8. Resolved approval authority
|
|
|
|
`memberships.businessRole` remains a compatibility fallback only inside the resolver path.
|
|
|
|
## Enforcement Layers
|
|
|
|
### Route permission gates
|
|
|
|
Every CRM route must first require organization access plus at least one explicit permission.
|
|
|
|
### Service-level scope enforcement
|
|
|
|
Sensitive list/detail/mutation services must additionally enforce:
|
|
|
|
- branch scope
|
|
- product scope
|
|
- ownership visibility
|
|
|
|
This is required because UI filtering is not a security boundary.
|
|
|
|
### Pricing visibility
|
|
|
|
Pricing-bearing outputs require quotation pricing visibility:
|
|
|
|
- quotation PDF preview/download
|
|
- approved PDF
|
|
- document preview/data
|
|
- revenue dashboard/export
|
|
- approved artifact download
|
|
|
|
Denied pricing access is logged as `crm_security_access` with action `pricing_hidden`.
|
|
|
|
### Approval authority
|
|
|
|
Approval step handling must use resolved CRM role unions instead of a single legacy business-role string.
|
|
|
|
## Current Ownership Model
|
|
|
|
- `own`: creator or assigned owner/salesman
|
|
- `team`: currently treated as broader-than-own, but still requires future team graph formalization
|
|
- `organization`: organization-wide inside active tenant
|
|
- `monitor`: read-oriented role with limited commercial visibility
|
|
|
|
## Customer Boundary
|
|
|
|
Customer visibility is now enforced from resolved CRM access.
|
|
|
|
- `organization` and admin scopes can see organization customers within branch scope
|
|
- `team` currently behaves as branch/product-scoped broad visibility until a first-class team graph exists
|
|
- `own` can see customers they created or customers linked to enquiries/quotations they can already access
|
|
- `monitor` can see customers only when those customers are related to visible lead/enquiry records
|
|
|
|
## Contact Boundary
|
|
|
|
Contact visibility is enforced through customer visibility plus contact ownership rules.
|
|
|
|
- if a user can access the parent customer, they can access its contact list within their role boundary
|
|
- contact creators retain access to their own contacts
|
|
- admin/organization scope retains access
|
|
- production contact sharing is persisted through `crm_contact_shares`, so explicit share grants are part of the live authorization boundary
|
|
|
|
## Approval Boundary
|
|
|
|
Approval visibility is now narrower than generic approval-read permission.
|
|
|
|
A user can see approval records only when at least one of these is true:
|
|
|
|
1. they can access the related quotation through resolved CRM scope
|
|
2. they are the current approval actor by resolved CRM role
|
|
3. they are admin / organization-wide CRM authority
|
|
|
|
## Artifact Boundary
|
|
|
|
Artifact permission alone is not enough for approved quotation PDFs.
|
|
|
|
The caller must satisfy:
|
|
|
|
1. artifact download permission
|
|
2. quotation pricing visibility when the artifact is an approved quotation PDF
|
|
|
|
## Dashboard Boundary
|
|
|
|
Dashboard access is split:
|
|
|
|
- base dashboard visibility: `crm.dashboard.read`
|
|
- revenue/commercial visibility: quotation pricing visibility
|
|
- approval widgets: approval read permission
|
|
- export visibility: same scope as dashboard, with extra revenue export restriction
|
|
|
|
Approval widgets additionally inherit approval-request visibility rules, not just a raw approval permission.
|
|
|
|
## Audit Events
|
|
|
|
Security-sensitive denials are recorded under entity type `crm_security_access` with actions:
|
|
|
|
- `access_denied`
|
|
- `scope_violation`
|
|
- `permission_violation`
|
|
- `pricing_hidden`
|