@elevasis/sdk 1.10.0 → 1.12.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 +52 -149
- package/dist/index.d.ts +468 -198
- package/dist/index.js +225 -147
- package/dist/test-utils/index.d.ts +272 -99
- package/dist/test-utils/index.js +4756 -125
- package/dist/types/worker/adapters/llm.d.ts +1 -1
- package/dist/worker/index.js +14 -6
- package/package.json +2 -2
- package/reference/claude-config/rules/agent-start-here.md +14 -14
- package/reference/claude-config/skills/configure/SKILL.md +3 -3
- package/reference/claude-config/skills/setup/SKILL.md +6 -6
- package/reference/claude-config/sync-notes/2026-04-25-auth-role-system-and-settings-roles.md +55 -0
- package/reference/claude-config/sync-notes/2026-04-27-crm-hitl-action-layer-cutover.md +101 -0
- package/reference/cli.mdx +57 -0
- package/reference/deployment/provided-features.mdx +40 -267
- package/reference/examples/organization-model.ts +99 -564
- package/reference/packages/core/src/organization-model/README.md +102 -97
- package/reference/resources/types.mdx +72 -163
- package/reference/scaffold/core/organization-graph.mdx +92 -272
- package/reference/scaffold/core/organization-model.mdx +155 -320
- package/reference/scaffold/index.mdx +3 -0
- package/reference/scaffold/operations/propagation-pipeline.md +4 -1
- package/reference/scaffold/operations/scaffold-maintenance.md +3 -0
- package/reference/scaffold/operations/workflow-recipes.md +13 -10
- package/reference/scaffold/recipes/add-a-feature.md +105 -158
- package/reference/scaffold/recipes/add-a-resource.md +88 -158
- package/reference/scaffold/recipes/customize-organization-model.md +144 -400
- package/reference/scaffold/recipes/extend-a-base-entity.md +11 -8
- package/reference/scaffold/recipes/gate-by-feature-or-admin.md +117 -158
- package/reference/scaffold/recipes/index.md +3 -0
- package/reference/scaffold/reference/contracts.md +107 -435
- package/reference/scaffold/reference/feature-registry.md +11 -8
- package/reference/scaffold/reference/glossary.md +74 -105
- package/reference/scaffold/ui/composition-extensibility.mdx +3 -0
- package/reference/scaffold/ui/customization.md +3 -0
- package/reference/scaffold/ui/feature-flags-and-gating.md +29 -231
- package/reference/scaffold/ui/feature-shell.mdx +53 -219
- package/reference/scaffold/ui/recipes.md +65 -397
- package/reference/claude-config/logs/pre-edit-vibe-gate.log +0 -40
- package/reference/claude-config/logs/scaffold-registry-reminder.log +0 -38
|
@@ -1,241 +1,75 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Feature Shell & Provider Runtime
|
|
3
|
-
description:
|
|
3
|
+
description: Current feature shell contract for flat Organization Model features, manifests, route matching, sidebars, and breadcrumbs.
|
|
4
4
|
---
|
|
5
|
+
<!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
|
|
6
|
+
<!-- Regenerate: pnpm scaffold:sync -->
|
|
5
7
|
|
|
6
|
-
## Overview
|
|
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.
|
|
9
|
-
|
|
10
|
-
Three layers participate, and the word "feature" means something different in each:
|
|
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).
|
|
15
|
-
|
|
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.
|
|
17
|
-
|
|
18
|
-
## Source of Truth
|
|
19
|
-
|
|
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
|
|
28
|
-
|
|
29
|
-
## The FeatureModule Contract
|
|
30
|
-
|
|
31
|
-
A `FeatureModule` describes one shell feature's contribution. Fields:
|
|
32
|
-
|
|
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)
|
|
40
|
-
|
|
41
|
-
`FeatureModule.label` has been removed; nav labels resolve from `navEntry.label` or from the matching organization-model feature's `label` field.
|
|
42
|
-
|
|
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.
|
|
44
|
-
|
|
45
|
-
### ResolvedFeatureModule
|
|
46
|
-
|
|
47
|
-
`ResolvedFeatureModule` extends `FeatureModule` with two additional fields added during provider resolution:
|
|
48
|
-
|
|
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
|
|
51
|
-
|
|
52
|
-
`ResolvedFeatureSemantics.surfaces` carries the full `OrganizationModelSurface[]` objects (not just IDs), so consumers can inspect surface metadata without a separate lookup.
|
|
53
|
-
|
|
54
|
-
## Provider Architecture
|
|
55
|
-
|
|
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
8
|
|
|
90
|
-
|
|
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:
|
|
9
|
+
## Overview
|
|
199
10
|
|
|
200
|
-
|
|
201
|
-
- `bottomNavItems?: FeatureNavEntry[]` -- rendered at the bottom of the shell nav; also subject to organization-model resolution and `filterNavLinks` filtering
|
|
11
|
+
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.
|
|
202
12
|
|
|
203
|
-
|
|
13
|
+
## Source Of Truth
|
|
204
14
|
|
|
205
|
-
|
|
15
|
+
- `packages/core/src/organization-model/defaults.ts` -- default flat feature list
|
|
16
|
+
- `packages/core/src/organization-model/helpers.ts` -- `childrenOf`, `ancestorsOf`, `parentOf`, `topLevel`, `findByPath`
|
|
17
|
+
- `packages/ui/src/features/registry/types.ts` -- `FeatureModule`
|
|
18
|
+
- `packages/ui/src/provider/ElevasisFeaturesProvider.tsx` -- runtime resolver
|
|
19
|
+
- `packages/ui/src/components/navigation/useBreadcrumbs.ts` -- breadcrumb derivation
|
|
206
20
|
|
|
207
|
-
|
|
21
|
+
## FeatureModule
|
|
208
22
|
|
|
209
|
-
|
|
23
|
+
```ts
|
|
24
|
+
export interface FeatureModule {
|
|
25
|
+
key: string
|
|
26
|
+
featureId: string
|
|
27
|
+
capabilityIds?: string[]
|
|
28
|
+
icon?: FeatureIconComponent
|
|
29
|
+
sidebar?: FeatureSidebarComponent
|
|
30
|
+
organizationGraph?: { featureId: string }
|
|
31
|
+
}
|
|
32
|
+
```
|
|
210
33
|
|
|
211
|
-
|
|
34
|
+
`featureId` must match an Organization Model feature ID. Structural fields such as route lists, nav labels, and nested links belong on `OrganizationModel.features`.
|
|
212
35
|
|
|
213
|
-
##
|
|
36
|
+
## Shell Model
|
|
214
37
|
|
|
215
|
-
|
|
38
|
+
`useElevasisFeatures()` exposes `shellModel`:
|
|
216
39
|
|
|
217
|
-
|
|
40
|
+
```ts
|
|
41
|
+
{
|
|
42
|
+
features,
|
|
43
|
+
findByPath,
|
|
44
|
+
findById,
|
|
45
|
+
childrenOf,
|
|
46
|
+
ancestorsOf,
|
|
47
|
+
parentOf,
|
|
48
|
+
topLevel,
|
|
49
|
+
uiPositionFor,
|
|
50
|
+
requiresAdminFor,
|
|
51
|
+
devOnlyFor
|
|
52
|
+
}
|
|
53
|
+
```
|
|
218
54
|
|
|
219
|
-
|
|
55
|
+
Sidebar rendering walks `topLevel()` and `childrenOf(id)`. Breadcrumbs resolve `findByPath(location.pathname)` and then map `ancestorsOf(id)`.
|
|
220
56
|
|
|
221
|
-
|
|
57
|
+
## Access
|
|
222
58
|
|
|
223
|
-
|
|
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)
|
|
59
|
+
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.
|
|
226
60
|
|
|
227
|
-
|
|
61
|
+
Routes still need guards:
|
|
228
62
|
|
|
229
|
-
|
|
63
|
+
```tsx
|
|
64
|
+
<ProtectedRoute>
|
|
65
|
+
<FeatureGuard featureKey="sales.crm">
|
|
66
|
+
<Outlet />
|
|
67
|
+
</FeatureGuard>
|
|
68
|
+
</ProtectedRoute>
|
|
69
|
+
```
|
|
230
70
|
|
|
231
|
-
|
|
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.
|
|
71
|
+
Use `AdminGuard` for pages that require platform-admin privileges.
|
|
235
72
|
|
|
236
|
-
##
|
|
73
|
+
## External Shells
|
|
237
74
|
|
|
238
|
-
|
|
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.
|
|
75
|
+
External templates pass `canonicalOrganizationModel` into `ElevasisFeaturesProvider` and derive sidebar links locally from `shellModel`. There is no separate nav config file to keep in sync.
|