@elevasis/sdk 1.10.0 → 1.11.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.
@@ -1,158 +1,102 @@
1
- ---
2
- title: Add a Feature
3
- description: End-to-end walkthrough for adding a new shell feature (e.g., analytics) from org-model key through manifest, routes, and gating.
4
- ---
5
-
6
- # Add a Feature
7
-
8
- End-to-end: add a new shell feature such as `analytics`. Steps are sequential.
9
-
10
- See [glossary.md](../reference/glossary.md) for term disambiguation throughout this recipe (Feature has three distinct contexts). See [contracts.md](../reference/contracts.md) for authoritative TypeScript shapes.
11
-
12
- ---
13
-
14
- ## 1. Decide the feature shape
15
-
16
- A shell feature requires a `feature.id` in the org model's `features[]` array to gate it. You have two options:
17
-
18
- - **Reuse an existing feature** (e.g., `operations`, `monitoring`). The new shell module shares the on/off toggle with the existing feature entry. Fine for sub-modules within the same product area.
19
- - **Add a new feature object** -- add an entry to the `features[]` array in `core/config/organization-model.ts`. This is always a template-local change; no core package change is required.
20
-
21
- For a genuinely new capability (e.g., `analytics`), you add a feature object to the defaults array and author a matching manifest.
22
-
23
- See [glossary.md](../reference/glossary.md) under **Feature** (three contexts).
24
-
25
- ---
26
-
27
- ## 2. Update the organization model
28
-
29
- File: `core/config/organization-model.ts`
30
-
31
- Add a new feature object to the `features[]` array passed to `defineOrganizationModel`.
32
-
33
- ```ts
34
- import { defineOrganizationModel } from '@elevasis/core/organization-model'
35
- ```
36
-
37
- Use typed constants for the 7 platform features (`SALES_FEATURE_ID`, `PROSPECTING_FEATURE_ID`, `PROJECTS_FEATURE_ID`, `OPERATIONS_FEATURE_ID`, `MONITORING_FEATURE_ID`, `SETTINGS_FEATURE_ID`, `SEO_FEATURE_ID`); use string literals for project-specific features you invent.
38
-
39
- ```ts
40
- const foundationOrganizationModelOverride = defineOrganizationModel({
41
- features: [
42
- // ... existing features
43
- {
44
- id: 'analytics',
45
- label: 'Analytics',
46
- enabled: false, // start disabled
47
- entityIds: [],
48
- surfaceIds: [],
49
- resourceIds: [],
50
- capabilityIds: []
51
- }
52
- ],
53
- // ... rest of model
54
- })
55
- ```
56
-
57
- Each field of the feature object:
58
-
59
- - `id` -- unique stable identifier; this is the value `FeatureModule.featureId` must match
60
- - `label` -- display name; used by nav label resolution when no manifest override is provided
61
- - `enabled` -- org-wide default; `MembershipFeatureConfig.features` can override per member
62
- - `entityIds`, `surfaceIds`, `resourceIds`, `capabilityIds` -- semantic references (leave empty to start)
63
-
64
- No domain entry or separate key resolver is needed. The `features[]` array is the sole source of truth.
65
-
66
- **Two-step pattern:** in a template-derived project, the `defineOrganizationModel` output is passed to `createFoundationOrganizationModel(override)` in `core/config/organization-model.ts`. The result exposes `.model`, `.canonical`, and `.homeLabel`. See `external/_template/core/config/organization-model.ts` for the canonical two-step example.
67
-
68
- ---
69
-
70
- ## 3. Author the FeatureModule
71
-
72
- Create `ui/src/features/analytics/manifest.ts`. Full `FeatureModule` shape is in [contracts.md](../reference/contracts.md#featuremodule) (`@elevasis/ui/provider`).
73
-
74
- ```ts
75
- import type { FeatureModule } from '@elevasis/ui/provider'
76
- import { IconChartBar } from '@tabler/icons-react'
77
- import { AnalyticsSidebar } from './sidebar'
78
-
79
- export const analyticsManifest: FeatureModule = {
80
- key: 'analytics',
81
- featureId: 'analytics', // must match a feature.id in the org model's features[] array
82
- navEntry: {
83
- label: 'Analytics',
84
- icon: IconChartBar,
85
- link: '/analytics'
86
- },
87
- sidebar: AnalyticsSidebar,
88
- subshellRoutes: ['/analytics', '/analytics/reports']
89
- }
90
- ```
91
-
92
- Key fields:
93
-
94
- - `featureId` -- the org-model feature ID that gates the entire feature. The provider throws at startup if this ID is not found in the org model's `features[]` array. See [glossary.md](../reference/glossary.md) under **featureId**.
95
- - `sidebar` -- a component that renders the subshell sidebar. Compose from published primitives. See [customization.md](../ui/customization.md).
96
- - `subshellRoutes` -- every path that should activate this feature's sidebar.
97
-
98
- Register the manifest in `ui/src/routes/__root.tsx` by adding it to the `FEATURE_MANIFESTS` array passed to `ElevasisFeaturesProvider`.
99
-
100
- ---
101
-
102
- ## 4. Add routes under the subshell
103
-
104
- Create the TanStack Router layout and child routes.
105
-
106
- Layout file (`ui/src/routes/analytics.tsx`) owns the subshell guard and renders `<Outlet />`:
107
-
108
- ```tsx
109
- import { createFileRoute, Outlet } from '@tanstack/react-router'
110
- import { ProtectedRoute } from '@/features/auth'
111
- import { FeatureGuard } from '@/features/auth/guards/FeatureGuard'
112
-
113
- export const Route = createFileRoute('/analytics')({
114
- component: AnalyticsLayout
115
- })
116
-
117
- function AnalyticsLayout() {
118
- return (
119
- <ProtectedRoute>
120
- <FeatureGuard featureKey="analytics">
121
- <Outlet />
122
- </FeatureGuard>
123
- </ProtectedRoute>
124
- )
125
- }
126
- ```
127
-
128
- Child pages go under `ui/src/routes/analytics/`. See [UI Recipes](../ui/recipes.md) recipe 2 for the nested page pattern.
129
-
130
- ---
131
-
132
- ## 5. Gate the route
133
-
134
- Two independent mechanisms -- use both:
135
-
136
- - `FeatureGuard` (feature-level): blocks access when the org model has the feature key disabled or when the member's `MembershipFeatureConfig` disables it. Always nest inside `ProtectedRoute`.
137
- - `AdminGuard` (admin-level): blocks access for non-admin members. Add this if the feature should only be accessible to admins.
138
-
139
- Full decision table and import paths are in [gate-by-feature-or-admin.md](gate-by-feature-or-admin.md).
140
-
141
- ---
142
-
143
- ## 6. (Optional) Add operations resources that back the feature
144
-
145
- If the feature drives automation (e.g., an analytics pipeline workflow), create the resources in `operations/src/` and optionally map them into the org model via `resourceMappings`. See [add-a-resource.md](add-a-resource.md).
146
-
147
- ---
148
-
149
- ## 7. Verify
150
-
151
- ```bash
152
- pnpm -C ui dev
153
- ```
154
-
155
- - Feature appears in the nav sidebar.
156
- - Route is accessible and the subshell sidebar renders.
157
- - Toggle `features.enabled.analytics` to `false` in `core/config/organization-model.ts` and confirm the nav item disappears and the route redirects.
158
- - Check `FeatureGuard` by navigating directly to `/analytics` with the feature disabled.
1
+ ---
2
+ title: Add a Feature
3
+ description: Add a shell feature using the flat Organization Model feature list, manifest registration, routes, and guards.
4
+ ---
5
+
6
+ # Add a Feature
7
+
8
+ Shell navigation is derived from `OrganizationModel.features`. Feature manifests attach implementation details to those feature IDs; they do not declare sidebar nav structure.
9
+
10
+ ## 1. Add the feature node
11
+
12
+ Edit `core/config/organization-model.ts` and add a feature to the `features` override.
13
+
14
+ ```ts
15
+ const organizationOverride = defineOrganizationModel({
16
+ features: [
17
+ {
18
+ id: 'analytics',
19
+ label: 'Analytics',
20
+ enabled: true,
21
+ path: '/analytics',
22
+ icon: 'chart',
23
+ uiPosition: 'sidebar-primary'
24
+ }
25
+ ]
26
+ })
27
+ ```
28
+
29
+ Use dotted IDs for hierarchy:
30
+
31
+ ```ts
32
+ { id: 'analytics', label: 'Analytics', enabled: true, uiPosition: 'sidebar-primary' },
33
+ { id: 'analytics.reports', label: 'Reports', enabled: true, path: '/analytics/reports' }
34
+ ```
35
+
36
+ Containers omit `path`; leaves provide `path`.
37
+
38
+ ## 2. Add the manifest
39
+
40
+ Create `ui/src/features/analytics/manifest.ts`.
41
+
42
+ ```ts
43
+ import type { FeatureModule } from '@elevasis/ui/provider'
44
+ import { IconChartBar } from '@tabler/icons-react'
45
+ import { AnalyticsSidebar } from './sidebar'
46
+
47
+ export const analyticsManifest: FeatureModule = {
48
+ key: 'analytics',
49
+ featureId: 'analytics',
50
+ icon: IconChartBar,
51
+ sidebar: AnalyticsSidebar
52
+ }
53
+ ```
54
+
55
+ Register it in the `FEATURE_MANIFESTS` array in `ui/src/routes/__root.tsx`.
56
+
57
+ ## 3. Add routes
58
+
59
+ Create TanStack routes whose paths match the feature nodes.
60
+
61
+ ```tsx
62
+ import { createFileRoute, Outlet } from '@tanstack/react-router'
63
+ import { ProtectedRoute, FeatureGuard } from '@elevasis/ui/features/auth'
64
+
65
+ export const Route = createFileRoute('/analytics')({
66
+ component: AnalyticsLayout
67
+ })
68
+
69
+ function AnalyticsLayout() {
70
+ return (
71
+ <ProtectedRoute>
72
+ <FeatureGuard featureKey="analytics">
73
+ <Outlet />
74
+ </FeatureGuard>
75
+ </ProtectedRoute>
76
+ )
77
+ }
78
+ ```
79
+
80
+ ## 4. Add backing resources
81
+
82
+ For workflows or agents that power the feature, declare graph links on the resource metadata:
83
+
84
+ ```ts
85
+ config: {
86
+ resourceId: 'analytics-refresh',
87
+ name: 'Analytics Refresh',
88
+ type: 'workflow',
89
+ version: '1.0.0',
90
+ status: 'prod',
91
+ links: [{ nodeId: 'feature:analytics', kind: 'operates-on' }],
92
+ category: 'production'
93
+ }
94
+ ```
95
+
96
+ ## 5. Verify
97
+
98
+ ```bash
99
+ pnpm -C ui check-types
100
+ pnpm -C ui test
101
+ pnpm -C operations check
102
+ ```
@@ -1,158 +1,85 @@
1
- ---
2
- title: Add a Resource
3
- description: End-to-end walkthrough for adding a new workflow or agent to the deployment spec, declaring relationships, and verifying in the resource inventory.
4
- ---
5
-
6
- # Add a Resource
7
-
8
- End-to-end: add a new workflow or agent to `operations/` and verify it in the platform inventory. Steps are sequential.
9
-
10
- See [glossary.md](../reference/glossary.md) under **Resource**, **DeploymentSpec**, and **Topology**. See [contracts.md](../reference/contracts.md) for `OrganizationModel` and `OrganizationModelResourceMapping` shapes.
11
-
12
- ---
13
-
14
- ## 1. Author the resource
15
-
16
- Create `operations/src/<name>/index.ts`. Follow the anatomy from [workflow-recipes.md](../operations/workflow-recipes.md) recipe 1 for the full `WorkflowDefinition` shape.
17
-
18
- ```ts
19
- import type { WorkflowDefinition } from '@elevasis/sdk'
20
- import { StepType } from '@elevasis/sdk'
21
- import { myInputSchema, myOutputSchema } from '@foundation/types'
22
-
23
- export const myWorkflow: WorkflowDefinition = {
24
- config: {
25
- resourceId: 'my-workflow',
26
- name: 'My Workflow',
27
- type: 'workflow',
28
- version: '1.0.0',
29
- status: 'dev'
30
- },
31
- contract: {
32
- inputSchema: myInputSchema,
33
- outputSchema: myOutputSchema
34
- },
35
- steps: {
36
- run: {
37
- id: 'run',
38
- name: 'Run',
39
- handler: async (rawInput, context) => {
40
- context.logger.info('[run] starting')
41
- // ...
42
- return { result: 'done' }
43
- },
44
- inputSchema: myInputSchema,
45
- outputSchema: myOutputSchema,
46
- next: null
47
- }
48
- },
49
- entryPoint: 'run'
50
- }
51
- ```
52
-
53
- Define input/output schemas in `foundations/types/index.ts`, not inline. Both runtimes import from `@foundation/types`. See [workflow-recipes.md](../operations/workflow-recipes.md) for Zod schema conventions and adapter usage (`llm`, `storage`, `scheduler`, `notifications` from `@elevasis/sdk/worker`).
54
-
55
- **Entity-backed workflows:** if your workflow operates on a domain entity (Project, Deal, Company, etc.), define or reference the entity shape in `foundations/types/entities.ts` rather than declaring an ad-hoc shape here. The entity types extend base contracts from `@elevasis/core/entities` (`BaseProject`, `BaseDeal`, etc.) with project-specific metadata. See [./extend-a-base-entity.md](./extend-a-base-entity.md) for the pattern.
56
-
57
- ---
58
-
59
- ## 2. Register in the DeploymentSpec
60
-
61
- Create an exports barrel at `operations/src/<name>/exports.ts`:
62
-
63
- ```ts
64
- import { myWorkflow } from './index.js'
65
- import type { WorkflowDefinition } from '@elevasis/sdk'
66
-
67
- export const workflows: WorkflowDefinition[] = [myWorkflow]
68
- export const agents: never[] = []
69
- ```
70
-
71
- Then spread into the top-level spec at `operations/src/index.ts`:
72
-
73
- ```ts
74
- import * as myFeature from './my-feature/exports.js'
75
-
76
- const org: DeploymentSpec = {
77
- version: '0.1.0',
78
- workflows: [...existing.workflows, ...myFeature.workflows],
79
- agents: [...existing.agents, ...myFeature.agents]
80
- }
81
- ```
82
-
83
- Use `.js` extensions in imports even though source is TypeScript -- required for ESM interoperability.
84
-
85
- ---
86
-
87
- ## 3. (Optional) Declare relationships
88
-
89
- If the resource triggers another resource, uses a human checkpoint, or depends on an integration, declare those relationships on the `DeploymentSpec`. See [glossary.md](../reference/glossary.md) under **Topology** for the three edge types (`triggers`, `uses`, `approval`).
90
-
91
- ```ts
92
- const org: DeploymentSpec = {
93
- // ...
94
- relationships: {
95
- 'my-workflow': {
96
- triggers: { workflows: ['email-notification'] }
97
- }
98
- },
99
- humanCheckpoints: [
100
- {
101
- resourceId: 'approval-gate',
102
- name: 'Approve before sending',
103
- type: 'human',
104
- version: '1.0.0',
105
- status: 'prod',
106
- routesTo: { workflows: ['my-workflow'] }
107
- }
108
- ]
109
- }
110
- ```
111
-
112
- Full relationship and checkpoint types are defined in `@elevasis/sdk` (`DeploymentSpec`). Resources are discovered live via `pnpm elevasis-sdk project:list` or by globbing `operations/resources/**` directly.
113
-
114
- ---
115
-
116
- ## 4. (Optional) Map to a domain
117
-
118
- To make the resource referenceable from the org model (so the Operations graph and Command View can link to it), add an entry to `resourceMappings` in `core/config/organization-model.ts`:
119
-
120
- ```ts
121
- resourceMappings: [
122
- {
123
- id: 'my-workflow',
124
- resourceId: 'my-workflow',
125
- resourceType: 'workflow',
126
- featureIds: ['operations'],
127
- label: 'My Workflow'
128
- }
129
- ]
130
- ```
131
-
132
- See `OrganizationModelResourceMapping` in [contracts.md](../reference/contracts.md) for the full shape.
133
-
134
- ---
135
-
136
- ## 5. Verify resource inventory
137
-
138
- Resources are discovered live via `pnpm elevasis-sdk project:list` or by globbing `operations/resources/**` directly. Confirm the new resource appears with the correct `resourceId`, `version`, and `status`.
139
-
140
- ---
141
-
142
- ## 6. Verify
143
-
144
- Validate and deploy:
145
-
146
- ```bash
147
- pnpm -C operations run check # validate resource definitions
148
- pnpm -C operations run deploy # deploy to dev
149
- ```
150
-
151
- Execute via the platform CLI from the project root:
152
-
153
- ```bash
154
- pnpm exec elevasis describe Elevasis/my-workflow
155
- pnpm exec elevasis exec Elevasis/my-workflow --input '{"field": "value"}'
156
- ```
157
-
158
- Use `--async` for long-running resources. Use `pnpm exec elevasis --prod exec ...` (flag before `exec`) for production. See [workflow-recipes.md](../operations/workflow-recipes.md) recipe 3 for the low-level frontend trigger pattern (`useApiClient` + `useMutation`). For the higher-level UI pattern using `RunResourceButton`, `useExecuteResource`, and `ZodFormRenderer`, see [../ui/recipes.md](../ui/recipes.md) recipe 6.
1
+ ---
2
+ title: Add a Resource
3
+ description: Add a workflow or agent with resource metadata, graph links, and deployment verification.
4
+ ---
5
+
6
+ # Add a Resource
7
+
8
+ Resources are workflows, agents, triggers, integrations, external systems, or human checkpoints collected in a `DeploymentSpec`. They link into the Organization Model graph through resource metadata, not through `OrganizationModel` mapping tables.
9
+
10
+ ## 1. Author the resource
11
+
12
+ ```ts
13
+ import type { WorkflowDefinition } from '@elevasis/sdk'
14
+
15
+ export const myWorkflow: WorkflowDefinition = {
16
+ config: {
17
+ resourceId: 'my-workflow',
18
+ name: 'My Workflow',
19
+ type: 'workflow',
20
+ version: '1.0.0',
21
+ status: 'dev',
22
+ links: [{ nodeId: 'feature:operations', kind: 'operates-on' }],
23
+ category: 'production'
24
+ },
25
+ contract: {
26
+ inputSchema,
27
+ outputSchema
28
+ },
29
+ steps: {
30
+ run: {
31
+ id: 'run',
32
+ name: 'Run',
33
+ handler: async (_input, context) => {
34
+ context.logger.info('[my-workflow] starting')
35
+ return { ok: true }
36
+ },
37
+ inputSchema,
38
+ outputSchema,
39
+ next: null
40
+ }
41
+ },
42
+ entryPoint: 'run'
43
+ }
44
+ ```
45
+
46
+ `links[].nodeId` uses the kind-prefixed graph grammar, such as `feature:sales.crm`, `integration:instantly`, or `capability:operations.queue.review`.
47
+
48
+ `category` is one of `production`, `diagnostic`, `internal`, or `testing`.
49
+
50
+ ## 2. Register in the deployment spec
51
+
52
+ ```ts
53
+ import { myWorkflow } from './my-workflow/index.js'
54
+
55
+ export const org = {
56
+ version: '0.1.0',
57
+ workflows: [myWorkflow],
58
+ agents: []
59
+ }
60
+ ```
61
+
62
+ Use `.js` extensions in TypeScript source imports for ESM compatibility.
63
+
64
+ ## 3. Declare runtime relationships
65
+
66
+ Use `DeploymentSpec.relationships` for execution topology:
67
+
68
+ ```ts
69
+ relationships: {
70
+ 'my-workflow': {
71
+ triggers: { workflows: ['email-notification'] },
72
+ uses: { integrations: ['hubspot'] }
73
+ }
74
+ }
75
+ ```
76
+
77
+ Use `config.links` for semantic graph binding and `relationships` for runtime execution relationships.
78
+
79
+ ## 4. Verify
80
+
81
+ ```bash
82
+ pnpm -C operations check
83
+ pnpm -C operations deploy
84
+ pnpm exec elevasis describe Elevasis/my-workflow
85
+ ```