# CRM Access Enforcement Inventory ## Status Key - `Protected`: route already passes through resolved CRM access or explicit permission/scope enforcement - `Partially Protected`: route requires auth/permission but still has legacy or coarse organization-wide behavior - `Legacy Protected`: route depends on role string or legacy membership behavior instead of resolved union access - `Not Protected`: no meaningful CRM scope enforcement beyond organization lookup ## Inventory | Area | Route / Module | Status | Notes | | --- | --- | --- | --- | | Customers | `/api/crm/customers` | `Protected` | List/detail/update/delete now pass resolved CRM scope context and customer visibility is filtered by ownership plus related enquiry/quotation signals | | Contacts | `/api/crm/customers/[id]/contacts` | `Protected` | Contact APIs now inherit customer visibility and creator/admin/team visibility rules from resolved CRM access | | Leads / Opportunities | `/api/crm/opportunities` and child routes | `Partially Protected` | Uses branch/product/own-scope logic already, but still passes legacy `businessRole` fields through route/service seams | | Quotations | `/api/crm/quotations` and `[id]` | `Protected` | List/detail/create/update/delete now pass resolved CRM scope context and enforce branch/product/own visibility | | Quotation pricing surfaces | document data, preview, PDF preview/download, approved PDF | `Protected` | Pricing-bearing outputs now require pricing visibility and emit `crm_security_access` audit events when denied | | Document artifacts | `/api/crm/document-artifacts/[id]/download` | `Protected` | Approved quotation artifacts now require artifact permission plus pricing visibility guard | | Approvals | `/api/crm/approvals`, approve/reject/return | `Protected` | Approval list/detail now require related quotation visibility or current-actor/admin visibility; step actor resolution uses resolved CRM access union | | Dashboard | `/api/crm/dashboard` | `Protected` | Route uses resolved context; revenue widgets are hidden unless quotation pricing is visible | | Dashboard export | `/api/crm/dashboard/export` | `Protected` | Revenue export explicitly blocked without pricing visibility | | CRM settings: roles | `/api/crm/settings/roles*` | `Partially Protected` | Permission-gated, but inventory still needs full pass for every mutation route | | CRM settings: user assignments | `/api/crm/settings/user-role-assignments*` | `Protected` | Explicit permission-gated through CRM role-assignment permissions | | CRM settings: approval workflows | `/api/crm/settings/approval-workflows*` | `Partially Protected` | Permission-gated at route layer; deeper union-based workflow visibility still pending | | CRM settings: document templates / sequences | `/api/crm/settings/document-templates*`, `/document-sequences*` | `Partially Protected` | Permission-gated, but not yet audited against the full L.3 export/artifact matrix | | Master options | `/api/foundation/master-options` | `Partially Protected` | Admin-oriented and permission-gated, but outside resolved CRM scope model | ## High-Risk Findings 1. Team-scope semantics are still coarse because the current model does not yet carry a first-class subordinate/team graph. 2. Contact sharing is now persisted, but team-scope still remains approximate because there is no first-class CRM team hierarchy. 3. Enquiry services already enforce meaningful scope, but several route files still pass legacy role-shaped context instead of a dedicated security context object. ## Follow-up Focus - Normalize remaining enquiry routes onto the same security-context builder used by quotations and dashboard. - Add runtime seeded scenario tests once dedicated security fixtures are available. - Introduce a first-class CRM team hierarchy if the business requires true team-based visibility.