@elevasis/core 0.5.0 → 0.6.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 (59) hide show
  1. package/dist/index.d.ts +427 -42
  2. package/dist/index.js +589 -47
  3. package/dist/organization-model/index.d.ts +427 -42
  4. package/dist/organization-model/index.js +589 -47
  5. package/package.json +3 -3
  6. package/src/__tests__/template-foundations-compatibility.test.ts +2 -2
  7. package/src/business/acquisition/types.ts +2 -0
  8. package/src/commands/queue/types/task.ts +3 -3
  9. package/src/execution/engine/index.ts +8 -0
  10. package/src/execution/engine/tools/registry.ts +26 -24
  11. package/src/execution/engine/tools/tool-maps.ts +13 -9
  12. package/src/execution/engine/workflow/types.ts +2 -3
  13. package/src/organization-model/README.md +16 -12
  14. package/src/organization-model/__tests__/defaults.test.ts +175 -0
  15. package/src/organization-model/__tests__/domains/customers.test.ts +295 -0
  16. package/src/organization-model/__tests__/domains/goals.test.ts +479 -0
  17. package/src/organization-model/__tests__/domains/identity.test.ts +278 -0
  18. package/src/organization-model/__tests__/domains/navigation.test.ts +212 -0
  19. package/src/organization-model/__tests__/domains/offerings.test.ts +419 -0
  20. package/src/organization-model/__tests__/domains/operations.test.ts +203 -0
  21. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +362 -0
  22. package/src/organization-model/__tests__/domains/roles.test.ts +347 -0
  23. package/src/organization-model/__tests__/domains/statuses.test.ts +243 -0
  24. package/src/organization-model/__tests__/foundation.test.ts +3 -3
  25. package/src/organization-model/__tests__/resolve.test.ts +447 -3
  26. package/src/organization-model/__tests__/schema.test.ts +407 -0
  27. package/src/organization-model/contracts.ts +5 -5
  28. package/src/organization-model/defaults.ts +39 -16
  29. package/src/organization-model/domains/customers.ts +75 -0
  30. package/src/organization-model/domains/goals.ts +80 -0
  31. package/src/organization-model/domains/identity.ts +87 -0
  32. package/src/organization-model/domains/navigation.ts +43 -4
  33. package/src/organization-model/domains/offerings.ts +66 -0
  34. package/src/organization-model/domains/operations.ts +85 -0
  35. package/src/organization-model/domains/{delivery.ts → projects.ts} +6 -6
  36. package/src/organization-model/domains/{lead-gen.ts → prospecting.ts} +5 -5
  37. package/src/organization-model/domains/roles.ts +55 -0
  38. package/src/organization-model/domains/sales.ts +94 -0
  39. package/src/organization-model/domains/shared.ts +30 -1
  40. package/src/organization-model/domains/statuses.ts +130 -0
  41. package/src/organization-model/index.ts +3 -3
  42. package/src/organization-model/organization-graph.mdx +1 -0
  43. package/src/organization-model/organization-model.mdx +84 -19
  44. package/src/organization-model/published.ts +53 -8
  45. package/src/organization-model/schema.ts +67 -7
  46. package/src/organization-model/types.ts +31 -7
  47. package/src/platform/constants/versions.ts +1 -1
  48. package/src/platform/registry/types.ts +1 -1
  49. package/src/projects/api-schemas.ts +1 -0
  50. package/src/reference/_generated/contracts.md +116 -8
  51. package/src/reference/glossary.md +25 -4
  52. package/src/requests/__tests__/api-schemas.test.ts +277 -0
  53. package/src/requests/api-schemas.ts +83 -0
  54. package/src/requests/index.ts +1 -0
  55. package/src/supabase/database.types.ts +88 -0
  56. package/src/organization-model/domains/crm.ts +0 -46
  57. /package/src/business/{delivery → projects}/index.ts +0 -0
  58. /package/src/business/{delivery → projects}/types.ts +0 -0
  59. /package/src/business/{crm → sales}/api-schemas.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "license": "MIT",
5
5
  "description": "Minimal shared constants across Elevasis monorepo",
6
6
  "sideEffects": false,
@@ -33,8 +33,8 @@
33
33
  "rollup-plugin-dts": "^6.3.0",
34
34
  "tsup": "^8.0.0",
35
35
  "typescript": "5.9.2",
36
- "@repo/eslint-config": "0.0.0",
37
- "@repo/typescript-config": "0.0.0"
36
+ "@repo/typescript-config": "0.0.0",
37
+ "@repo/eslint-config": "0.0.0"
38
38
  },
39
39
  "dependencies": {
40
40
  "@anthropic-ai/sdk": "^0.62.0",
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { DELIVERY_PROJECTS_VIEW_CAPABILITY_ID, PROJECTS_FEATURE_ID } from '../organization-model/published'
2
+ import { PROJECTS_VIEW_CAPABILITY_ID, PROJECTS_FEATURE_ID } from '../organization-model/published'
3
3
  import {
4
4
  getOrganizationSurface,
5
5
  homeLabel,
@@ -50,7 +50,7 @@ describe('template foundations compatibility', () => {
50
50
  expectedIcon: 'projects',
51
51
  expectedPath: '/projects',
52
52
  expectedEntityIds: ['delivery.project'],
53
- expectedCapabilityIds: [DELIVERY_PROJECTS_VIEW_CAPABILITY_ID]
53
+ expectedCapabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
54
54
  },
55
55
  {
56
56
  id: 'lead-gen',
@@ -268,6 +268,8 @@ export interface DealContact {
268
268
  export interface DealFilters {
269
269
  stage?: DealStage
270
270
  search?: string
271
+ limit?: number
272
+ offset?: number
271
273
  }
272
274
 
273
275
  /** Deal list item with joined contact and company data */
@@ -25,7 +25,7 @@ export interface Task extends OriginTracking {
25
25
  humanCheckpoint?: string
26
26
 
27
27
  // Status (updated to include 'completed')
28
- status: TaskStatus
28
+ status: QueueTaskStatus
29
29
 
30
30
  /**
31
31
  * Target resource tracking — mirrors origin columns.
@@ -59,7 +59,7 @@ export interface Task extends OriginTracking {
59
59
  * - failed: execution failed, task can be retried
60
60
  * - expired: timed out before action
61
61
  */
62
- export type TaskStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'expired'
62
+ export type QueueTaskStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'expired'
63
63
 
64
64
  /**
65
65
  * Parameters for creating a new HITL task
@@ -106,7 +106,7 @@ export interface PatchTaskParams {
106
106
  */
107
107
  export interface ListTasksFilters {
108
108
  organizationId: string
109
- status?: TaskStatus
109
+ status?: QueueTaskStatus
110
110
  humanCheckpoint?: string
111
111
  timeRange?: TimeRange
112
112
  priorityMin?: number
@@ -278,12 +278,20 @@ export {
278
278
  type AddContactsToListResult,
279
279
  type BulkImportParams,
280
280
  type BulkImportResult,
281
+ type BulkImportCompanyEntry,
282
+ type BulkImportCompaniesParams,
283
+ type BulkImportCompaniesResult,
281
284
  type DeactivateContactsByCompanyParams,
282
285
  type DeactivateContactsByCompanyResult,
283
286
  // Deal types (acq_deals table)
284
287
  type UpsertDealParams,
285
288
  type AcqDeal,
286
289
  type DealActivityEntry,
290
+ // Deal analytics types
291
+ type DealStageSummary,
292
+ type StaleDeal,
293
+ type DealPipelineAnalytics,
294
+ type DealAnalyticsParams,
287
295
  // Deal-sync param types
288
296
  type UpdateDiscoveryDataParams,
289
297
  type UpdateProposalDataParams,
@@ -21,14 +21,9 @@ import type {
21
21
  MilestoneRow,
22
22
  TaskRow,
23
23
  NoteRow
24
- } from '../../../business/delivery'
25
- import type {
26
- DealListItem,
27
- DealDetail,
28
- DealStage,
29
- ListDealsQuery
30
- } from '../../../business/acquisition'
31
- import type { RecentActivityEntry } from '../../../business/crm/api-schemas'
24
+ } from '../../../business/projects'
25
+ import type { DealListItem, DealDetail, DealStage, ListDealsQuery } from '../../../business/acquisition'
26
+ import type { RecentActivityEntry } from '../../../business/sales/api-schemas'
32
27
  import type { Database } from '../../../supabase/database.types'
33
28
 
34
29
  /**
@@ -148,12 +143,24 @@ export interface ICrmService {
148
143
  getDeal(dealId: string, organizationId: string): Promise<DealDetail | null>
149
144
  getDealByEmail(email: string, organizationId: string): Promise<DealDetail | null>
150
145
  updateDealStage(dealId: string, organizationId: string, stage: DealStage): Promise<void>
151
- createDealNote(params: import('./lead-service-types').CreateDealNoteParams): Promise<import('./lead-service-types').AcqDealNote>
152
- listDealNotes(params: import('./lead-service-types').ListDealNotesParams): Promise<import('./lead-service-types').AcqDealNote[]>
153
- createDealTask(params: import('./lead-service-types').CreateDealTaskParams): Promise<import('./lead-service-types').AcqDealTask>
154
- listDealTasks(params: import('./lead-service-types').ListDealTasksParams): Promise<import('./lead-service-types').AcqDealTask[]>
155
- listDealTasksDue(params: import('./lead-service-types').ListDealTasksDueParams): Promise<import('./lead-service-types').AcqDealTask[]>
156
- completeDealTask(params: import('./lead-service-types').CompleteDealTaskParams): Promise<import('./lead-service-types').AcqDealTask>
146
+ createDealNote(
147
+ params: import('./lead-service-types').CreateDealNoteParams
148
+ ): Promise<import('./lead-service-types').AcqDealNote>
149
+ listDealNotes(
150
+ params: import('./lead-service-types').ListDealNotesParams
151
+ ): Promise<import('./lead-service-types').AcqDealNote[]>
152
+ createDealTask(
153
+ params: import('./lead-service-types').CreateDealTaskParams
154
+ ): Promise<import('./lead-service-types').AcqDealTask>
155
+ listDealTasks(
156
+ params: import('./lead-service-types').ListDealTasksParams
157
+ ): Promise<import('./lead-service-types').AcqDealTask[]>
158
+ listDealTasksDue(
159
+ params: import('./lead-service-types').ListDealTasksDueParams
160
+ ): Promise<import('./lead-service-types').AcqDealTask[]>
161
+ completeDealTask(
162
+ params: import('./lead-service-types').CompleteDealTaskParams
163
+ ): Promise<import('./lead-service-types').AcqDealTask>
157
164
  recordActivity(params: import('./lead-service-types').RecordDealActivityParams): Promise<void>
158
165
  deleteDeal(params: import('./lead-service-types').DeleteDealParams): Promise<void>
159
166
  }
@@ -208,11 +215,7 @@ export interface IProjectsService {
208
215
  ): Promise<TaskRow[]>
209
216
  getTask(id: string, organizationId: string): Promise<TaskRow | null>
210
217
  createTask(input: Omit<TaskInsert, 'organization_id'> & { organizationId: string }): Promise<TaskRow>
211
- updateTask(
212
- id: string,
213
- organizationId: string,
214
- input: Omit<TaskUpdate, 'organization_id'>
215
- ): Promise<TaskRow | null>
218
+ updateTask(id: string, organizationId: string, input: Omit<TaskUpdate, 'organization_id'>): Promise<TaskRow | null>
216
219
  deleteTask(id: string, organizationId: string): Promise<boolean>
217
220
  mergeTaskResumeContext(
218
221
  id: string,
@@ -221,11 +224,7 @@ export interface IProjectsService {
221
224
  ): Promise<TaskResumeContextRow | null>
222
225
  listNotes(projectId: string, organizationId: string): Promise<NoteRow[]>
223
226
  createNote(input: Omit<NoteInsert, 'organization_id'> & { organizationId: string }): Promise<NoteRow>
224
- updateNote(
225
- id: string,
226
- organizationId: string,
227
- input: Omit<NoteUpdate, 'organization_id'>
228
- ): Promise<NoteRow | null>
227
+ updateNote(id: string, organizationId: string, input: Omit<NoteUpdate, 'organization_id'>): Promise<NoteRow | null>
229
228
  deleteNote(id: string, organizationId: string): Promise<boolean>
230
229
  }
231
230
 
@@ -548,6 +547,9 @@ export {
548
547
  type AddContactsToListResult,
549
548
  type BulkImportParams,
550
549
  type BulkImportResult,
550
+ type BulkImportCompanyEntry,
551
+ type BulkImportCompaniesParams,
552
+ type BulkImportCompaniesResult,
551
553
  type DeactivateContactsByCompanyParams,
552
554
  type DeactivateContactsByCompanyResult,
553
555
  type ILeadService,
@@ -261,8 +261,8 @@ import type {
261
261
  } from './lead-service-types'
262
262
 
263
263
  import type { DealListItem, DealDetail } from '../../../business/acquisition'
264
- import { CrmSchemas } from '../../../business/crm/api-schemas'
265
- import type { RecentActivityEntry } from '../../../business/crm/api-schemas'
264
+ import { CrmSchemas } from '../../../business/sales/api-schemas'
265
+ import type { RecentActivityEntry } from '../../../business/sales/api-schemas'
266
266
  import { DealSchemas } from '../../../business/acquisition'
267
267
  import { ProjectSchemas } from '../../../projects/api-schemas'
268
268
  import type {
@@ -272,7 +272,7 @@ import type {
272
272
  NoteRow,
273
273
  ProjectWithCounts,
274
274
  ProjectDetail
275
- } from '../../../business/delivery'
275
+ } from '../../../business/projects'
276
276
  import type { z } from 'zod'
277
277
 
278
278
  // ---------------------------------------------------------------------------
@@ -357,14 +357,14 @@ export type NotificationToolMap = {
357
357
  type ProjectsListParams = z.infer<typeof ProjectSchemas.GetProjectsQuery>
358
358
  type ProjectCreateParams = z.infer<typeof ProjectSchemas.CreateProjectRequest>
359
359
  type ProjectUpdateParams = z.infer<typeof ProjectSchemas.UpdateProjectRequest>
360
- type MilestoneCreateParams =
361
- z.infer<typeof ProjectSchemas.ProjectIdPathParams> & z.infer<typeof ProjectSchemas.CreateMilestoneRequest>
360
+ type MilestoneCreateParams = z.infer<typeof ProjectSchemas.ProjectIdPathParams> &
361
+ z.infer<typeof ProjectSchemas.CreateMilestoneRequest>
362
362
  type MilestoneUpdateParams = z.infer<typeof ProjectSchemas.UpdateMilestoneRequest>
363
363
  type TaskListParams = z.infer<typeof ProjectSchemas.ProjectIdPathParams> & z.infer<typeof ProjectSchemas.GetTasksQuery>
364
364
  type TaskCreateParams = z.infer<typeof ProjectSchemas.CreateTaskRequest>
365
365
  type TaskUpdateParams = z.infer<typeof ProjectSchemas.UpdateTaskRequest>
366
- type TaskResumeContextParams =
367
- z.infer<typeof ProjectSchemas.TaskIdParams> & z.infer<typeof ProjectSchemas.MergeResumeContextRequest>
366
+ type TaskResumeContextParams = z.infer<typeof ProjectSchemas.TaskIdParams> &
367
+ z.infer<typeof ProjectSchemas.MergeResumeContextRequest>
368
368
  type NoteListParams = z.infer<typeof ProjectSchemas.ProjectIdPathParams>
369
369
  type NoteCreateParams = z.infer<typeof ProjectSchemas.CreateNoteRequest>
370
370
  type NoteUpdateParams = z.infer<typeof ProjectSchemas.UpdateNoteRequest>
@@ -378,7 +378,10 @@ export type ProjectsToolMap = {
378
378
  deleteProject: { params: z.infer<typeof ProjectSchemas.ProjectIdParams>; result: void }
379
379
  listMilestones: { params: z.infer<typeof ProjectSchemas.ProjectIdPathParams>; result: MilestoneRow[] }
380
380
  createMilestone: { params: MilestoneCreateParams; result: MilestoneRow }
381
- updateMilestone: { params: z.infer<typeof ProjectSchemas.MilestoneIdParams> & MilestoneUpdateParams; result: MilestoneRow }
381
+ updateMilestone: {
382
+ params: z.infer<typeof ProjectSchemas.MilestoneIdParams> & MilestoneUpdateParams
383
+ result: MilestoneRow
384
+ }
382
385
  deleteMilestone: { params: z.infer<typeof ProjectSchemas.MilestoneIdParams>; result: void }
383
386
  listTasks: { params: TaskListParams; result: TaskRow[] }
384
387
  getTask: { params: z.infer<typeof ProjectSchemas.TaskIdParams>; result: TaskRow }
@@ -399,7 +402,8 @@ export type ProjectsToolMap = {
399
402
  type CrmRecentActivityParams = Partial<z.infer<typeof CrmSchemas.GetRecentActivityQuery>>
400
403
  type CrmListDealsParams = Partial<z.infer<typeof DealSchemas.ListDealsQuery>>
401
404
  type CrmGetDealParams = z.infer<typeof DealSchemas.DealIdParams>
402
- type CrmUpdateDealStageParams = z.infer<typeof DealSchemas.DealIdParams> & z.infer<typeof DealSchemas.SyncDealStageRequest>
405
+ type CrmUpdateDealStageParams = z.infer<typeof DealSchemas.DealIdParams> &
406
+ z.infer<typeof DealSchemas.SyncDealStageRequest>
403
407
  type CrmGetDealByEmailParams = { email: string }
404
408
  type CrmTaskDueParams = Partial<z.infer<typeof DealSchemas.ListDealTasksDueQuery>>
405
409
  type CrmDealTaskParams = Omit<CreateDealTaskParams, 'organizationId'>
@@ -28,10 +28,9 @@ export type StepHandler = (input: unknown, context: ExecutionContext) => Promise
28
28
  // Step type for flow control
29
29
  export const StepType = {
30
30
  LINEAR: 'linear',
31
- CONDITIONAL: 'conditional',
31
+ CONDITIONAL: 'conditional'
32
32
  } as const
33
- // eslint-disable-next-line no-redeclare -- intentional const+type pattern (enum-like)
34
- export type StepType = typeof StepType[keyof typeof StepType]
33
+ export type StepType = (typeof StepType)[keyof typeof StepType]
35
34
 
36
35
  // Next step configuration types
37
36
  export interface LinearNext {
@@ -14,7 +14,7 @@ The public entry point exposes:
14
14
  - `resolveOrganizationModel`
15
15
  - `PROJECTS_FEATURE_ID`
16
16
  - `PROJECTS_INDEX_SURFACE_ID`
17
- - `DELIVERY_PROJECTS_VIEW_CAPABILITY_ID`
17
+ - `PROJECTS_VIEW_CAPABILITY_ID`
18
18
  - `OrganizationModel` and the supporting domain types
19
19
 
20
20
  Import it from the published subpath:
@@ -22,7 +22,7 @@ Import it from the published subpath:
22
22
  ```ts
23
23
  import {
24
24
  DEFAULT_ORGANIZATION_MODEL,
25
- DELIVERY_PROJECTS_VIEW_CAPABILITY_ID,
25
+ PROJECTS_VIEW_CAPABILITY_ID,
26
26
  defineOrganizationModel,
27
27
  PROJECTS_FEATURE_ID,
28
28
  PROJECTS_INDEX_SURFACE_ID,
@@ -41,30 +41,34 @@ Top-level fields:
41
41
  - `branding` - organization branding defaults and overrides.
42
42
  - `features` - unified feature entries that combine enablement, labels, and semantic references.
43
43
  - `navigation` - navigation model for the product shell.
44
- - `crm` - CRM-specific contract data.
45
- - `leadGen` - lead generation contract data.
46
- - `delivery` - delivery and project contract data.
47
- - `resourceMappings` - cross-surface resource mappings.
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).
48
51
 
49
52
  ## Default Feature Set
50
53
 
51
- The default model includes seven feature IDs:
54
+ The default model includes eight feature IDs:
52
55
 
53
- - `crm` - deal pipeline and relationship management.
54
- - `lead-gen` - lists, companies, and contacts.
56
+ - `sales` - deal pipeline and relationship management.
57
+ - `prospecting` - lists, companies, and contacts.
55
58
  - `projects` - projects, milestones, and tasks.
56
59
  - `operations` - organization graph and command-view surfaces.
57
60
  - `monitoring` - monitoring surfaces.
58
61
  - `settings` - organization settings.
59
62
  - `seo` - SEO surfaces (disabled by default).
63
+ - `configure` - `/configure` skill entry point (external projects).
60
64
 
61
65
  ## Project Bridge Constants
62
66
 
63
- The organization-model surface now exports a narrow set of canonical IDs for the shared Projects bridge:
67
+ The organization-model surface exports a narrow set of canonical IDs for the shared Projects bridge:
64
68
 
65
69
  - `PROJECTS_FEATURE_ID` -> `projects`
66
70
  - `PROJECTS_INDEX_SURFACE_ID` -> `projects.index`
67
- - `DELIVERY_PROJECTS_VIEW_CAPABILITY_ID` -> `delivery.projects.view`
71
+ - `PROJECTS_VIEW_CAPABILITY_ID` -> `delivery.projects.view`
68
72
 
69
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.
70
74
 
@@ -89,5 +93,5 @@ Use these when wiring shared UI manifests, template adapters, or other consumers
89
93
 
90
94
  - Use `resolveOrganizationModel()` when you need a runtime-safe model for rendering or policy checks.
91
95
  - Use `defineOrganizationModel()` when authoring a static partial model in source.
92
- - Treat feature IDs such as `crm`, `lead-gen`, and `projects` as the canonical shell-level contract in new organization-model authoring.
96
+ - Treat feature IDs such as `sales`, `prospecting`, and `projects` as the canonical shell-level contract in new organization-model authoring.
93
97
  - Keep feature IDs, surface IDs, and capability IDs stable because downstream UI and policy code depend on them.
@@ -0,0 +1,175 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { DEFAULT_ORGANIZATION_MODEL } from '../defaults'
3
+ import { DEFAULT_ORGANIZATION_MODEL_BRANDING } from '../domains/branding'
4
+ import { OrganizationModelBrandingSchema } from '../domains/branding'
5
+ import { DEFAULT_ORGANIZATION_MODEL_SALES } from '../domains/sales'
6
+ import { OrganizationModelSalesSchema } from '../domains/sales'
7
+ import { DEFAULT_ORGANIZATION_MODEL_PROJECTS } from '../domains/projects'
8
+ import { OrganizationModelProjectsSchema } from '../domains/projects'
9
+ import { DEFAULT_ORGANIZATION_MODEL_PROSPECTING } from '../domains/prospecting'
10
+ import { OrganizationModelProspectingSchema } from '../domains/prospecting'
11
+ import { DEFAULT_ORGANIZATION_MODEL_NAVIGATION } from '../domains/navigation'
12
+ import { OrganizationModelNavigationSchema } from '../domains/navigation'
13
+ import { DEFAULT_ORGANIZATION_MODEL_OPERATIONS } from '../domains/operations'
14
+ import { OperationsDomainSchema } from '../domains/operations'
15
+ import { DEFAULT_ORGANIZATION_MODEL_STATUSES } from '../domains/statuses'
16
+ import { StatusesDomainSchema } from '../domains/statuses'
17
+ import { resolveOrganizationModel } from '../resolve'
18
+ import { OrganizationModelSchema } from '../schema'
19
+
20
+ // All DEFAULT_ORGANIZATION_MODEL* constants and the schemas used to validate them.
21
+ // The composite constant lives in defaults.ts; domain sub-constants live in their
22
+ // respective domain files. All are covered here for roundtrip integrity.
23
+ const domainCases = [
24
+ {
25
+ name: 'DEFAULT_ORGANIZATION_MODEL_BRANDING',
26
+ constant: DEFAULT_ORGANIZATION_MODEL_BRANDING,
27
+ schema: OrganizationModelBrandingSchema
28
+ },
29
+ {
30
+ name: 'DEFAULT_ORGANIZATION_MODEL_SALES',
31
+ constant: DEFAULT_ORGANIZATION_MODEL_SALES,
32
+ schema: OrganizationModelSalesSchema
33
+ },
34
+ {
35
+ name: 'DEFAULT_ORGANIZATION_MODEL_PROJECTS',
36
+ constant: DEFAULT_ORGANIZATION_MODEL_PROJECTS,
37
+ schema: OrganizationModelProjectsSchema
38
+ },
39
+ {
40
+ name: 'DEFAULT_ORGANIZATION_MODEL_PROSPECTING',
41
+ constant: DEFAULT_ORGANIZATION_MODEL_PROSPECTING,
42
+ schema: OrganizationModelProspectingSchema
43
+ },
44
+ {
45
+ name: 'DEFAULT_ORGANIZATION_MODEL_NAVIGATION',
46
+ constant: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
47
+ schema: OrganizationModelNavigationSchema
48
+ },
49
+ {
50
+ name: 'DEFAULT_ORGANIZATION_MODEL_STATUSES',
51
+ constant: DEFAULT_ORGANIZATION_MODEL_STATUSES,
52
+ schema: StatusesDomainSchema
53
+ },
54
+ {
55
+ name: 'DEFAULT_ORGANIZATION_MODEL_OPERATIONS',
56
+ constant: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
57
+ schema: OperationsDomainSchema
58
+ }
59
+ ] as const
60
+
61
+ describe('organization-model defaults', () => {
62
+ describe('DEFAULT_ORGANIZATION_MODEL (composite)', () => {
63
+ it('passes OrganizationModelSchema.parse without throwing', () => {
64
+ expect(() => OrganizationModelSchema.parse(DEFAULT_ORGANIZATION_MODEL)).not.toThrow()
65
+ })
66
+
67
+ it('resolveOrganizationModel(DEFAULT_ORGANIZATION_MODEL) returns a schema-valid model', () => {
68
+ const result = resolveOrganizationModel(DEFAULT_ORGANIZATION_MODEL)
69
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
70
+ })
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
+ })
78
+
79
+ describe.each(domainCases)('$name (domain sub-constant)', ({ name: _name, constant, schema }) => {
80
+ it('passes its domain schema parse without throwing', () => {
81
+ expect(() => schema.parse(constant)).not.toThrow()
82
+ })
83
+ })
84
+
85
+ describe('DEFAULT_ORGANIZATION_MODEL_BRANDING via resolveOrganizationModel', () => {
86
+ it('resolving with branding override produces a schema-valid model', () => {
87
+ const result = resolveOrganizationModel({ branding: DEFAULT_ORGANIZATION_MODEL_BRANDING })
88
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
89
+ })
90
+ })
91
+
92
+ describe('DEFAULT_ORGANIZATION_MODEL_SALES via resolveOrganizationModel', () => {
93
+ it('resolving with sales override produces a schema-valid model', () => {
94
+ const result = resolveOrganizationModel({ sales: DEFAULT_ORGANIZATION_MODEL_SALES })
95
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
96
+ })
97
+ })
98
+
99
+ describe('DEFAULT_ORGANIZATION_MODEL_PROJECTS via resolveOrganizationModel', () => {
100
+ it('resolving with projects override produces a schema-valid model', () => {
101
+ const result = resolveOrganizationModel({ projects: DEFAULT_ORGANIZATION_MODEL_PROJECTS })
102
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
103
+ })
104
+ })
105
+
106
+ describe('DEFAULT_ORGANIZATION_MODEL_PROSPECTING via resolveOrganizationModel', () => {
107
+ it('resolving with prospecting override produces a schema-valid model', () => {
108
+ const result = resolveOrganizationModel({ prospecting: DEFAULT_ORGANIZATION_MODEL_PROSPECTING })
109
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
110
+ })
111
+ })
112
+
113
+ describe('DEFAULT_ORGANIZATION_MODEL_NAVIGATION via resolveOrganizationModel', () => {
114
+ it('resolving with navigation override produces a schema-valid model', () => {
115
+ const result = resolveOrganizationModel({ navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION })
116
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
117
+ })
118
+ })
119
+
120
+ describe('DEFAULT_ORGANIZATION_MODEL_OPERATIONS via resolveOrganizationModel', () => {
121
+ it('resolving with operations override produces a schema-valid model', () => {
122
+ const result = resolveOrganizationModel({ operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS })
123
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
124
+ })
125
+
126
+ it('default operations seed covers all 5 entity categories', () => {
127
+ expect(DEFAULT_ORGANIZATION_MODEL_OPERATIONS.entries).toHaveLength(5)
128
+ })
129
+
130
+ it('every entry has a non-empty id, label, and semanticClass', () => {
131
+ for (const entry of DEFAULT_ORGANIZATION_MODEL_OPERATIONS.entries) {
132
+ expect(entry.id.length).toBeGreaterThan(0)
133
+ expect(entry.label.length).toBeGreaterThan(0)
134
+ expect(entry.semanticClass.length).toBeGreaterThan(0)
135
+ }
136
+ })
137
+
138
+ it('all entry ids are unique', () => {
139
+ const ids = DEFAULT_ORGANIZATION_MODEL_OPERATIONS.entries.map((e) => e.id)
140
+ const uniqueIds = new Set(ids)
141
+ expect(uniqueIds.size).toBe(ids.length)
142
+ })
143
+ })
144
+
145
+ describe('DEFAULT_ORGANIZATION_MODEL_STATUSES via resolveOrganizationModel', () => {
146
+ it('resolving with statuses override produces a schema-valid model', () => {
147
+ const result = resolveOrganizationModel({ statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES })
148
+ expect(() => OrganizationModelSchema.parse(result)).not.toThrow()
149
+ })
150
+
151
+ it('default statuses seed covers all 9 delivery.task values', () => {
152
+ const taskEntries = DEFAULT_ORGANIZATION_MODEL_STATUSES.entries.filter((e) => e.semanticClass === 'delivery.task')
153
+ expect(taskEntries).toHaveLength(9)
154
+ })
155
+
156
+ it('default statuses seed covers all 5 queue values', () => {
157
+ const queueEntries = DEFAULT_ORGANIZATION_MODEL_STATUSES.entries.filter((e) => e.semanticClass === 'queue')
158
+ expect(queueEntries).toHaveLength(5)
159
+ })
160
+
161
+ it('every entry has a non-empty id, label, and semanticClass', () => {
162
+ for (const entry of DEFAULT_ORGANIZATION_MODEL_STATUSES.entries) {
163
+ expect(entry.id.length).toBeGreaterThan(0)
164
+ expect(entry.label.length).toBeGreaterThan(0)
165
+ expect(entry.semanticClass.length).toBeGreaterThan(0)
166
+ }
167
+ })
168
+
169
+ it('all entry ids are unique', () => {
170
+ const ids = DEFAULT_ORGANIZATION_MODEL_STATUSES.entries.map((e) => e.id)
171
+ const uniqueIds = new Set(ids)
172
+ expect(uniqueIds.size).toBe(ids.length)
173
+ })
174
+ })
175
+ })