@elevasis/sdk 1.9.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.
Files changed (31) hide show
  1. package/dist/cli.cjs +228 -190
  2. package/dist/index.d.ts +127 -154
  3. package/dist/index.js +15 -139
  4. package/dist/test-utils/index.d.ts +8270 -0
  5. package/dist/test-utils/index.js +20070 -0
  6. package/dist/types/worker/index.d.ts +20 -1
  7. package/dist/worker/index.js +7 -4
  8. package/package.json +8 -2
  9. package/reference/_navigation.md +15 -1
  10. package/reference/_reference-manifest.json +56 -0
  11. package/reference/claude-config/sync-notes/2026-04-24-test-utils-and-template-tests.md +73 -0
  12. package/reference/claude-config/sync-notes/2026-04-24-ui-consolidation-and-sdk-cli-train.md +1 -1
  13. package/reference/deployment/provided-features.mdx +40 -267
  14. package/reference/examples/organization-model.ts +96 -564
  15. package/reference/packages/core/src/organization-model/README.md +101 -97
  16. package/reference/packages/core/src/test-utils/README.md +5 -10
  17. package/reference/packages/ui/src/test-utils/README.md +5 -0
  18. package/reference/resources/types.mdx +72 -163
  19. package/reference/scaffold/core/organization-graph.mdx +89 -272
  20. package/reference/scaffold/core/organization-model.mdx +149 -320
  21. package/reference/scaffold/operations/workflow-recipes.md +94 -1
  22. package/reference/scaffold/recipes/add-a-feature.md +102 -158
  23. package/reference/scaffold/recipes/add-a-resource.md +85 -158
  24. package/reference/scaffold/recipes/customize-organization-model.md +141 -400
  25. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +114 -158
  26. package/reference/scaffold/reference/contracts.md +62 -148
  27. package/reference/scaffold/reference/feature-registry.md +8 -8
  28. package/reference/scaffold/reference/glossary.md +71 -105
  29. package/reference/scaffold/ui/feature-flags-and-gating.md +27 -232
  30. package/reference/scaffold/ui/feature-shell.mdx +50 -219
  31. package/reference/scaffold/ui/recipes.md +62 -397
@@ -1,241 +1,72 @@
1
1
  ---
2
2
  title: Feature Shell & Provider Runtime
3
- description: Organization OS UI Shell Runtime and Features layer architecture covering FeatureModule manifests, ElevasisFeaturesProvider, route-to-sidebar dispatch, and organization-model-aware runtime resolution.
3
+ description: Current feature shell contract for flat Organization Model features, manifests, route matching, sidebars, and breadcrumbs.
4
4
  ---
5
5
 
6
6
  ## Overview
7
7
 
8
- Within Organization OS, the feature shell spans two layers: the **UI Shell Runtime** that resolves shared nav/sidebar behavior, and the **Features** layer that declares what each feature contributes. It lets command-center and external template consumers compose the same nav, sidebars, and subshell routes from a small set of manifests. It is intentionally a thin layer: manifests describe what a feature contributes, the provider resolves that into a runtime shell model, and consumers still own their own routes, branding, and app-local nav.
8
+ The feature shell derives app navigation from `OrganizationModel.features`. Feature manifests provide implementation hooks such as icons and sidebars; they no longer own structural navigation.
9
9
 
10
- Three layers participate, and the word "feature" means something different in each:
10
+ ## Source Of Truth
11
11
 
12
- - **Platform capabilities** -- product-facing areas documented under `technical/features/` (Execution Engine, Workflows, Agents, Operations, etc.). These are not one-to-one with shell features.
13
- - **Shell features** -- features in `packages/ui/src/features/*`. Seven are manifest-backed (`crm`, `lead-gen`, `projects`, `operations`, `monitoring`, `settings`, `seo`); two are utility features without manifests (`auth`, `dashboard`).
14
- - **Organization-model features** -- feature objects in `@repo/core/organization-model` with shape `{ id, label, enabled, entityIds, surfaceIds, resourceIds, capabilityIds }`. The 7 defaults are `crm`, `lead-gen`, `projects`, `operations`, `monitoring`, `settings`, `seo`. See [Organization Model](../core/organization-model.mdx).
12
+ - `packages/core/src/organization-model/defaults.ts` -- default flat feature list
13
+ - `packages/core/src/organization-model/helpers.ts` -- `childrenOf`, `ancestorsOf`, `parentOf`, `topLevel`, `findByPath`
14
+ - `packages/ui/src/features/registry/types.ts` -- `FeatureModule`
15
+ - `packages/ui/src/provider/ElevasisFeaturesProvider.tsx` -- runtime resolver
16
+ - `packages/ui/src/components/navigation/useBreadcrumbs.ts` -- breadcrumb derivation
15
17
 
16
- One shell feature can contain several platform capabilities; a manifest's `featureId` directly matches `feature.id` in the org model with no alias layer.
18
+ ## FeatureModule
17
19
 
18
- ## Source of Truth
20
+ ```ts
21
+ export interface FeatureModule {
22
+ key: string
23
+ featureId: string
24
+ capabilityIds?: string[]
25
+ icon?: FeatureIconComponent
26
+ sidebar?: FeatureSidebarComponent
27
+ organizationGraph?: { featureId: string }
28
+ }
29
+ ```
19
30
 
20
- - `packages/ui/src/features/registry/types.ts` -- `FeatureModule` contract
21
- - `packages/ui/src/features/registry/manifests.ts` -- published `FEATURE_MANIFESTS` convenience map
22
- - `packages/ui/src/provider/ElevasisFeaturesProvider.tsx` -- runtime composition
23
- - `packages/ui/src/provider/FeatureShell.tsx` -- route-to-sidebar dispatch
24
- - `packages/ui/src/provider/resolvers/{RouteResolver,NavResolver}.ts` -- pure path/nav helpers
25
- - `packages/ui/src/provider/validateManifests.ts` -- startup-time manifest validation
26
- - `packages/ui/src/provider/published.ts` -- headless published barrel
27
- - `apps/command-center/src/routes/__root.tsx` -- reference composition
31
+ `featureId` must match an Organization Model feature ID. Structural fields such as route lists, nav labels, and nested links belong on `OrganizationModel.features`.
28
32
 
29
- ## The FeatureModule Contract
33
+ ## Shell Model
30
34
 
31
- A `FeatureModule` describes one shell feature's contribution. Fields:
35
+ `useElevasisFeatures()` exposes `shellModel`:
32
36
 
33
- - `key` -- unique stable identifier (e.g., `'crm'`, `'projects'`)
34
- - `featureId` -- **required**; the `feature.id` value from the org model that this module maps to; used by `useFeatureAccess()` for gating
35
- - `capabilityIds` -- semantic references into the organization model
36
- - `navEntry` -- top-level nav contribution (label, icon, optional `link`, optional nested `links`, optional `requiresAdmin`, optional onboarding-tour ID, optional `featureKey` override when nav identity must diverge from access identity)
37
- - `sidebar` -- optional `ComponentType` for the feature's subshell sidebar
38
- - `subshellRoutes` -- routes the feature owns under its subshell
39
- - `organizationGraph` -- **Operations-only**; bridges a manifest to an organization-model surface (ignored by other features)
37
+ ```ts
38
+ {
39
+ features,
40
+ findByPath,
41
+ findById,
42
+ childrenOf,
43
+ ancestorsOf,
44
+ parentOf,
45
+ topLevel,
46
+ uiPositionFor,
47
+ requiresAdminFor,
48
+ devOnlyFor
49
+ }
50
+ ```
40
51
 
41
- `FeatureModule.label` has been removed; nav labels resolve from `navEntry.label` or from the matching organization-model feature's `label` field.
52
+ Sidebar rendering walks `topLevel()` and `childrenOf(id)`. Breadcrumbs resolve `findByPath(location.pathname)` and then map `ancestorsOf(id)`.
42
53
 
43
- Manifests are validated at provider registration via `validateManifests()`. Unknown `featureId` or `capabilityIds` (measured against the resolved organization model) throw with all violations collected into one error.
54
+ ## Access
44
55
 
45
- ### ResolvedFeatureModule
56
+ Feature access is keyed by Organization Model feature ID. `requiresAdmin` and `devOnly` inherit from ancestor feature nodes and are applied when deriving visible sidebar entries.
46
57
 
47
- `ResolvedFeatureModule` extends `FeatureModule` with two additional fields added during provider resolution:
58
+ Routes still need guards:
48
59
 
49
- - `access: ResolvedFeatureAccess` -- `{ featureId: string, enabled: boolean }` -- the resolved access state for this feature
50
- - `semantics: ResolvedFeatureSemantics` -- `{ capabilityIds, surfaceIds, surfaces }` -- merged semantic identifiers derived from both manifest declarations and organization-model surface data
60
+ ```tsx
61
+ <ProtectedRoute>
62
+ <FeatureGuard featureKey="sales.crm">
63
+ <Outlet />
64
+ </FeatureGuard>
65
+ </ProtectedRoute>
66
+ ```
51
67
 
52
- `ResolvedFeatureSemantics.surfaces` carries the full `OrganizationModelSurface[]` objects (not just IDs), so consumers can inspect surface metadata without a separate lookup.
68
+ Use `AdminGuard` for pages that require platform-admin privileges.
53
69
 
54
- ## Provider Architecture
70
+ ## External Shells
55
71
 
56
- The provider layer is composed of several focused context providers. `ElevasisCoreProvider` and `ElevasisFeaturesProvider` are the two consumer-facing entry points; the others are internal building blocks also published for advanced use.
57
-
58
- ### ElevasisCoreProvider
59
-
60
- `ElevasisCoreProvider` is the headless root provider for Elevasis-powered applications. It is pure auth + API with no style side-effects -- no CSS variables, no `data-elevasis-scheme`, no font loading. When `apiUrl` is provided it composes the full provider stack:
61
-
62
- `QueryClientProvider` -> `AuthProvider` -> `ApiClientProvider` -> `ProfileProvider` -> `OrganizationProvider` -> `ElevasisServiceProvider` -> `NotificationProvider` -> `InitializationProvider`
63
-
64
- Consumers that need Mantine theming use `ElevasisUIProvider` (internal) or `ElevasisProvider` instead. `ElevasisCoreProvider` is exported from `packages/ui/src/provider/published.ts` for headless SDK consumers.
65
-
66
- ### ElevasisServiceProvider
67
-
68
- `ElevasisServiceProvider` (from `ElevasisServiceContext.tsx`) is the standalone service context. It accepts three props directly: `apiRequest`, `organizationId`, and `isReady`. `ElevasisCoreProvider` composes this internally after org resolution; advanced consumers can mount it standalone for testing or embedding.
69
-
70
- `useElevasisServices()` reads this context and throws if used outside a provider. Consumed throughout the shared component library wherever API requests are needed.
71
-
72
- ### AppearanceProvider
73
-
74
- `AppearanceProvider` (from `AppearanceContext.tsx`) supplies an `AppearanceConfig` to the tree: `{ background?: ReactNode, loader?: ReactNode }`. The `background` field controls layers rendered behind app content; `loader` controls loading-state elements. Defaults are set in the provider rather than at context creation to avoid importing heavy visual components at module scope.
75
-
76
- `useAppearance()` reads this context and throws if used outside a provider.
77
-
78
- ### NotificationProvider
79
-
80
- `NotificationProvider` (from `NotificationContext.tsx`) accepts a pluggable `NotificationAdapter` for routing notifications to any library. The adapter interface is `{ success, error, info, warning, apiError }`. `ElevasisUIProvider` wires the Mantine adapter automatically.
81
-
82
- When no provider is present in the tree, `useNotificationAdapter()` falls back to a console-based adapter (not a no-op), so template consumers work without Mantine. The hook never throws.
83
-
84
- ### Memoization Strategy
85
-
86
- All computed values inside `ElevasisFeaturesProvider` are wrapped in `useMemo()` with precise dependency tracking. Resolved features, nav items, shell model, organization graph, and the context value object are each memoized separately so downstream consumers only re-render when their specific inputs change.
87
-
88
- ## Provider Responsibilities
89
-
90
- `ElevasisFeaturesProvider` owns:
91
-
92
- - registration of shared feature manifests
93
- - feature-flag-aware nav contribution
94
- - route-to-sidebar subshell dispatch (via `shellRuntime.resolveRoute`)
95
- - provider-scoped shared runtime context
96
- - resolved shell-model composition and shell-native route matching
97
- - organization-model-aware nav label and path resolution
98
- - resolved feature output (no legacy `shellModule` wrapper)
99
-
100
- It does **not** own:
101
-
102
- - TanStack file-based route registration
103
- - app branding, topbar behavior, admin entries, assistant/context glue
104
-
105
- Consumers keep thin local route wrappers and app-local nav where needed.
106
-
107
- ## Runtime Flow
108
-
109
- 1. The app defines a manifest list (often by spreading `FEATURE_MANIFESTS` and overriding entries).
110
- 2. The app optionally resolves an organization model and passes it to the provider.
111
- 3. The provider combines `useFeatureAccess()` with the org model's `features[]` array to compute enabled features.
112
- 4. Nav labels and nav paths resolve from the matching `feature.label` in `organizationModel.features` and from `organizationModel.navigation.surfaces` when present.
113
- 5. The provider exposes `shellModel`, `shellRuntime`, resolved feature access, `organizationGraph`, and shared runtime inputs via `useElevasisFeatures()`.
114
- 6. `FeatureShell` calls `shellRuntime.resolveRoute(currentPath)`:
115
- - `matched` -- render the feature's sidebar subshell
116
- - `hidden` -- render `FeatureUnavailableState`
117
- - `unmatched` -- render plain children (consumer owns the route)
118
-
119
- A route resolves as `hidden` when the matched nav link meets either of these conditions: its `featureKey` fails the `isFeatureEnabled()` check, or its path matches an entry in `disabledSubsectionPaths`. Both checks are applied recursively through nested nav links.
120
-
121
- Consumer nav derivation runs locally from `shellModel.navItems`; the provider no longer exposes `visibleNavItems`.
122
-
123
- ## Provider-Scoped Runtime Context
124
-
125
- `useElevasisFeatures()` exposes:
126
-
127
- - `shellModel` -- `{ navItems: ResolvedShellNavItem[] }` -- the full resolved nav list
128
- - `shellRuntime` -- `{ resolveRoute: (path) => ResolvedShellRouteMatch }` -- route dispatch
129
- - `resolvedFeatures` -- all `ResolvedFeatureModule[]` regardless of enabled state
130
- - `enabledResolvedFeatures` -- filtered to `access.enabled === true`
131
- - `timeRange`
132
- - `operationsApiUrl`, `operationsSSEManager`
133
- - `deliveryApiUrl`, `deliverySSEManager`
134
- - `organizationModel`
135
- - `organizationGraph` (resolved from `operations.organization-graph` surface; see [Organization Graph](../core/organization-graph.mdx))
136
- - `disabledSubsectionPaths` -- used by consumers like `_template` to hide specific subsections (e.g., `/settings/appearance`)
137
- - `isFeatureEnabled(key: string): boolean` -- checks both membership flag and organization-model feature state
138
- - `getResolvedFeature(key: string): ResolvedFeatureModule | undefined` -- looks up a resolved feature by its `key` field (module key, not access key)
139
-
140
- ## Nav Resolution
141
-
142
- ### ResolvedShellNavItem
143
-
144
- `ResolvedShellNavItem` extends `FeatureNavEntry` with two additional fields:
145
-
146
- - `placement: 'primary' | 'bottom'` -- where the item appears in the shell nav; feature manifests always produce `'primary'`; `appShellOverrides.bottomNavItems` produce `'bottom'`
147
- - `source: 'app' | 'feature'` -- whether the item came from a manifest (`'feature'`) or from `appShellOverrides` (`'app'`)
148
- - `featureId?: string` -- the feature ID associated with this nav item for gating checks
149
-
150
- `shellModel.navItems` contains the merged and filtered list of all `ResolvedShellNavItem`s from both manifest features and `appShellOverrides`.
151
-
152
- ### filterNavLinks
153
-
154
- `filterNavLinks()` in `ElevasisFeaturesProvider.tsx` recursively removes gated and disabled-subsection links from a `FeatureNavLink[]` array. A link is removed if its `featureKey` fails `isFeatureEnabled()` or if its path matches any entry in `disabledSubsectionPaths`. The function recurses into nested `links` arrays before deciding whether a parent with now-empty children should be retained or dropped.
155
-
156
- ## Access Resolution
157
-
158
- Shell feature-module keys map directly to feature IDs in the organization model. There is no alias layer:
159
-
160
- - `createFeatureAccessHook` is the factory that produces `useFeatureAccess`. (Old name `createUseFeatureAccess` is re-exported as `@deprecated`.)
161
- - `FeatureModule.featureId` must match a `feature.id` value in the org model's `features[]` array. The provider throws at startup if the ID is not found.
162
- - `MembershipFeatureConfig.features` is `Record<string, boolean>` -- a dynamic map keyed by feature ID. Any feature can be overridden per member without schema changes.
163
- - The provider fallback for missing feature access identity is retired -- explicit `featureId` is required.
164
-
165
- ## Published Surface
166
-
167
- `packages/ui/src/provider/published.ts` is intentionally headless: it exports the provider, types, and hooks, but no Mantine-dependent visual provider pieces. External consumers can adopt the feature/provider contract without pulling the full internal visual surface.
168
-
169
- All nine features are published as individual subpath exports from `@elevasis/ui`:
170
-
171
- - `@elevasis/ui/features/auth` -- `ProtectedRoute`, `AdminGuard`, `FeatureGuard`, `useUserProfile` (utility feature; no manifest)
172
- - `@elevasis/ui/features/dashboard` -- `Dashboard`, `ResourceOverview`, `RecentExecutionsByResource`, `UnresolvedErrorsTeaser` (utility feature; no manifest)
173
- - `@elevasis/ui/features/crm`
174
- - `@elevasis/ui/features/lead-gen`
175
- - `@elevasis/ui/features/projects`
176
- - `@elevasis/ui/features/monitoring`
177
- - `@elevasis/ui/features/operations`
178
- - `@elevasis/ui/features/seo`
179
- - `@elevasis/ui/features/settings`
180
-
181
- The `auth` and `dashboard` features are not in `FEATURE_MANIFESTS` and are not registered with `ElevasisFeaturesProvider`. They are standalone published feature modules consumed directly by host apps.
182
-
183
- ## Composition Patterns
184
-
185
- ### Command-center composition
186
-
187
- `apps/command-center/src/routes/__root.tsx`:
188
-
189
- 1. imports the mounted manifest list
190
- 2. resolves `COMMAND_CENTER_ORGANIZATION_MODEL`
191
- 3. passes manifests, organization model, time range, operations API URL, and SSE manager to `ElevasisFeaturesProvider`
192
- 4. keeps app-local nav entries for dashboard, admin, archive (passed into `appShellOverrides`)
193
- 5. derives filtered nav locally from `shellModel.navItems`
194
- 6. lets `FeatureShell` dispatch subshell sidebars for matched routes
195
-
196
- ### appShellOverrides
197
-
198
- `appShellOverrides` is an `AppShellOverrides` prop on `ElevasisFeaturesProvider` that lets the host app inject nav items outside the manifest registry:
199
-
200
- - `primaryNavItems?: FeatureNavEntry[]` -- prepended before feature nav items in the primary nav position; organization-model label and path resolution is applied to these entries
201
- - `bottomNavItems?: FeatureNavEntry[]` -- rendered at the bottom of the shell nav; also subject to organization-model resolution and `filterNavLinks` filtering
202
-
203
- Both arrays go through the same `isFeatureEnabled()` and `disabledSubsectionPaths` filtering as manifest-derived items. Items whose `featureKey` is disabled, or that have only disabled nested links and no direct `link`, are dropped entirely.
204
-
205
- Nine feature modules are published (see **Published Surface** above). Six are currently mounted in command-center: `leadGenManifest`, `crmManifest`, `projectsManifest`, `operationsManifest`, `monitoringManifest`, `settingsManifest`. The remaining three (`seoManifest`, `auth`, `dashboard`) are published but not mounted through `ElevasisFeaturesProvider` in command-center -- `auth` and `dashboard` are utility features consumed directly, while `seoManifest` is available for composition but not wired into the current command-center shell.
206
-
207
- ### External-consumer composition
208
-
209
- External shells consume the published `@elevasis/ui` provider surface. `_template/ui` imports individual manifests, composes a local `FEATURE_MANIFESTS: FeatureModule[]` array, and passes `canonicalOrganizationModel` (from `@foundation/config/organization-model`) into the provider. Host-local nav (home/dashboard) remains app-owned -- the provider covers shared shell features, not total shell ownership.
210
-
211
- See [Composition & Extensibility](./composition-extensibility.mdx) for the sidebar/page override patterns consumers use to customize shared features without forking.
212
-
213
- ## Feature-Specific Sidebar Behavior
214
-
215
- ### CRM Sidebar
216
-
217
- The CRM sidebar (`packages/ui/src/features/crm/sidebar/`) exports `CrmSidebar`, `CrmSidebarTop`, and `CrmSidebarMiddle`. `SavedViewsPanel` lives in `packages/ui/src/features/crm/workbench/SavedViewsPanel.tsx` and is exported from the CRM workbench barrel; it provides the saved contact views panel. It is currently commented out of the default `CrmSidebarMiddle` layout while the CRM sidebar section model is being reworked, but can be re-included explicitly when composing a custom sidebar.
218
-
219
- ### Operations Sidebar
220
-
221
- `OperationsSidebarTop` in `packages/ui/src/features/operations/sidebar/OperationsSidebarTop.tsx` is context-aware by route:
222
-
223
- - Returns `null` for sessions (`/operations/sessions`) and command-view (`/operations/command-view`) routes -- these sections own their own top-area UI
224
- - Shows a "Resource Overview" navigation button for the resources section (`/operations/resources`)
225
- - Returns `null` for all other paths (e.g., the operations index)
226
-
227
- This pattern avoids hardcoding sidebar top content in the parent and lets each operations sub-section declare its own top panel entry point.
228
-
229
- ## Testing
230
-
231
- - `createTestFeaturesProvider` fixture at `packages/ui/src/provider/createTestFeaturesProvider.tsx` (internal; exported from `provider/index.ts`) gives tests a pre-wired provider with configurable organization model and feature access.
232
- - Resolver modules have focused unit tests (`RouteResolver.test.ts`, `NavResolver.test.ts`).
233
- - `validateManifests.test.ts` covers manifest validation against the organization model.
234
- - `ElevasisFeaturesProvider.test.tsx`, `FeatureShell.test.tsx`, and `feature-contract.test.ts` cover runtime composition and the published surface.
235
-
236
- ## Key Conceptual Distinctions
237
-
238
- - **Platform capability vs. shell feature** -- capabilities are the product map; shell features are manifest-backed UI surfaces.
239
- - **Shell feature key vs. org-model feature id** -- both are the same value (e.g., `crm`). `FeatureModule.featureId` directly matches `feature.id` in the org model; there is no alias layer.
240
- - **Feature vs. capability** -- a feature object in the org model carries `entityIds`, `surfaceIds`, `resourceIds`, and `capabilityIds`; capabilities are one kind of semantic reference a feature can hold.
241
- - **Provider-owned vs. consumer-owned** -- provider owns shared manifests, nav contribution, sidebar dispatch, shared runtime context; consumers own route files, branding, topbar behavior, admin entries.
72
+ External templates pass `canonicalOrganizationModel` into `ElevasisFeaturesProvider` and derive sidebar links locally from `shellModel`. There is no separate nav config file to keep in sync.