Skip to content

Commit 0a8e685

Browse files
os-zhuangclaude
andauthored
feat(showcase,docs): ADR-0090 permission-model zoo + full docs alignment (#2739)
Showcase now exercises the complete Permission Model v2 authoring surface (positions via typed factories, CRUD+FLS+RLS, org-depth read/write asymmetry, VAMA, systemPermissions, the isDefault everyone-suggestion, guest-safe capability, adminScope delegated administration anchored on a seeded sys_business_unit tree, externalSharingModel dials) and opts into the D6 access-matrix snapshot gate; guarded end-to-end by a new dogfood test. defineStack cross-reference validation learns that platform-provided (sys_/cloud_/ai_) objects are legitimate permission-grant and seed targets (ADR-0090 D12 delegated-admin shape; seed-loader parity), with tests. Docs: protocol/objectql/security.mdx rewritten to the v2 vocabulary; isProfile scrubbed from all authoring examples; dead identity/role reference link fixed; stale zod docstrings (rls/territory/sharing/tool/agent) rewritten and the security/ai references regenerated (adds the missing explain.mdx page). Deliberately NOT demoed (declared ≠ enforced): hierarchy depth scopes (enterprise hierarchy-security), tabPermissions (single-app package, ADR-0019 D3), owner-type sharing rules (seed-skipped [experimental]). Rename misses and platform bugs found while verifying are tracked in #2722 #2723 #2724 (vocabulary leftovers) and #2734 #2735 #2737 (fresh-boot org-RLS visibility, JSON-field seed batch inserts, count-scope leak). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent bc26360 commit 0a8e685

49 files changed

Lines changed: 1613 additions & 306 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
"@objectstack/spec": minor
3+
"@objectstack/example-showcase": minor
4+
"@objectstack/plugin-sharing": patch
5+
"@objectstack/plugin-security": patch
6+
---
7+
8+
ADR-0090 permission-model zoo + docs alignment.
9+
10+
**Showcase (`@objectstack/example-showcase`)** now exercises the full Permission
11+
Model v2 authoring surface and is guarded by a new runtime dogfood test
12+
(`showcase-permission-zoo.dogfood.test.ts`): typed `definePosition`/
13+
`definePermissionSet`/`defineSharingRule` factories; six flat positions (the
14+
stale pre-D3 `parent` fields are gone); permission sets covering CRUD+FLS+RLS,
15+
org-depth read/write asymmetry (`readScope: 'org'` / `writeScope: 'own'`),
16+
View-All (auditor) and Modify-All (ops) bypasses, `systemPermissions`
17+
(`setup.access`), the `isDefault` everyone-suggestion (incl. personal-data
18+
grants on the `private`-OWD note object), a guest-safe set for the `guest`
19+
anchor (D9), and a delegated-administration `adminScope` bounded to a seeded
20+
`sys_business_unit` subtree (D12). Objects gain `externalSharingModel` dials
21+
(D11). A committed `access-matrix.json` opts the showcase into the D6 snapshot
22+
gate. Hierarchy depths (`own_and_reports`/`unit`/`unit_and_below`) are
23+
deliberately NOT authored — they are enterprise (`hierarchy-security`) and the
24+
open runtime fails closed; BU-shaped visibility is demonstrated via the
25+
enforced `unit_and_subordinates` sharing-rule recipient instead.
26+
27+
**`@objectstack/spec`**: `defineStack` strict cross-reference validation no
28+
longer rejects permission grants or seed datasets that target platform-provided
29+
objects (`sys_`/`cloud_`/`ai_` prefixes) — a delegated-admin set carrying CRUD
30+
on the RBAC link tables (ADR-0090 D12) and an app seeding the business-unit
31+
tree are legitimate shapes; the typo net stays intact for the stack's own
32+
objects. Stale pre-ADR-0090 vocabulary in zod docstrings (rls/territory/
33+
sharing/tool/agent) is rewritten; the auto-generated references (including the
34+
previously missing `security/explain.mdx`) are regenerated.
35+
36+
**Docs**: `protocol/objectql/security.mdx` rewritten to the v2 model (no
37+
profiles, positions, canonical OWD four + D1 private default +
38+
`externalSharingModel`, position-scoped RLS, enforced sharing recipients);
39+
`isProfile` scrubbed from every authoring example; the dead
40+
`/docs/references/identity/role` link fixed; implementation-status and
41+
plugin READMEs aligned. Remaining rename misses are tracked in #2722
42+
(RLSUserContext.role), #2723 (portal `profiles`), #2724 (sys_record_share
43+
`role` enum).

content/docs/ai/actions-as-tools.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ await aiService.chatWithTools(messages, tools, {
210210
actor: {
211211
id: currentUser.id,
212212
name: currentUser.displayName,
213-
roles: currentUser.roles,
213+
positions: currentUser.positions,
214214
permissions: currentUser.permissions,
215215
},
216216
conversationId,

content/docs/ai/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ end-user's `ExecutionContext` so tool calls respect row-level security:
167167
```typescript
168168
const reply = await aiService.chatWithTools(messages, tools, {
169169
toolExecutionContext: {
170-
actor: { id: currentUser.id, name: currentUser.displayName, roles: currentUser.roles, permissions: currentUser.permissions },
170+
actor: { id: currentUser.id, name: currentUser.displayName, positions: currentUser.positions, permissions: currentUser.permissions },
171171
conversationId,
172172
environmentId,
173173
},

content/docs/concepts/architecture.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,12 @@ That's the job of the other layers.
152152
// src/permissions/sales_rep.permission.ts
153153
import { definePermissionSet } from '@objectstack/spec';
154154

155-
// A permission set (here used as a profile) keyed by object and field.
155+
// A permission set keyed by object and field — the only capability
156+
// container (ADR-0090: capability is the union of held sets; the old
157+
// profile concept was removed).
156158
export const SalesRepPermission = definePermissionSet({
157159
name: 'sales_rep',
158160
label: 'Sales Rep',
159-
isProfile: true,
160161
objects: {
161162
customer: {
162163
allowCreate: true,

content/docs/concepts/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,11 @@ This ensures ObjectStack apps can run on Node.js + PostgreSQL today, Python + SQ
133133
| Layer | Responsibility | Example |
134134
| :--- | :--- | :--- |
135135
| **Protocol** | Defines capabilities | A row-level-security policy slot (`operation` + `using` clause) |
136-
| **App** | Defines business logic | `{ operation: 'select', using: "role == 'admin'" }` |
136+
| **App** | Defines business logic | `{ operation: 'select', using: "owner_id == current_user.id" }` |
137137
| **Engine** | Enforces the logic | Compiles the `using` condition into a query filter |
138138

139139
<Callout type="info">
140-
CRUD permissions (`allowRead`, `allowEdit`, …) are simple booleans — they grant or deny an operation. Record-level *conditional* access is a separate mechanism: [Row-Level Security](/docs/concepts/architecture) policies, whose `using` clause is a CEL predicate over context variables such as `current_user.roles` and `current_user.id`.
140+
CRUD permissions (`allowRead`, `allowEdit`, …) are simple booleans — they grant or deny an operation. Record-level *conditional* access is a separate mechanism: [Row-Level Security](/docs/concepts/architecture) policies, whose `using` clause is a CEL predicate over context variables such as `current_user.positions` and `current_user.id`.
141141
</Callout>
142142

143143
### Single Source of Truth

content/docs/data-modeling/objects.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ indexes: [
183183
| `active` | `boolean` | Is object active (default: `true`) |
184184
| `isSystem` | `boolean` | System object, protected from deletion (default: `false`) |
185185
| `abstract` | `boolean` | Abstract base, cannot be instantiated (default: `false`) |
186-
| `sharingModel` | `enum` | Org-Wide Default record visibility (ADR-0055/0056). Canonical: `'private'`, `'public_read'`, `'public_read_write'`, `'controlled_by_parent'` (detail visibility derived from its master). Legacy aliases: `'read'`=public_read, `'read_write'`/`'full'`=public_read_write |
186+
| `sharingModel` | `enum` | Org-Wide Default record visibility (ADR-0055/0056/0090). Canonical four only: `'private'`, `'public_read'`, `'public_read_write'`, `'controlled_by_parent'` (detail visibility derived from its master). The legacy aliases (`'read'`, `'read_write'`, `'full'`) were removed from the enum (ADR-0090 D4) — authoring rejects them. Unset on a custom object resolves to `'private'` (ADR-0090 D1) |
187187
| `keyPrefix` | `string` | Short prefix for record IDs (e.g. `'001'`) |
188188
| `validations` | `ValidationRule[]` | Object-level validation rules (see [Validation](/docs/data-modeling/validation)) |
189189

content/docs/getting-started/common-patterns.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,6 @@ import { definePermissionSet } from '@objectstack/spec';
424424
export const HrRepPermission = definePermissionSet({
425425
name: 'hr_rep',
426426
label: 'HR Rep',
427-
isProfile: true,
428427
objects: {
429428
employee: { allowCreate: true, allowRead: true, allowEdit: true, allowDelete: false },
430429
},

content/docs/getting-started/examples.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,10 @@ hotcrm/
230230
│ ├── dashboards/ # Executive, Sales, Service dashboards
231231
│ ├── data/ # Seed data for all objects
232232
│ ├── flows/ # 5 automation flows: case escalation, approval, ...
233-
│ ├── profiles/ # 5 security profiles: admin, sales rep, manager, ...
233+
│ ├── security/ # 5 permission sets: admin, sales rep, manager, ...
234234
│ ├── rag/ # 4 RAG pipelines: product info, competitive intel, ...
235235
│ ├── reports/ # 7 reports with tabular, summary, matrix formats
236-
│ └── sharing/ # Sharing rules, role hierarchy, org defaults
236+
│ └── sharing/ # Sharing rules, business-unit hierarchy, org defaults
237237
```
238238

239239
### Features Showcased
@@ -244,7 +244,7 @@ hotcrm/
244244
| **State Machine** | Lead lifecycle: `new → contacted → qualified → converted` with `Lead.state.ts` |
245245
| **AI Agents** | Sales Assistant, Service Agent, Revenue Intelligence, Email Campaign, Lead Enrichment |
246246
| **RAG Pipelines** | Product info, competitive intel, sales knowledge, support knowledge |
247-
| **Security Model** | 5 profiles (Admin, Manager, Rep, Agent, Marketing), sharing rules, role hierarchy |
247+
| **Security Model** | 5 permission sets (Admin, Manager, Rep, Agent, Marketing), sharing rules, business-unit hierarchy |
248248
| **Automation** | Lead conversion, case escalation, opportunity approval, campaign enrollment, quote generation |
249249
| **Custom APIs** | `POST /lead-convert`, `GET /pipeline-stats` |
250250
| **Seed Data** | 50+ realistic records across all objects |

content/docs/getting-started/glossary.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ External communication layer including REST contracts, API discovery, Realtime s
5353
Business process automation including Workflows (state machines), Flows (visual logic), and Webhooks (HTTP callbacks).
5454

5555
### Identity Protocol
56-
User, organization, and profile schemas for identity management.
56+
User, organization, and position schemas for identity management.
5757

5858
### Security Protocol
5959
RBAC, permissions, policy, and access-control schemas.

content/docs/getting-started/quick-reference.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,13 @@ Access control, permissions, and row-level security.
170170

171171
## Identity Protocol (4 schemas)
172172

173-
User identity, organizations, and role management.
173+
User identity, organizations, and position management.
174174

175175
| Protocol | Source File | Key Schemas | Purpose |
176176
|:---------|:-----------|:------------|:--------|
177177
| **[Identity](/docs/references/identity/identity)** | `identity.zod.ts` | Identity, User | User identity management |
178178
| **[Organization](/docs/references/identity/organization)** | `organization.zod.ts` | Organization | Multi-organization support |
179-
| **[Role](/docs/references/identity/role)** | `role.zod.ts` | Role | Role-based access control |
179+
| **[Position](/docs/references/identity/position)** | `position.zod.ts` | Position | Permission-set distribution (岗位, ADR-0090) |
180180
| **[SCIM](/docs/references/identity/scim)** | `scim.zod.ts` | SCIMUser, SCIMGroup | SCIM 2.0 provisioning |
181181

182182
## Cloud Protocol (4 schemas)

0 commit comments

Comments
 (0)