# 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`
