@elevasis/core 0.10.0 → 0.11.1

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 (58) hide show
  1. package/dist/index.d.ts +69 -159
  2. package/dist/index.js +324 -613
  3. package/dist/organization-model/index.d.ts +69 -159
  4. package/dist/organization-model/index.js +324 -613
  5. package/dist/test-utils/index.d.ts +192 -45
  6. package/dist/test-utils/index.js +260 -600
  7. package/package.json +1 -1
  8. package/src/__tests__/template-core-compatibility.test.ts +73 -91
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +94 -182
  10. package/src/auth/multi-tenancy/index.ts +20 -17
  11. package/src/auth/multi-tenancy/memberships/api-schemas.ts +142 -126
  12. package/src/auth/multi-tenancy/memberships/index.ts +26 -22
  13. package/src/auth/multi-tenancy/permissions.test.ts +42 -0
  14. package/src/auth/multi-tenancy/permissions.ts +104 -0
  15. package/src/organization-model/README.md +102 -97
  16. package/src/organization-model/__tests__/defaults.test.ts +19 -6
  17. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +24 -93
  18. package/src/organization-model/__tests__/graph.test.ts +82 -894
  19. package/src/organization-model/__tests__/resolve.test.ts +59 -690
  20. package/src/organization-model/__tests__/schema.test.ts +83 -407
  21. package/src/organization-model/contracts.ts +4 -3
  22. package/src/organization-model/defaults.ts +277 -141
  23. package/src/organization-model/domains/features.ts +31 -22
  24. package/src/organization-model/domains/navigation.ts +27 -20
  25. package/src/organization-model/foundation.ts +42 -54
  26. package/src/organization-model/graph/build.ts +42 -217
  27. package/src/organization-model/graph/index.ts +4 -4
  28. package/src/organization-model/graph/link.ts +10 -0
  29. package/src/organization-model/graph/schema.ts +21 -16
  30. package/src/organization-model/graph/types.ts +10 -10
  31. package/src/organization-model/helpers.ts +74 -0
  32. package/src/organization-model/index.ts +7 -7
  33. package/src/organization-model/organization-graph.mdx +89 -272
  34. package/src/organization-model/organization-model.mdx +152 -320
  35. package/src/organization-model/published.ts +20 -19
  36. package/src/organization-model/resolve.ts +8 -33
  37. package/src/organization-model/schema.ts +63 -205
  38. package/src/organization-model/types.ts +12 -11
  39. package/src/platform/constants/versions.ts +3 -3
  40. package/src/platform/registry/__tests__/command-view.test.ts +6 -5
  41. package/src/platform/registry/__tests__/resource-link.test.ts +30 -0
  42. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +15 -15
  43. package/src/platform/registry/command-view.ts +10 -12
  44. package/src/platform/registry/index.ts +93 -93
  45. package/src/platform/registry/resource-link.ts +32 -0
  46. package/src/platform/registry/resource-registry.ts +917 -876
  47. package/src/platform/registry/serialization.ts +56 -73
  48. package/src/platform/registry/serialized-types.ts +17 -12
  49. package/src/platform/registry/types.ts +14 -43
  50. package/src/reference/_generated/contracts.md +94 -182
  51. package/src/reference/glossary.md +71 -105
  52. package/src/scaffold-registry/__tests__/index.test.ts +125 -1
  53. package/src/scaffold-registry/__tests__/schema.test.ts +48 -20
  54. package/src/scaffold-registry/index.ts +236 -188
  55. package/src/scaffold-registry/schema.ts +47 -22
  56. package/src/supabase/database.types.ts +2880 -2719
  57. package/src/test-utils/fixtures/memberships.ts +82 -80
  58. package/src/platform/registry/domains.ts +0 -165
@@ -1,97 +1,102 @@
1
- # Organization Model
2
-
3
- The organization model is the published semantic contract that maps a tenant's product shape to domain surfaces, features, and navigation.
4
-
5
- Use this module when you need to resolve or validate an organization's contract before wiring UI shells, routing, or domain-specific capability checks.
6
-
7
- ## Published Exports
8
-
9
- The public entry point exposes:
10
-
11
- - `OrganizationModelSchema`
12
- - `DEFAULT_ORGANIZATION_MODEL`
13
- - `defineOrganizationModel`
14
- - `resolveOrganizationModel`
15
- - `PROJECTS_FEATURE_ID`
16
- - `PROJECTS_INDEX_SURFACE_ID`
17
- - `PROJECTS_VIEW_CAPABILITY_ID`
18
- - `OrganizationModel` and the supporting domain types
19
-
20
- Import it from the published subpath:
21
-
22
- ```ts
23
- import {
24
- DEFAULT_ORGANIZATION_MODEL,
25
- PROJECTS_VIEW_CAPABILITY_ID,
26
- defineOrganizationModel,
27
- PROJECTS_FEATURE_ID,
28
- PROJECTS_INDEX_SURFACE_ID,
29
- resolveOrganizationModel,
30
- type OrganizationModel
31
- } from '@elevasis/core/organization-model'
32
- ```
33
-
34
- ## Contract Shape
35
-
36
- The model is versioned and currently validates against `version: 1`.
37
-
38
- Top-level fields:
39
-
40
- - `version` - schema version for the resolved contract.
41
- - `branding` - organization branding defaults and overrides.
42
- - `features` - unified feature entries that combine enablement, labels, and semantic references.
43
- - `navigation` - navigation model for the product shell.
44
- - `sales` - sales pipeline and relationship management.
45
- - `prospecting` - lists, companies, and contacts.
46
- - `projects` - projects, milestones, and tasks.
47
- - `identity`, `customers`, `offerings`, `roles`, `goals` - reality domains (2026-04 expansion).
48
- - `statuses` - unified status registry across delivery / hitl / execution / request / schedule.
49
- - `operations` - catalog of stateful runtime entities (HITL queue, sessions, executions, notifications, schedules).
50
- - `resourceMappings` - cross-surface resource mappings (includes techStack subsection).
51
-
52
- ## Default Feature Set
53
-
54
- The default model includes eight feature IDs:
55
-
56
- - `sales` - deal pipeline and relationship management.
57
- - `prospecting` - lists, companies, and contacts.
58
- - `projects` - projects, milestones, and tasks.
59
- - `operations` - organization graph and command-view surfaces.
60
- - `monitoring` - monitoring surfaces.
61
- - `settings` - organization settings.
62
- - `seo` - SEO surfaces (disabled by default).
63
- - `configure` - `/configure` skill entry point (external projects).
64
-
65
- ## Project Bridge Constants
66
-
67
- The organization-model surface exports a narrow set of canonical IDs for the shared Projects bridge:
68
-
69
- - `PROJECTS_FEATURE_ID` -> `projects`
70
- - `PROJECTS_INDEX_SURFACE_ID` -> `projects.index`
71
- - `PROJECTS_VIEW_CAPABILITY_ID` -> `delivery.projects.view`
72
-
73
- Use these when wiring shared UI manifests, template adapters, or other consumers that need to agree on the same Projects contract without repeating raw literals.
74
-
75
- ## Resolution Semantics
76
-
77
- - `defineOrganizationModel()` is a typed helper. It does not validate or merge anything by itself.
78
- - `resolveOrganizationModel()` deep-merges a partial override into the default model, then validates the result with `OrganizationModelSchema`.
79
- - Plain objects merge recursively.
80
- - Arrays replace the default value instead of merging element-by-element.
81
- - If `navigation.surfaces` is replaced without also supplying `navigation.groups`, inherited default groups are dropped when they no longer point at declared surfaces.
82
- - Missing fields fall back to `DEFAULT_ORGANIZATION_MODEL`.
83
-
84
- ## Referential Integrity
85
-
86
- - `navigation.defaultSurfaceId` must point at a declared navigation surface.
87
- - Every navigation group `surfaceId` must resolve to a declared surface.
88
- - Feature, surface, and resource-mapping IDs must resolve to declared counterparts; dangling references fail validation.
89
- - Feature-to-surface and feature/surface-to-resource links are validated in both directions so one-sided declarations fail during resolution.
90
- - Feature-bearing surfaces validate `featureId` against the canonical feature set.
91
-
92
- ## Practical Guidance
93
-
94
- - Use `resolveOrganizationModel()` when you need a runtime-safe model for rendering or policy checks.
95
- - Use `defineOrganizationModel()` when authoring a static partial model in source.
96
- - Treat feature IDs such as `sales`, `prospecting`, and `projects` as the canonical shell-level contract in new organization-model authoring.
97
- - Keep feature IDs, surface IDs, and capability IDs stable because downstream UI and policy code depend on them.
1
+ # Organization Model
2
+
3
+ The organization model is the published semantic contract that maps a tenant's product shape to flat feature hierarchy, shell navigation, business semantics, and graph bindings.
4
+
5
+ Use this module when resolving or validating an organization's contract before wiring UI shells, routing, feature gates, or domain-specific capability checks.
6
+
7
+ ## Published Exports
8
+
9
+ The public entry point exposes:
10
+
11
+ - `OrganizationModelSchema`
12
+ - `FeatureSchema`
13
+ - `DEFAULT_ORGANIZATION_MODEL`
14
+ - `defineOrganizationModel`
15
+ - `resolveOrganizationModel`
16
+ - `createFoundationOrganizationModel`
17
+ - node ID and feature helper types
18
+ - `OrganizationModel` and supporting domain types
19
+
20
+ Import it from the published subpath:
21
+
22
+ ```ts
23
+ import {
24
+ DEFAULT_ORGANIZATION_MODEL,
25
+ createFoundationOrganizationModel,
26
+ defineOrganizationModel,
27
+ resolveOrganizationModel,
28
+ type OrganizationModel
29
+ } from '@elevasis/core/organization-model'
30
+ ```
31
+
32
+ ## Contract Shape
33
+
34
+ The model is versioned and currently validates against `version: 1`.
35
+
36
+ Top-level fields:
37
+
38
+ - `version`
39
+ - `branding`
40
+ - `features`
41
+ - `navigation`
42
+ - `sales`
43
+ - `prospecting`
44
+ - `projects`
45
+ - `identity`
46
+ - `customers`
47
+ - `offerings`
48
+ - `roles`
49
+ - `goals`
50
+ - `statuses`
51
+ - `operations`
52
+
53
+ Resources bind to the graph from deployment metadata through `links` and `category`.
54
+
55
+ ## Feature Set
56
+
57
+ Feature hierarchy is authored as a flat array. Dotted IDs define parent/child relationships:
58
+
59
+ ```ts
60
+ features: [
61
+ { id: 'dashboard', label: 'Dashboard', enabled: true, path: '/', uiPosition: 'sidebar-primary' },
62
+ { id: 'sales', label: 'Sales', enabled: true, uiPosition: 'sidebar-primary' },
63
+ { id: 'sales.crm', label: 'CRM', enabled: true, path: '/crm' },
64
+ { id: 'operations.resources', label: 'Resources', enabled: true, path: '/operations/resources' }
65
+ ]
66
+ ```
67
+
68
+ Containers omit `path`; leaves provide `path`. `uiPosition`, `requiresAdmin`, and `devOnly` inherit from ancestors.
69
+ Development-only features remain in the contract with `enabled: true` and `devOnly: true`; shell consumers hide them and guard their paths outside development mode.
70
+
71
+ ## Graph IDs
72
+
73
+ Cross-collection links use kind-prefixed IDs:
74
+
75
+ - `feature:sales.crm`
76
+ - `integration:instantly`
77
+ - `resource:lead-import`
78
+ - `capability:operations.queue.review`
79
+
80
+ ## Resolution Semantics
81
+
82
+ - `defineOrganizationModel()` is a typed helper.
83
+ - `resolveOrganizationModel()` deep-merges a partial override into the default model, then validates it.
84
+ - `createFoundationOrganizationModel()` resolves the canonical model and returns UI-facing helper outputs.
85
+ - Plain objects merge recursively.
86
+ - Arrays replace the default value.
87
+ - Missing fields fall back to `DEFAULT_ORGANIZATION_MODEL`.
88
+
89
+ ## Referential Integrity
90
+
91
+ - Feature IDs must be unique.
92
+ - Child feature IDs require ancestor feature nodes.
93
+ - Container features omit `path`.
94
+ - Leaf features provide `path`.
95
+ - Resource links are validated against graph node IDs during registry registration.
96
+
97
+ ## Practical Guidance
98
+
99
+ - Use `resolveOrganizationModel()` when you need a runtime-safe model.
100
+ - Use `defineOrganizationModel()` when authoring static overrides.
101
+ - Keep feature IDs stable because shell routing, gating, breadcrumbs, and docs depend on them.
102
+ - Put semantic resource relationships on resource metadata, not on feature nodes.
@@ -69,12 +69,25 @@ describe('organization-model defaults', () => {
69
69
  expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
70
70
  })
71
71
 
72
- it('resolveOrganizationModel with no override equals resolveOrganizationModel with DEFAULT_ORGANIZATION_MODEL', () => {
73
- const fromUndefined = resolveOrganizationModel(undefined)
74
- const fromDefault = resolveOrganizationModel(DEFAULT_ORGANIZATION_MODEL)
75
- expect(fromDefault).toEqual(fromUndefined)
76
- })
77
- })
72
+ it('resolveOrganizationModel with no override equals resolveOrganizationModel with DEFAULT_ORGANIZATION_MODEL', () => {
73
+ const fromUndefined = resolveOrganizationModel(undefined)
74
+ const fromDefault = resolveOrganizationModel(DEFAULT_ORGANIZATION_MODEL)
75
+ expect(fromDefault).toEqual(fromUndefined)
76
+ })
77
+
78
+ it('keeps Command View enabled but development-only in the default Operations navigation', () => {
79
+ const result = resolveOrganizationModel(undefined)
80
+ const commandViewFeature = result.features.find((feature) => feature.id === 'operations.command-view')
81
+ const commandViewSurface = DEFAULT_ORGANIZATION_MODEL_NAVIGATION.surfaces.find(
82
+ (surface) => surface.id === 'operations.command-view'
83
+ )
84
+
85
+ expect(commandViewFeature?.enabled).toBe(true)
86
+ expect(commandViewFeature?.devOnly).toBe(true)
87
+ expect(commandViewSurface?.enabled).toBe(true)
88
+ expect(commandViewSurface?.devOnly).toBe(true)
89
+ })
90
+ })
78
91
 
79
92
  describe.each(domainCases)('$name (domain sub-constant)', ({ name: _name, constant, schema }) => {
80
93
  it('passes its domain schema parse without throwing', () => {
@@ -267,96 +267,27 @@ describe('ResourceMappingSchema — mixed techStack presence across entries', ()
267
267
  // Group 6: Integration via resolveOrganizationModel
268
268
  // ---------------------------------------------------------------------------
269
269
 
270
- describe('resolveOrganizationModel resourceMappings with techStack', () => {
271
- it('resolves a model with no resourceMappings (default empty array)', () => {
272
- const model = resolveOrganizationModel({})
273
- expect(model.resourceMappings).toEqual([])
274
- })
275
-
276
- it('resolves a model with a resourceMapping that has no techStack', () => {
277
- const model = resolveOrganizationModel({
278
- resourceMappings: [
279
- {
280
- id: 'rm-legacy',
281
- label: 'Legacy mapping',
282
- resourceId: 'legacy-workflow',
283
- resourceType: 'workflow',
284
- featureIds: [],
285
- entityIds: [],
286
- surfaceIds: [],
287
- capabilityIds: []
288
- }
289
- ]
290
- })
291
- expect(model.resourceMappings).toHaveLength(1)
292
- expect(model.resourceMappings[0].techStack).toBeUndefined()
293
- })
294
-
295
- it('resolves a model with a resourceMapping that has techStack', () => {
296
- const model = resolveOrganizationModel({
297
- resourceMappings: [
298
- {
299
- id: 'rm-crm-sync',
300
- label: 'CRM Sync',
301
- resourceId: 'crm-sync-workflow',
302
- resourceType: 'workflow',
303
- featureIds: [],
304
- entityIds: [],
305
- surfaceIds: [],
306
- capabilityIds: [],
307
- techStack: {
308
- platform: 'Salesforce',
309
- purpose: 'Enterprise CRM integration',
310
- credentialStatus: 'configured',
311
- isSystemOfRecord: true
312
- }
313
- }
314
- ]
315
- })
316
- expect(model.resourceMappings).toHaveLength(1)
317
- const mapping = model.resourceMappings[0]
318
- expect(mapping.techStack).toBeDefined()
319
- expect(mapping.techStack?.platform).toBe('Salesforce')
320
- expect(mapping.techStack?.isSystemOfRecord).toBe(true)
321
- })
322
-
323
- it('resolves multiple mappings with mixed techStack presence', () => {
324
- const model = resolveOrganizationModel({
325
- resourceMappings: [
326
- {
327
- id: 'rm-a',
328
- label: 'Mapping A',
329
- resourceId: 'workflow-a',
330
- resourceType: 'workflow',
331
- featureIds: [],
332
- entityIds: [],
333
- surfaceIds: [],
334
- capabilityIds: [],
335
- techStack: {
336
- platform: 'HubSpot',
337
- purpose: 'Contacts',
338
- credentialStatus: 'pending'
339
- }
340
- },
341
- {
342
- id: 'rm-b',
343
- label: 'Mapping B',
344
- resourceId: 'workflow-b',
345
- resourceType: 'agent',
346
- featureIds: [],
347
- entityIds: [],
348
- surfaceIds: [],
349
- capabilityIds: []
350
- }
351
- ]
352
- })
353
- expect(model.resourceMappings).toHaveLength(2)
354
- expect(model.resourceMappings[0].techStack?.platform).toBe('HubSpot')
355
- expect(model.resourceMappings[0].techStack?.isSystemOfRecord).toBe(false)
356
- expect(model.resourceMappings[1].techStack).toBeUndefined()
357
- })
358
-
359
- it('resolved model still validates without errors when resourceMappings omitted', () => {
360
- expect(() => resolveOrganizationModel({})).not.toThrow()
361
- })
362
- })
270
+ describe('resolveOrganizationModel resource mapping removal', () => {
271
+ it('resolved model validates without resourceMappings', () => {
272
+ expect(() => resolveOrganizationModel({})).not.toThrow()
273
+ })
274
+
275
+ it('drops resourceMappings overrides because graph links now live on resources', () => {
276
+ const model = resolveOrganizationModel({
277
+ resourceMappings: [
278
+ {
279
+ id: 'rm-legacy',
280
+ label: 'Legacy mapping',
281
+ resourceId: 'legacy-workflow',
282
+ resourceType: 'workflow',
283
+ featureIds: [],
284
+ entityIds: [],
285
+ surfaceIds: [],
286
+ capabilityIds: []
287
+ }
288
+ ]
289
+ } as Parameters<typeof resolveOrganizationModel>[0])
290
+
291
+ expect('resourceMappings' in model).toBe(false)
292
+ })
293
+ })