Skip to content

Commit 2e8fa44

Browse files
docs(skills): author the 16 factory domains via defineX, not bare literals (#2035) (#2124)
The example apps were migrated to the `defineX` factories in #2088/#2095 and a lint guard keeps them clean — but the skills and hand-written docs still taught the old bare-literal pattern (`: Page = {}`, `: Action = {}`, `: PermissionSet = {}`, …). Skills are the corpus AI authors from, so this directly undercut the #2035 north star: leaving the unsafe pattern as the thing AI copies. Converts every bare output/Input-type metadata literal for the 16 factory domains to its `defineX(...)` factory call, across: - skills/objectstack-ui/SKILL.md (8: Page/Action/Report/Cube) - content/docs/guides/security.mdx (8: PermissionSet/SharingRule) - content/docs/{guides/standards,concepts/index,concepts/architecture, getting-started/architecture,protocol/objectui/record-alert}.* (7) Imports are rewritten in place (preserving each block's import source — root vs subpath) or injected where the snippet had none. Pre-existing `defineView` / `defineFlow` examples are untouched. `check:skill-docs` stays green (generated references come from frontmatter, unchanged). Docs-only — no package code, no changeset. Code blocks in MDX/skills are not type-checked by any gate, which is why they drifted; a lightweight MDX code-block lint is noted as a separate follow-up. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
1 parent 00c32f2 commit 2e8fa44

7 files changed

Lines changed: 75 additions & 59 deletions

File tree

content/docs/concepts/architecture.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,12 @@ That's the job of the other layers.
144144

145145
```typescript
146146
// packages/crm/src/permissions/sales_rep.permission.ts
147-
import type { PermissionSet } from '@objectstack/spec/security';
147+
import { definePermissionSet } from '@objectstack/spec/security';
148148

149149
// A permission set is keyed by object name. Each object grants the four
150150
// CRUD verbs (allowCreate / allowRead / allowEdit / allowDelete), and
151151
// optional field-level security keyed by "object.field".
152-
export const SalesRep: PermissionSet = {
152+
export const SalesRep = definePermissionSet({
153153
name: 'sales_rep',
154154
isProfile: true,
155155
objects: {
@@ -163,7 +163,7 @@ export const SalesRep: PermissionSet = {
163163
fields: {
164164
'customer.annual_revenue': { readable: true, editable: false }, // Read-only
165165
},
166-
};
166+
});
167167
```
168168

169169
### Example: Workflow Automation

content/docs/concepts/index.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ Access control is declared as **permission set** metadata (the `PermissionSet` s
150150

151151
```typescript
152152
// packages/crm/src/permissions/sales_rep.permission.ts
153-
import type { PermissionSet } from '@objectstack/spec';
153+
import { definePermissionSet } from '@objectstack/spec';
154154

155-
export const salesRep: PermissionSet = {
155+
export const salesRep = definePermissionSet({
156156
name: 'sales_rep',
157157
label: 'Sales Rep',
158158
isProfile: true,
@@ -167,10 +167,10 @@ export const salesRep: PermissionSet = {
167167
fields: {
168168
'customer.annual_revenue': { readable: true, editable: false }, // Read-only
169169
},
170-
};
170+
});
171171

172172
// packages/crm/src/permissions/sales_manager.permission.ts
173-
export const salesManager: PermissionSet = {
173+
export const salesManager = definePermissionSet({
174174
name: 'sales_manager',
175175
label: 'Sales Manager',
176176
isProfile: true,
@@ -182,7 +182,7 @@ export const salesManager: PermissionSet = {
182182
allowDelete: true,
183183
},
184184
},
185-
};
185+
});
186186
```
187187

188188
### Example: Flow Automation

content/docs/getting-started/architecture.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ That's the job of the other layers.
144144

145145
```typescript
146146
// src/permissions/sales_rep.permission.ts
147-
import type { PermissionSet } from '@objectstack/spec';
147+
import { definePermissionSet } from '@objectstack/spec';
148148

149149
// A permission set (here used as a profile) keyed by object and field.
150-
export const SalesRepPermission: PermissionSet = {
150+
export const SalesRepPermission = definePermissionSet({
151151
name: 'sales_rep',
152152
label: 'Sales Rep',
153153
isProfile: true,
@@ -163,7 +163,7 @@ export const SalesRepPermission: PermissionSet = {
163163
// <object>.<field> -> field-level security
164164
'customer.annual_revenue': { readable: true, editable: false }, // Read-only
165165
},
166-
};
166+
});
167167
```
168168

169169
### Example: Workflow Automation

content/docs/guides/security.mdx

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ A profile is modelled as a `PermissionSet` with `isProfile: true` (see
6262
`PermissionSetSchema`.
6363

6464
```typescript
65-
import type { PermissionSet } from '@objectstack/spec/security';
65+
import { definePermissionSet } from '@objectstack/spec/security';
6666

67-
export const SalesRepProfile: PermissionSet = {
67+
export const SalesRepProfile = definePermissionSet({
6868
name: 'sales_rep',
6969
label: 'Sales Representative',
7070
isProfile: true,
@@ -101,7 +101,7 @@ export const SalesRepProfile: PermissionSet = {
101101
app_admin: 'hidden', // Not visible
102102
app_sales: 'visible', // Available
103103
},
104-
};
104+
});
105105
```
106106

107107
### Object Permission Levels
@@ -153,7 +153,9 @@ RLS (no compiler change; ADR-0055). Sharing rules still widen on top.
153153
#### Sales Representative
154154

155155
```typescript
156-
export const SalesRepProfile: PermissionSet = {
156+
import { definePermissionSet } from '@objectstack/spec/security';
157+
158+
export const SalesRepProfile = definePermissionSet({
157159
name: 'sales_rep',
158160
isProfile: true,
159161
objects: {
@@ -167,13 +169,15 @@ export const SalesRepProfile: PermissionSet = {
167169
fields: {
168170
'account.annual_revenue': { readable: true, editable: false }, // Read-only
169171
},
170-
};
172+
});
171173
```
172174

173175
#### Sales Manager
174176

175177
```typescript
176-
export const SalesManagerProfile: PermissionSet = {
178+
import { definePermissionSet } from '@objectstack/spec/security';
179+
180+
export const SalesManagerProfile = definePermissionSet({
177181
name: 'sales_manager',
178182
isProfile: true,
179183
objects: {
@@ -187,13 +191,15 @@ export const SalesManagerProfile: PermissionSet = {
187191
},
188192
// ... full access to sales objects
189193
},
190-
};
194+
});
191195
```
192196

193197
#### Service Agent
194198

195199
```typescript
196-
export const ServiceAgentProfile: PermissionSet = {
200+
import { definePermissionSet } from '@objectstack/spec/security';
201+
202+
export const ServiceAgentProfile = definePermissionSet({
197203
name: 'service_agent',
198204
isProfile: true,
199205
objects: {
@@ -206,7 +212,7 @@ export const ServiceAgentProfile: PermissionSet = {
206212
'case.is_sla_violated': { readable: true, editable: false },
207213
'case.resolution_time_hours': { readable: true, editable: false },
208214
},
209-
};
215+
});
210216
```
211217

212218
---
@@ -216,9 +222,9 @@ export const ServiceAgentProfile: PermissionSet = {
216222
Permission sets extend profile permissions without changing the profile.
217223

218224
```typescript
219-
import type { PermissionSet } from '@objectstack/spec/security';
225+
import { definePermissionSet } from '@objectstack/spec/security';
220226

221-
export const AdvancedReportingPermissionSet: PermissionSet = {
227+
export const AdvancedReportingPermissionSet = definePermissionSet({
222228
name: 'advanced_reporting',
223229
label: 'Advanced Reporting',
224230

@@ -238,15 +244,15 @@ export const AdvancedReportingPermissionSet: PermissionSet = {
238244

239245
// System permissions are a flat array of capability strings
240246
systemPermissions: ['run_reports', 'export_reports', 'create_dashboards'],
241-
};
247+
});
242248

243-
export const BulkDataPermissionSet: PermissionSet = {
249+
export const BulkDataPermissionSet = definePermissionSet({
244250
name: 'bulk_data_access',
245251
label: 'Bulk Data Access',
246252

247253
objects: {},
248254
systemPermissions: ['bulk_api', 'view_all_data'],
249-
};
255+
});
250256
```
251257

252258
### Built-in Permission Sets
@@ -418,9 +424,9 @@ export const OrganizationDefaults = {
418424
Share records based on field criteria:
419425

420426
```typescript
421-
import type { SharingRule } from '@objectstack/spec/security';
427+
import { defineSharingRule } from '@objectstack/spec/security';
422428

423-
export const AccountTeamSharingRule: SharingRule = {
429+
export const AccountTeamSharingRule = defineSharingRule({
424430
name: 'account_team_sharing',
425431
label: 'Share Active Customers with Sales Team',
426432
type: 'criteria',
@@ -437,7 +443,7 @@ export const AccountTeamSharingRule: SharingRule = {
437443

438444
// Access level granted: read | edit | full
439445
accessLevel: 'edit',
440-
};
446+
});
441447
```
442448

443449
#### Recipient types
@@ -466,7 +472,9 @@ evaluated (`afterInsert` / `afterUpdate`); `role_and_subordinates` walks the
466472
Share based on record owner characteristics:
467473

468474
```typescript
469-
export const OpportunityOwnerSharingRule: SharingRule = {
475+
import { defineSharingRule } from '@objectstack/spec/security';
476+
477+
export const OpportunityOwnerSharingRule = defineSharingRule({
470478
name: 'opportunity_owner_sharing',
471479
label: 'Share Sales Rep Opportunities with Managers',
472480
type: 'owner',
@@ -485,7 +493,7 @@ export const OpportunityOwnerSharingRule: SharingRule = {
485493
},
486494

487495
accessLevel: 'read',
488-
};
496+
});
489497
```
490498

491499
### Analytics and Dataset Read Scope

content/docs/guides/standards.mdx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,9 @@ A profile is just a `PermissionSet` with `isProfile: true`. There is no separate
241241
`Profile` type — both share the same `PermissionSetSchema`.
242242

243243
```typescript
244-
import type { PermissionSet } from '@objectstack/spec/security';
244+
import { definePermissionSet } from '@objectstack/spec/security';
245245

246-
export const MyProfile: PermissionSet = {
246+
export const MyProfile = definePermissionSet({
247247
name: 'profile_name',
248248
label: 'Profile Label',
249249
isProfile: true,
@@ -271,15 +271,15 @@ export const MyProfile: PermissionSet = {
271271
app_sales: 'visible', // Visible
272272
app_admin: 'hidden', // Hidden
273273
},
274-
};
274+
});
275275
```
276276

277277
### Sharing Rule Pattern
278278

279279
```typescript
280-
import type { SharingRule } from '@objectstack/spec/security';
280+
import { defineSharingRule } from '@objectstack/spec/security';
281281

282-
export const MySharingRule: SharingRule = {
282+
export const MySharingRule = defineSharingRule({
283283
name: 'rule_name',
284284
object: 'object_name',
285285
type: 'criteria', // 'criteria' | 'owner'
@@ -294,7 +294,7 @@ export const MySharingRule: SharingRule = {
294294
},
295295

296296
accessLevel: 'edit', // 'read' | 'edit' | 'full'
297-
};
297+
});
298298
```
299299

300300
---

content/docs/protocol/objectui/record-alert.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ Common use cases:
4141
`record:alert` is registered as a slot component in the slotted page schema. Add it to the `alerts` slot of your `*.page.ts`:
4242

4343
```ts
44-
import type { Page } from '@objectstack/spec/ui';
44+
import { definePage } from '@objectstack/spec/ui';
4545

46-
export const SysUserDetailPage: Page = {
46+
export const SysUserDetailPage = definePage({
4747
name: 'sys_user_detail',
4848
label: 'User',
4949
object: 'sys_user',
@@ -70,7 +70,7 @@ export const SysUserDetailPage: Page = {
7070
],
7171
// …other slots: header, actions, highlights, details, tabs, discussion
7272
},
73-
};
73+
});
7474
```
7575

7676
The `alerts` slot is rendered between the page header (`header/actions`) and the highlights strip — the standard enterprise UX placement for contextual notices.

0 commit comments

Comments
 (0)