task-l.3.1

This commit is contained in:
phaichayon
2026-06-22 14:18:26 +07:00
parent 42f403a7ed
commit 1b901efc51
21 changed files with 1320 additions and 102 deletions

View File

@@ -11,13 +11,13 @@
| Area | Route / Module | Status | Notes |
| --- | --- | --- | --- |
| Customers | `/api/crm/customers` | `Partially Protected` | Permission-gated, but service is still mostly organization-wide and not yet ownership-scoped |
| Contacts | `/api/crm/customers/[id]/contacts` | `Partially Protected` | Bound to customer org, but no dedicated resolved ownership/contact-sharing policy yet |
| 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 / Enquiries | `/api/crm/enquiries` 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 | `Legacy Protected` | Permission-gated; step actor resolution now uses resolved CRM access union, but request listing is still organization-wide |
| 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 |
@@ -28,14 +28,12 @@
## High-Risk Findings
1. Customer/contact services still need full ownership-scope enforcement rather than organization-only reads.
2. Approval request listing and detail visibility are still broader than the final resolved-ownership model.
1. Team-scope semantics are still coarse because the current model does not yet carry a first-class subordinate/team graph.
2. Production contact sharing is not yet backed by a persisted sharing table; current enforcement covers creator/customer/admin visibility only.
3. Enquiry services already enforce meaningful scope, but several route files still pass legacy role-shaped context instead of a dedicated security context object.
4. Team-scope semantics are still coarse because the current model does not yet carry a first-class subordinate/team graph.
## Follow-up Focus
- Finish customer/contact ownership enforcement.
- Convert approval list/detail visibility from organization scope to resolved quotation visibility.
- Normalize remaining enquiry routes onto the same security-context builder used by quotations and dashboard.
- Add runtime scenario tests once seeded multi-role fixtures are available.
- Add runtime seeded scenario tests once dedicated security fixtures are available.
- Introduce a first-class team hierarchy and production contact-sharing model if the business requires them.

View File

@@ -56,6 +56,34 @@ Approval step handling must use resolved CRM role unions instead of a single leg
- `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 shared-contact persistence does not exist yet, so legacy demo sharing is not 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.
@@ -74,6 +102,8 @@ Dashboard access is split:
- 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:

View File

@@ -0,0 +1,41 @@
# Team Scope Limitations
## Current Team Scope Logic
Current CRM authorization resolves the most permissive ownership scope from active CRM role assignments.
For `team` scope today:
- quotation visibility is effectively broader than `own`, but still constrained by branch scope and product scope
- customer visibility is approximated from branch scope plus related enquiry/quotation relationships
- approval visibility inherits quotation visibility or current approval-actor visibility
## Known Limitations
There is not yet a first-class team hierarchy model in the domain.
That means the system does **not** currently know:
- who reports to whom
- which sales users belong to the same explicit team
- whether a manager should see one subset of sales users but not another inside the same branch
Because of that, `team` currently behaves as an approximate operational scope rather than a strict org-chart scope.
## Contact Sharing Limitation
The production schema currently has no persisted contact-sharing table.
Result:
- contact visibility is enforced through customer ownership plus contact creator visibility
- mock/demo shared-contact behavior from legacy demo data is not part of the production boundary yet
## Future Team Hierarchy Model
Recommended future direction:
1. add a first-class manager/team relationship model
2. resolve `team` scope from that relationship instead of permissive approximation
3. add explicit contact-sharing persistence if the business still requires cross-owner contact access
4. expand runtime security fixtures around manager-team boundaries after real hierarchy data exists