Skip to content

Commit 7ddf6a1

Browse files
committed
Add territory management schema and update docs
Introduces a new territory management protocol with a Zod schema (`territory.zod.ts`) to support matrix organizations and flexible territory assignments. Updates documentation to explain the distinction between role and territory hierarchies, and modifies the spec index to export the new territory schema.
1 parent 84e65d5 commit 7ddf6a1

File tree

3 files changed

+88
-16
lines changed

3 files changed

+88
-16
lines changed

content/docs/concepts/security_architecture.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,24 @@ If you are coming from the Microsoft/Dynamics ecosystem:
3939
* **Security Role (User Level)** -> `allowRead: true`
4040
* **Security Role (BU Level)** -> `allowRead: true` + `Sharing Rule (Share with Role)`
4141
* **Security Role (Org Level)** -> `viewAllRecords: true`
42-
* **Business Unit** -> `Role` (Functional) / `OrgUnit` (Physical)
42+
* **Business Unit** -> `Role` (Functional Hierarchy)
4343

44-
## 4. The Chinese Enterprise Extension (中国企业适配)
44+
## 4. Advanced: Matrix Management (Territory Management)
4545

46-
In the context of Chinese enterprises, the hierarchy is often strictly defined by **legal entities and departments** (Organization), which is distinct from the **reporting line** (Role).
46+
For large global enterprises where a single reporting line ("Role") is insufficient, ObjectStack implements the **Territory Management** protocol (`src/system/territory.zod.ts`).
4747

48-
* **OrgUnit (组织机构)**: `src/system/org_unit.zod.ts`
49-
* **Group (集团)**
50-
* **Company (分公司)**
51-
* **Department (部门)**
52-
* **Role (角色)**: `src/system/role.zod.ts`
53-
* Defines titles regardless of department (e.g., "Department Manager", "Accountant").
48+
This solves the "Matrix Organization" problem without breaking the strict Role hierarchy.
5449

55-
**Example Assignment:**
56-
* User: "Zhang San"
57-
* OrgUnit: "Shanghai Branch / Sales Dept"
58-
* Role: "Sales Manager"
50+
* **Role Hierarchy (HR/Reporting)**: "Who reports to whom?" (Stable)
51+
* Example: A Sales Rep reports to a Sales Manager.
52+
* **Territory Hierarchy (Market/Revenue)**: "Who owns which market?" (Flexible, Multi-assignment)
53+
* Example: A Sales Rep might be assigned to both "West Coast (Geo)" and "Healthcare (Industry)".
54+
55+
**How it works:**
56+
1. **Accounts/Deals** are assigned to **Territories** based on rules (e.g., `State = 'CA'`).
57+
2. **Users** are assigned to **Territories**.
58+
3. Users gain access to records in their Territories, *regardless* of their Role.
59+
60+
This aligns with best practices from **Salesforce Enterprise Territory Management** and **Oracle Sales Cloud**.
5961

60-
The **Sharing Engine** can then support rules like:
61-
> "Share records owned by [Shanghai Branch] with [Headquarters Audit Role]."
6262

packages/spec/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export * from './system/api.zod';
3434
export * from './system/identity.zod';
3535
export * from './system/policy.zod';
3636
export * from './system/role.zod';
37-
export * from './system/org_unit.zod';
37+
export * from './system/territory.zod';
3838
export * from './system/license.zod';
3939
export * from './system/translation.zod';
4040
export * from './system/constants';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { z } from 'zod';
2+
3+
/**
4+
* Territory Management Protocol
5+
* Defines a matrix reporting structure that exists parallel to the Role Hierarchy.
6+
*
7+
* USE CASE:
8+
* - Enterprise Sales Teams (Geo-based: "EMEA", "APAC")
9+
* - Industry Verticals (Industry-based: "Healthcare", "Financial")
10+
* - Strategic Accounts (Account-based: "Strategic Accounts")
11+
*
12+
* DIFFERENCE FROM ROLE:
13+
* - Role: Hierarchy of PEOPLE (Who reports to whom). Stable. HR-driven.
14+
* - Territory: Hierarchy of ACCOUNTS/REVENUE (Who owns which market). Flexible. Sales-driven.
15+
* - One User can be assigned to MANY Territories (Matrix).
16+
* - One User has only ONE Role (Tree).
17+
*/
18+
19+
export const TerritoryType = z.enum([
20+
'geography', // Region/Country/City
21+
'industry', // Vertical
22+
'named_account', // Key Accounts
23+
'product_line' // Product Specialty
24+
]);
25+
26+
/**
27+
* Territory Model Schema
28+
* A container for a version of territory planning.
29+
* (e.g. "Fiscal Year 2024 Planning" vs "Fiscal Year 2025 Planning")
30+
*/
31+
export const TerritoryModelSchema = z.object({
32+
name: z.string().describe('Model Name (e.g. FY24 Planning)'),
33+
state: z.enum(['planning', 'active', 'archived']).default('planning'),
34+
startDate: z.string().optional(),
35+
endDate: z.string().optional(),
36+
});
37+
38+
/**
39+
* Territory Node Schema
40+
* A single node in the territory tree.
41+
*/
42+
export const TerritorySchema = z.object({
43+
/** Identity */
44+
name: z.string().regex(/^[a-z_][a-z0-9_]*$/),
45+
label: z.string().describe('Territory Label (e.g. "West Coast")'),
46+
47+
/** Structure */
48+
modelId: z.string().describe('Belongs to which Territory Model'),
49+
parent: z.string().optional().describe('Parent Territory'),
50+
type: TerritoryType.default('geography'),
51+
52+
/**
53+
* Assignment Rules (The "Magic")
54+
* How do accounts automatically fall into this territory?
55+
* e.g. "BillingCountry = 'US' AND BillingState = 'CA'"
56+
*/
57+
assignmentRule: z.string().optional().describe('Criteria based assignment rule'),
58+
59+
/**
60+
* User Assignment
61+
* Users assigned to work this territory.
62+
*/
63+
assignedUsers: z.array(z.string()).optional(),
64+
65+
/** Access Level */
66+
accountAccess: z.enum(['read', 'edit']).default('read'),
67+
opportunityAccess: z.enum(['read', 'edit']).default('read'),
68+
caseAccess: z.enum(['read', 'edit']).default('read'),
69+
});
70+
71+
export type Territory = z.infer<typeof TerritorySchema>;
72+
export type TerritoryModel = z.infer<typeof TerritoryModelSchema>;

0 commit comments

Comments
 (0)