@elevasis/sdk 1.47.0 → 1.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +1034 -319
- package/dist/index.d.ts +687 -49
- package/dist/index.js +297 -47
- package/dist/node/index.d.ts +110 -26
- package/dist/test-utils/index.d.ts +649 -36
- package/dist/test-utils/index.js +275 -45
- package/dist/worker/index.d.ts +687 -53
- package/dist/worker/index.js +121 -6
- package/package.json +2 -2
- package/reference/_navigation.md +7 -6
- package/reference/_reference-manifest.json +12 -2
- package/reference/core/index.mdx +6 -4
- package/reference/index.mdx +11 -5
- package/reference/packages/core/src/README.md +46 -44
- package/reference/packages/core/src/content/README.md +13 -12
- package/reference/packages/core/src/organization-model/README.md +9 -6
- package/reference/rules/content.md +27 -0
- package/reference/rules/organization-model.md +9 -3
- package/reference/rules/organization-os.md +2 -2
- package/reference/rules/ui.md +1 -1
- package/reference/rules/vibe-intents.md +19 -16
- package/reference/rules/vibe.md +32 -12
- package/reference/scaffold/recipes/add-a-feature.md +1 -1
- package/reference/scaffold/recipes/customize-organization-model.md +2 -2
- package/reference/scaffold/recipes/extend-content.md +172 -30
- package/reference/scaffold/reference/glossary.md +2 -2
- package/reference/scaffold/reference/system-interface-capabilities.md +26 -6
- package/reference/sdk/cli-management.mdx +246 -41
- package/reference/sdk/cli.mdx +103 -64
- package/reference/sdk/define-builders.mdx +1 -1
- package/reference/sdk/deployment/command-center.mdx +2 -2
- package/reference/sdk/deployment/index.mdx +1 -1
- package/reference/sdk/exports.mdx +4 -4
- package/reference/sdk/framework/agent.mdx +4 -3
- package/reference/sdk/framework/index.mdx +1 -1
- package/reference/sdk/framework/project-structure.mdx +34 -23
- package/reference/sdk/framework/tutorial-system.mdx +1 -1
- package/reference/sdk/getting-started.mdx +25 -52
- package/reference/sdk/index.mdx +3 -3
- package/reference/sdk/platform-tools/adapters-integration.mdx +1 -1
- package/reference/sdk/platform-tools/adapters-platform.mdx +5 -5
- package/reference/sdk/platform-tools/type-safety.mdx +1 -1
- package/reference/sdk/resources/patterns.mdx +10 -11
- package/reference/sdk/resources/types.mdx +15 -9
- package/reference/sdk/templates/data-enrichment.mdx +1 -1
- package/reference/sdk/templates/email-sender.mdx +1 -1
- package/reference/sdk/templates/index.mdx +47 -47
- package/reference/sdk/templates/lead-scorer.mdx +1 -1
- package/reference/sdk/templates/pdf-generator.mdx +42 -24
- package/reference/sdk/templates/recurring-job.mdx +20 -15
- package/reference/sdk/templates/text-classifier.mdx +1 -1
- package/reference/sdk/templates/web-scraper.mdx +9 -5
- package/reference/ui/exports.mdx +1 -1
- package/reference/ui/index.mdx +2 -2
|
@@ -57,17 +57,17 @@ A pipeline's step catalog is named `content:catalog/{pipelineId}-steps` and refe
|
|
|
57
57
|
|
|
58
58
|
## Published Content Surfaces
|
|
59
59
|
|
|
60
|
-
| Surface
|
|
61
|
-
|
|
|
62
|
-
| `contentManifest`, `CONTENT_ITEMS`, `ContentSidebar`, `ContentSidebarMiddle`, `MyReviewQueuePanel`
|
|
63
|
-
| `ContentOverviewPage`, `ContentItemsPage`, `ContentItemReviewPage`, `ContentPipelinesPage`, `
|
|
64
|
-
| `ContentDistributionsPage`, `ContentDistributionDetailPage`
|
|
65
|
-
| `ContentReviewCard`, `ReviewActionBar`, `PayloadBody`, `AlternatesPanel`, `ProcessingStateStrip`
|
|
66
|
-
| `useContentConfig`, `resolveContentStepResource`
|
|
67
|
-
| `useContentItems`, `useContentItem`, `useContentItemAttempts`, `useUpdateContentItem`, `useReviewContentItem`
|
|
68
|
-
| `useContentDistributions`, `useContentDistribution`, `useUpdateContentDistribution`
|
|
69
|
-
| `useContentPipelineSummary`
|
|
70
|
-
| `content`
|
|
60
|
+
| Surface | Import from | Use for |
|
|
61
|
+
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------ |
|
|
62
|
+
| `contentManifest`, `CONTENT_ITEMS`, `ContentSidebar`, `ContentSidebarMiddle`, `MyReviewQueuePanel` | `@elevasis/ui/features/content` | Feature registration and sidebar composition |
|
|
63
|
+
| `ContentOverviewPage`, `ContentItemsPage`, `ContentItemReviewPage`, `ContentPipelinesPage`, `ContentPipelineBoardPage` | `@elevasis/ui/features/content` | Shared pages you can route to or wrap |
|
|
64
|
+
| `ContentDistributionsPage`, `ContentDistributionDetailPage` | `@elevasis/ui/features/content` | Distribution surfaces |
|
|
65
|
+
| `ContentReviewCard`, `ReviewActionBar`, `PayloadBody`, `AlternatesPanel`, `ProcessingStateStrip` | `@elevasis/ui/features/content` | Review UI primitives for a custom review screen |
|
|
66
|
+
| `useContentConfig`, `resolveContentStepResource` | `@elevasis/ui/features/content` | Read the resolved pipeline/step catalogs from OM |
|
|
67
|
+
| `useContentItems`, `useContentItem`, `useContentItemAttempts`, `useUpdateContentItem`, `useReviewContentItem` | `@elevasis/ui/hooks` | Item data access and review mutations |
|
|
68
|
+
| `useContentDistributions`, `useContentDistribution`, `useUpdateContentDistribution` | `@elevasis/ui/hooks` | Distribution data access |
|
|
69
|
+
| `useContentPipelineSummary` | `@elevasis/ui/hooks` | Pipeline roll-ups |
|
|
70
|
+
| `content` | `@elevasis/sdk/worker` | Workflow-side content adapter |
|
|
71
71
|
|
|
72
72
|
Read the generated contracts before changing typed boundaries:
|
|
73
73
|
|
|
@@ -104,6 +104,70 @@ Then set `content.config.defaultPipelineId` if this should be the pipeline the U
|
|
|
104
104
|
|
|
105
105
|
**The step catalog name is load-bearing.** `content:catalog/{pipelineId}-steps` must match the pipeline record's `stepCatalog` exactly. Nothing type-checks that string.
|
|
106
106
|
|
|
107
|
+
### Or declare it once with `defineContentPipeline`
|
|
108
|
+
|
|
109
|
+
The hand-written form above is fine and stays supported, but a pipeline is actually declared in **five** places, and missing one fails at runtime rather than at build:
|
|
110
|
+
|
|
111
|
+
1. the `content:catalog/pipeline` entry
|
|
112
|
+
2. the step catalog, whose id must match the string above exactly
|
|
113
|
+
3. `content.config.defaultPipelineId`
|
|
114
|
+
4. `apiInterface.readinessContract.requiredCatalogs`
|
|
115
|
+
5. each participating resource's `ontology.usesCatalogs`
|
|
116
|
+
|
|
117
|
+
`defineContentPipeline` takes one declaration and derives all five.
|
|
118
|
+
|
|
119
|
+
<!-- doc-snippet:skip: illustrative excerpt -- references project-local descriptors -->
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { buildContentPipelineCatalogs, defineContentPipeline } from '@elevasis/core/organization-model'
|
|
123
|
+
import { z } from 'zod'
|
|
124
|
+
|
|
125
|
+
export const podcastToClips = defineContentPipeline({
|
|
126
|
+
systemPath: 'content',
|
|
127
|
+
id: 'podcast-to-clips',
|
|
128
|
+
label: 'Podcast to Clips',
|
|
129
|
+
workspaceRoute: '/content/clips',
|
|
130
|
+
steps: [
|
|
131
|
+
{
|
|
132
|
+
key: 'transcript',
|
|
133
|
+
actor: 'workflow',
|
|
134
|
+
review: 'none',
|
|
135
|
+
advancesTo: 'clip-selection',
|
|
136
|
+
resource: transcribeEpisode,
|
|
137
|
+
payload: z.object({ transcriptPath: z.string() })
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
key: 'clip-selection',
|
|
141
|
+
actor: 'agent',
|
|
142
|
+
review: 'required',
|
|
143
|
+
advancesTo: 'publish',
|
|
144
|
+
resource: proposeClips,
|
|
145
|
+
payload: z.object({ candidateIds: z.array(z.string()) })
|
|
146
|
+
},
|
|
147
|
+
{ key: 'publish', actor: 'workflow', review: 'none', resource: publishClip }
|
|
148
|
+
]
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Inside the content System:
|
|
152
|
+
// ontology.catalogTypes: { ...buildContentPipelineCatalogs([podcastToClips]), ...yourOtherCatalogs }
|
|
153
|
+
// config: { defaultPipelineId: podcastToClips.defaultPipelineId }
|
|
154
|
+
// apiInterface: { resourceIds: podcastToClips.resourceIds,
|
|
155
|
+
// readinessContract: { requiredCatalogs: [...podcastToClips.requiredCatalogs,
|
|
156
|
+
// 'content:catalog/status'] } }
|
|
157
|
+
// And on each participating resource:
|
|
158
|
+
// ontology: { usesCatalogs: podcastToClips.usesCatalogs }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Three failure modes stop being possible:
|
|
162
|
+
|
|
163
|
+
- **`resource` is a descriptor reference, not a string.** Deleting a workflow is a type error at the declaration site instead of a readiness failure at deploy.
|
|
164
|
+
- **`payloadFields` derives from `payload`.** The declared field list and the schema your producer emits cannot drift, because there is only one of them. Use `.meta({ label, contentFieldType })` on a field to override a derived label or force `'text'` — nothing in a Zod schema distinguishes a long body from a short string.
|
|
165
|
+
- **`workspaceRoute` gets a type**, and is validated for the leading slash at declaration time. The raw catalog entry type is open, which is how a route rename can point production at a dead path with every gate green.
|
|
166
|
+
|
|
167
|
+
`buildContentPipelineCatalogs` exists because the pipeline catalog is **shared**: every pipeline in a System is an entry in the same `content:catalog/pipeline` record, so spreading two definitions independently would have the second silently replace the first. Call it once per System with all of them.
|
|
168
|
+
|
|
169
|
+
Steps stay catalog data either way. Adding one remains an org-model edit plus a workflow, never a shared-UI or route change — the helper removes no expressiveness, it stops one fact being written in five files.
|
|
170
|
+
|
|
107
171
|
## 2. Produce a Step in a Workflow
|
|
108
172
|
|
|
109
173
|
One workflow per step. The workflow records an **attempt** against the item, tagged with the step it satisfies.
|
|
@@ -178,13 +242,17 @@ export const clipSelectionWorkflow: WorkflowDefinition = {
|
|
|
178
242
|
}
|
|
179
243
|
```
|
|
180
244
|
|
|
181
|
-
`ContentToolMap` is the full surface,
|
|
245
|
+
`ContentToolMap` is the full surface, 19 methods: `createItem`, `getItem`, `listItems`, `updateItem`, `addItemSourceAsset`, `removeItemSourceAsset`, `reorderItemSourceAssets`, `updateItemSourceAsset`, `createAttempt`, `listAttempts`, `updateAttempt`, `createSourceAsset`, `getSourceAsset`, `listSourceAssets`, `updateSourceAsset`, `getDistribution`, `listDistributions`, `createDistribution`, `updateDistribution`. `organizationId` is injected server-side — never pass it from workflow code.
|
|
182
246
|
|
|
183
247
|
**`reviewItem` is deliberately not on this list.** Clearing a `queued` review gate is operator work, done through `elevasis-sdk content:review` (see `apps/docs/content/docs/sdk/sdk/cli-management.mdx`), not something a producer workflow can call. A producer approving its own output collapses the gate the review step exists to provide.
|
|
184
248
|
|
|
185
249
|
### Source Assets
|
|
186
250
|
|
|
187
|
-
`createSourceAsset`, `getSourceAsset`, `listSourceAssets`, and `updateSourceAsset` manage the raw material a producer works from -- an uploaded podcast episode, a transcript, a reference file -- independent of any content item. A producer lists or fetches source assets to pick material, then references the chosen one
|
|
251
|
+
`createSourceAsset`, `getSourceAsset`, `listSourceAssets`, and `updateSourceAsset` manage the raw material a producer works from -- an uploaded podcast episode, a transcript, a reference file -- independent of any content item. A producer lists or fetches source assets to pick material, then references the chosen one when it calls `createItem`. Source assets have their own `kind`-keyed payload envelope, declared per-kind in the content System's OM catalog, the same pattern `createItem`'s payload uses.
|
|
252
|
+
|
|
253
|
+
### Item Membership (Which Assets Are In Which Item)
|
|
254
|
+
|
|
255
|
+
A content item's membership in `content_item_source_assets` -- which source assets it carries, in what slide order, with what per-slide crop and alt text -- is a separate concern from the source asset row itself, and it is owned entirely by four dedicated methods: `addItemSourceAsset`, `removeItemSourceAsset`, `reorderItemSourceAssets`, and `updateItemSourceAsset`. `createItem` also accepts an initial ordered `sourceAssets` list, so a carousel can be created with its full membership in one call; `updateItem` deliberately does not accept a `sourceAssets` field, and every membership change after creation goes through the four methods above.
|
|
188
256
|
|
|
189
257
|
## 3. Give Producers Their Instructions
|
|
190
258
|
|
|
@@ -217,16 +285,37 @@ function ReviewRoute() {
|
|
|
217
285
|
|
|
218
286
|
When the layout itself has to change, compose the primitives — `ContentReviewCard`, `ReviewActionBar`, `PayloadBody`, `AlternatesPanel`, `ProcessingStateStrip` — with `useContentItem`, `useContentItemAttempts`, and `useReviewContentItem`. Read the pipeline's steps through `useContentConfig` rather than hardcoding them, or a new step silently fails to render.
|
|
219
287
|
|
|
220
|
-
## 5.
|
|
288
|
+
## 5. Own the Workspace
|
|
289
|
+
|
|
290
|
+
This section is a contract, not a nav convention. One line divides the content System's UI:
|
|
291
|
+
|
|
292
|
+
**You own the surfaces where content is operated on. The platform owns the surfaces where it is
|
|
293
|
+
observed.**
|
|
294
|
+
|
|
295
|
+
Operating means creating a piece and clearing its review gates. Both are yours, and they are usually
|
|
296
|
+
one screen. Observing means the board, the items list, the attempt history, the distributions, and
|
|
297
|
+
the cross-pipeline review queue — those are shared, they display state, and they do not write.
|
|
298
|
+
|
|
299
|
+
The sidebar is shaped to match: the **`Workspace`** section on top holds your screens; the
|
|
300
|
+
`Content Pipeline` section below it is the shared observation nav.
|
|
221
301
|
|
|
222
|
-
|
|
223
|
-
pipeline section below it is the shared review and tracking nav. Which one you are adding to decides
|
|
224
|
-
which prop you pass.
|
|
302
|
+
### Why the split is drawn here
|
|
225
303
|
|
|
226
|
-
|
|
304
|
+
There are many ways to make content and many ways to review it, and both vary by source, by
|
|
305
|
+
platform, and by pipeline. A shared screen cannot hold that variation — every attempt produces a
|
|
306
|
+
page that fits nobody. What the System actually shares is the data model, the gate mechanics, and
|
|
307
|
+
the cross-pipeline view.
|
|
227
308
|
|
|
228
|
-
|
|
229
|
-
|
|
309
|
+
Nothing is given up by moving the review screen to your side. The rule that a producer cannot
|
|
310
|
+
approve its own output is enforced in two places, neither of them the UI: `reviewItem` is
|
|
311
|
+
deliberately absent from the content tool map, so no workflow can call it, and the HTTP route
|
|
312
|
+
carries `requireAccess(AccessKeys.contentManage)`. A React page of yours calling
|
|
313
|
+
`useReviewContentItem` is a person in a browser holding a JWT — exactly the operator the gate exists
|
|
314
|
+
for.
|
|
315
|
+
|
|
316
|
+
### Declare your Workspace pages
|
|
317
|
+
|
|
318
|
+
Pass `workspaceItems`:
|
|
230
319
|
|
|
231
320
|
```tsx
|
|
232
321
|
import { contentManifest, ContentSidebar } from '@elevasis/ui/features/content'
|
|
@@ -234,19 +323,72 @@ import type { SystemModule } from '@elevasis/ui/provider'
|
|
|
234
323
|
import type { NavItem } from '@elevasis/ui/layout'
|
|
235
324
|
import { IconPencil } from '@tabler/icons-react'
|
|
236
325
|
|
|
237
|
-
const
|
|
326
|
+
const workspaceItems: NavItem[] = [{ label: 'Draft a Post', to: '/content/write', icon: IconPencil, exact: false }]
|
|
238
327
|
|
|
239
328
|
export const customContentManifest: SystemModule = {
|
|
240
329
|
...contentManifest,
|
|
241
|
-
sidebar: () => <ContentSidebar
|
|
330
|
+
sidebar: () => <ContentSidebar workspaceItems={workspaceItems} />
|
|
242
331
|
}
|
|
243
332
|
```
|
|
244
333
|
|
|
245
|
-
Add as many as you like — a drafting screen, a brief builder, a batch generator
|
|
246
|
-
one, the section renders a "No
|
|
334
|
+
Add as many as you like — a drafting screen, a brief builder, a batch generator, a review console.
|
|
335
|
+
Until you declare one, the section renders a "No workspace pages declared yet" hint rather than an
|
|
336
|
+
empty gap.
|
|
337
|
+
|
|
338
|
+
Everything you need to build a combined create-and-review screen is already exported:
|
|
339
|
+
`useReviewContentItem`, `ReviewActionBar`, `ContentReviewCard`, `PayloadBody`, `AlternatesPanel`,
|
|
340
|
+
`ProcessingStateStrip`, `useContentItem`, `useContentItemAttempts`, `useContentConfig`, and
|
|
341
|
+
`resolveContentStepResource`.
|
|
342
|
+
|
|
343
|
+
**`Workspace` is a fixed platform label and is not vocabulary-driven.** Rename the page, not the
|
|
344
|
+
section. (The section was called `Create` before 2026-08-15. `createItems` still works as a
|
|
345
|
+
deprecated alias for one minor; move to `workspaceItems`.)
|
|
346
|
+
|
|
347
|
+
### Point the shared pages at your Workspace
|
|
348
|
+
|
|
349
|
+
A display-only surface with nothing to click is a dead end, so declare where a reviewer should go.
|
|
350
|
+
Set `workspaceRoute` on the pipeline's catalog entry:
|
|
351
|
+
|
|
352
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
'linkedin-post': {
|
|
356
|
+
label: 'LinkedIn Post',
|
|
357
|
+
stepCatalog: 'content:catalog/linkedin-post-steps',
|
|
358
|
+
workspaceRoute: '/content/write'
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
The board, the items list, and the review queue all resolve it: a card or row sitting at an open
|
|
363
|
+
gate opens your screen instead of the shared item page. A step may override it when a pipeline's
|
|
364
|
+
gates are genuinely different screens — a video chain reviewing text candidates, then rendered
|
|
365
|
+
video, then copy plus a schedule, is three screens, not one:
|
|
366
|
+
|
|
367
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
'render-video': { actor: 'workflow', reviewMode: 'required', workspaceRoute: '/content/review-render' }
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Resolution is override-then-fallback — the step's route when it declares one, the pipeline's
|
|
374
|
+
otherwise. Use `resolveContentWorkspaceRoute` rather than reading either field directly.
|
|
375
|
+
|
|
376
|
+
**`reviewMode` says whether, not where.** It has two values, `'required'` and `'none'`. Where a
|
|
377
|
+
required review happens is derived from the route above: a step whose route resolves is reviewed on
|
|
378
|
+
your screen, and one whose route does not is reviewed in the shared queue. The resolved answer is
|
|
379
|
+
`step.reviewVenue` (`'none' | 'queue' | 'workspace'`) — read that rather than recombining
|
|
380
|
+
`reviewMode` and `workspaceRoute` yourself.
|
|
381
|
+
|
|
382
|
+
The field used to take `'live' | 'queued' | 'none'`, where `'live'` and `'queued'` differed only in
|
|
383
|
+
location. They are **not** accepted as aliases: a step still declaring one fails validation and is
|
|
384
|
+
dropped from the pipeline. If you are upgrading, `'live'` and `'queued'` both become `'required'` —
|
|
385
|
+
declare a `workspaceRoute` wherever you previously meant `'live'`.
|
|
247
386
|
|
|
248
|
-
|
|
249
|
-
|
|
387
|
+
**Declaring it is expected, and omitting it is supported.** A pipeline with no `workspaceRoute`
|
|
388
|
+
keeps the shared review page's action bar, so you can clear gates before you have built anything.
|
|
389
|
+
Once you declare a route, that page defers to it and links out instead. The route is an
|
|
390
|
+
app-relative path (`/content/write`); an absolute URL is rejected, because a pipeline entry should
|
|
391
|
+
not be able to send a reviewer off-origin.
|
|
250
392
|
|
|
251
393
|
### Adding to the pipeline nav (rare)
|
|
252
394
|
|
|
@@ -263,14 +405,14 @@ const customItems: NavItem[] = [
|
|
|
263
405
|
|
|
264
406
|
sidebar: () => (
|
|
265
407
|
<ContentSidebar>
|
|
266
|
-
<ContentSidebarMiddle
|
|
408
|
+
<ContentSidebarMiddle workspaceItems={workspaceItems} items={customItems} />
|
|
267
409
|
</ContentSidebar>
|
|
268
410
|
)
|
|
269
411
|
```
|
|
270
412
|
|
|
271
|
-
**Prefer `
|
|
272
|
-
|
|
273
|
-
|
|
413
|
+
**Prefer `workspaceItems` whenever the page is one of yours.** `CONTENT_ITEMS` is a static snapshot
|
|
414
|
+
built from the default vocabulary, so spreading it pins the shared labels at their defaults — a
|
|
415
|
+
tenant that later renames its pipelines to "Campaigns" through `system.config.vocabulary` keeps
|
|
274
416
|
rendering "Pipelines" here, and nothing fails to tell you.
|
|
275
417
|
|
|
276
418
|
Replace `contentManifest` with `customContentManifest` in the local `SYSTEM_MANIFESTS` array and add
|
|
@@ -42,9 +42,9 @@ description: Terminology disambiguation for Organization OS concepts used in the
|
|
|
42
42
|
|
|
43
43
|
**MembershipFeatureConfig** -- retired per-member feature override config. The migration is complete: access is resolved through the unified Access Model using Organization Model System lifecycle, role permissions, diagnostic allowlists, membership scope, and platform-admin bypass.
|
|
44
44
|
|
|
45
|
-
**OrganizationModel** -- top-level semantic contract for an organization. Current primary fields include `version`, `snapshotHash`, `domainMetadata`, `branding`, `navigation`, `ontology`, `systems`, `resources`, `topology`, `identity`, `clients`, `customers`, `offerings`, `roles`, `goals`,
|
|
45
|
+
**OrganizationModel** -- top-level semantic contract for an organization. Current primary fields include `version`, `snapshotHash`, `domainMetadata`, `branding`, `navigation`, `ontology`, `systems`, `resources`, `topology`, `identity`, `clients`, `customers`, `offerings`, `roles`, `goals`, and `knowledge`. `sales`, `prospecting`, `projects`, `statuses`, and `policies` were removed from the top-level contract in the Phase 4 schema cut; do not author against them. `actions` and `entities` remain current schema fields but are compatibility-oriented -- new authoring prefers System-owned ontology/config/resource contracts.
|
|
46
46
|
|
|
47
|
-
**OrganizationModelSystemEntry** -- System node in `OrganizationModel.systems`. Primary authoring fields include `id`, `label`, `description`, `parentSystemId`, `systems`, `lifecycle`, `ui`, `requiresAdmin`, `devOnly`, `responsibleRoleId`, `governedByKnowledge`, `drivesGoals`, `actions`, `
|
|
47
|
+
**OrganizationModelSystemEntry** -- System node in `OrganizationModel.systems`. Primary authoring fields include `id`, `label`, `description`, `parentSystemId`, `systems`, `lifecycle`, `ui`, `requiresAdmin`, `devOnly`, `responsibleRoleId`, `governedByKnowledge`, `drivesGoals`, `actions`, `ontology`, `config`, and `order`. `subsystems` is a retained compatibility input for older projects and should not be used for new recursive Systems. `content` is **retired** — the System schema is strict and rejects it. Author schemas and catalogs in `ontology`, and system-local settings in `config`.
|
|
48
48
|
|
|
49
49
|
**Provider / ElevasisSystemsProvider** -- runtime that registers System modules, resolves System lifecycle against the org model, projects sidebar navigation, and exposes shell helpers through `useElevasisSystems()`.
|
|
50
50
|
|
|
@@ -8,18 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
This catalog is generated from `SYSTEM_INTERFACE_PROFILES` and the derived-readiness checks in `packages/core/src/organization-model/readiness/` (built-in lead-gen/CRM profiles are registered from `packages/core/src/business/acquisition/ontology-validation.ts`).
|
|
10
10
|
|
|
11
|
-
System Interface profiles are a closed platform adoption handshake.
|
|
11
|
+
System Interface profiles are a closed platform adoption handshake. This table is the complete set of profiles a System may declare; a System that adopts none of them omits `apiInterface` entirely and extends behavior through workflows/operations plus ontology, resources, and topology instead.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
|
13
|
+
The catalog is closed because a `readinessProfile` names a capability the platform API gates a route on -- only the platform can mint one. `SystemInterfaceReadinessProfileSchema` accepts any non-empty string, but that is a property of the schema layer, not permission: an uncataloged id names no route, so the declaring System computes as **ready** and every call still fails, which is worse than the `missing-interface` a plain omission reports. Needing an uncataloged capability is a platform request (a route plus a catalog entry), not something to route around by inventing an id.
|
|
14
|
+
|
|
15
|
+
Two validation modes appear below. A **built-in** profile has a validator registered in platform code, so the adopting System needs no `readinessContract`. A **contract-validated** profile is platform-served but its structural requirements differ per adopter, so the adopting System MUST declare a `readinessContract`. `registerBuiltInReadinessProfile` is platform-code-only and is not reachable from a project: it mutates an in-process registry, while the readiness assertion that gates the API runs in the API process.
|
|
16
|
+
|
|
17
|
+
| Profile | Required System path | Interface key | Validation | `readinessContract` |
|
|
18
|
+
| --- | --- | --- | --- | --- |
|
|
19
|
+
| `sales.lead-gen.api` | `sales.lead-gen` | `api` | built-in | not required |
|
|
20
|
+
| `sales.crm.api` | `sales.crm` | `api` | built-in | not required |
|
|
21
|
+
| `sales.lead-gen.crm-handoff` | `sales.lead-gen` | `crm-handoff` | built-in | not required |
|
|
22
|
+
| `content.api` | `content` | `api` | contract | **required** |
|
|
18
23
|
|
|
19
24
|
## `sales.lead-gen.api`
|
|
20
25
|
|
|
21
26
|
- Required System path: `sales.lead-gen`
|
|
22
27
|
- Interface key: `api`
|
|
28
|
+
- Validation: **built-in** -- a platform-registered validator covers this profile; no `readinessContract` is required.
|
|
23
29
|
- Derived-readiness requirements:
|
|
24
30
|
- System Interface marker must be active and scope at least one active `sales.lead-gen` Resource.
|
|
25
31
|
- Object types: `sales.lead-gen:object/list`, `sales.lead-gen:object/company`, `sales.lead-gen:object/contact`.
|
|
@@ -33,6 +39,7 @@ System Interface profiles are a closed platform adoption handshake. Tenant custo
|
|
|
33
39
|
|
|
34
40
|
- Required System path: `sales.crm`
|
|
35
41
|
- Interface key: `api`
|
|
42
|
+
- Validation: **built-in** -- a platform-registered validator covers this profile; no `readinessContract` is required.
|
|
36
43
|
- Derived-readiness requirements:
|
|
37
44
|
- System Interface marker must be active and scope at least one active `sales.crm` Resource.
|
|
38
45
|
- Catalog types with entries: `sales.crm:catalog/crm.pipeline`.
|
|
@@ -42,6 +49,7 @@ System Interface profiles are a closed platform adoption handshake. Tenant custo
|
|
|
42
49
|
|
|
43
50
|
- Required System path: `sales.lead-gen`
|
|
44
51
|
- Interface key: `crm-handoff`
|
|
52
|
+
- Validation: **built-in** -- a platform-registered validator covers this profile; no `readinessContract` is required.
|
|
45
53
|
- Derived-readiness requirements:
|
|
46
54
|
- Derived handoff readiness is evaluated for `sales.lead-gen/crm-handoff`; it is not authored as a separate custom tenant API surface.
|
|
47
55
|
- Lead-gen API readiness requirements must pass for `sales.lead-gen/api`.
|
|
@@ -49,3 +57,15 @@ System Interface profiles are a closed platform adoption handshake. Tenant custo
|
|
|
49
57
|
- Derived scoped resources are active `sales.lead-gen` Resources whose `ontology.usesCatalogs` includes `sales.crm:catalog/crm.pipeline`.
|
|
50
58
|
- Provider readiness must pass for `sales.crm/api`.
|
|
51
59
|
- Topology must include a scoped `systemInterfaceGrant` relationship from consumer `sales.lead-gen/crm-handoff` to provider `sales.crm/api`.
|
|
60
|
+
|
|
61
|
+
## `content.api`
|
|
62
|
+
|
|
63
|
+
- Required System path: `content`
|
|
64
|
+
- Interface key: `api`
|
|
65
|
+
- Validation: **contract-validated** -- the adopting System MUST declare a `readinessContract`.
|
|
66
|
+
- Derived-readiness requirements:
|
|
67
|
+
- Gates every `/api/content/*` and `/api/external/content/*` route, via `CONTENT_API_INTERFACE` in `apps/api/src/business/content/organization-model.ts`.
|
|
68
|
+
- A `readinessContract` is REQUIRED. Unlike the `sales.*` profiles, no built-in validator is registered for this id, so readiness is checked structurally against the contract you declare; omitting it produces `missing-readiness-contract` at deploy preflight.
|
|
69
|
+
- `readinessContract.requiredObjects` must name the content item object owned by `content`, with a scoped `ontology.reads` binding on at least one scoped resource.
|
|
70
|
+
- `readinessContract.requiredCatalogs` must name your pipeline and status catalogs plus the step catalog your pipeline declares, each owned by `content`, non-empty, and carrying a scoped `ontology.usesCatalogs` binding. The step catalog id is project-specific by design.
|
|
71
|
+
- `resourceIds` must scope at least one active Resource; an empty array fails at runtime with `missing-scoped-resources` regardless of what deploy reported.
|