@elevasis/core 0.23.0 → 0.24.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/index.d.ts +1326 -552
- package/dist/index.js +869 -154
- package/dist/knowledge/index.d.ts +487 -209
- package/dist/knowledge/index.js +104 -1
- package/dist/organization-model/index.d.ts +1326 -552
- package/dist/organization-model/index.js +869 -154
- package/dist/test-utils/index.d.ts +357 -72
- package/dist/test-utils/index.js +795 -142
- package/package.json +5 -5
- package/src/README.md +14 -14
- package/src/__tests__/publish.test.ts +24 -24
- package/src/__tests__/template-core-compatibility.test.ts +9 -12
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2102 -2096
- package/src/_gen/__tests__/scaffold-contracts.test.ts +30 -30
- package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -217
- package/src/auth/multi-tenancy/credentials/server/encryption.ts +69 -69
- package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +37 -37
- package/src/auth/multi-tenancy/index.ts +26 -26
- package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -104
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +143 -143
- package/src/auth/multi-tenancy/memberships/index.ts +26 -26
- package/src/auth/multi-tenancy/memberships/membership.ts +130 -130
- package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -194
- package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -136
- package/src/auth/multi-tenancy/permissions.test.ts +42 -42
- package/src/auth/multi-tenancy/permissions.ts +123 -123
- package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -78
- package/src/auth/multi-tenancy/role-management/index.ts +16 -16
- package/src/auth/multi-tenancy/theme-presets.ts +45 -45
- package/src/auth/multi-tenancy/types.ts +57 -57
- package/src/auth/multi-tenancy/users/api-schemas.ts +165 -165
- package/src/business/README.md +2 -2
- package/src/business/acquisition/activity-events.test.ts +250 -250
- package/src/business/acquisition/activity-events.ts +93 -93
- package/src/business/acquisition/api-schemas.test.ts +1883 -1843
- package/src/business/acquisition/api-schemas.ts +1492 -1497
- package/src/business/acquisition/build-templates.test.ts +240 -240
- package/src/business/acquisition/build-templates.ts +98 -98
- package/src/business/acquisition/crm-next-action.test.ts +262 -262
- package/src/business/acquisition/crm-next-action.ts +220 -220
- package/src/business/acquisition/crm-priority.test.ts +216 -216
- package/src/business/acquisition/crm-priority.ts +349 -349
- package/src/business/acquisition/crm-state-actions.test.ts +153 -153
- package/src/business/acquisition/deal-ownership.test.ts +351 -351
- package/src/business/acquisition/deal-ownership.ts +120 -120
- package/src/business/acquisition/derive-actions.test.ts +129 -104
- package/src/business/acquisition/derive-actions.ts +74 -84
- package/src/business/acquisition/index.ts +171 -170
- package/src/business/acquisition/ontology-validation.ts +309 -0
- package/src/business/acquisition/stateful.ts +30 -30
- package/src/business/acquisition/types.ts +396 -396
- package/src/business/clients/api-schemas.test.ts +115 -115
- package/src/business/clients/api-schemas.ts +158 -158
- package/src/business/clients/index.ts +1 -1
- package/src/business/crm/api-schemas.ts +40 -40
- package/src/business/crm/index.ts +1 -1
- package/src/business/deals/api-schemas.ts +87 -87
- package/src/business/deals/index.ts +1 -1
- package/src/business/index.ts +5 -5
- package/src/business/projects/types.ts +144 -144
- package/src/commands/queue/types/task.ts +15 -15
- package/src/execution/core/runner-types.ts +61 -61
- package/src/execution/core/sse-executions.ts +7 -7
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -10
- package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -16
- package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -4
- package/src/execution/engine/agent/core/types.ts +25 -25
- package/src/execution/engine/agent/index.ts +6 -6
- package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -24
- package/src/execution/engine/index.ts +443 -443
- package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +298 -298
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -55
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -107
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -48
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -99
- package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -1
- package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -363
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -162
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -316
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -18
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -194
- package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -7
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -204
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +105 -105
- package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -428
- package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -2
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1474 -1474
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +103 -103
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -88
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -141
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -76
- package/src/execution/engine/tools/integration/server/adapters/signature-api/signature-api-tools.ts +182 -182
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +310 -310
- package/src/execution/engine/tools/integration/service.test.ts +239 -239
- package/src/execution/engine/tools/integration/service.ts +172 -172
- package/src/execution/engine/tools/integration/tool.ts +255 -255
- package/src/execution/engine/tools/lead-service-types.ts +1005 -1005
- package/src/execution/engine/tools/messages.ts +43 -43
- package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -7
- package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -6
- package/src/execution/engine/tools/platform/acquisition/list-tools.ts +6 -6
- package/src/execution/engine/tools/platform/acquisition/types.ts +280 -280
- package/src/execution/engine/tools/platform/email/types.ts +97 -97
- package/src/execution/engine/tools/registry.ts +704 -704
- package/src/execution/engine/tools/tool-maps.ts +831 -831
- package/src/execution/engine/tools/types.ts +234 -234
- package/src/execution/engine/workflow/types.ts +202 -202
- package/src/execution/external/__tests__/api-schemas.test.ts +127 -127
- package/src/execution/external/api-schemas.ts +40 -40
- package/src/execution/external/index.ts +1 -1
- package/src/index.ts +18 -18
- package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -420
- package/src/integrations/credentials/api-schemas.ts +146 -146
- package/src/integrations/credentials/schemas.ts +200 -200
- package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -7
- package/src/integrations/oauth/provider-registry.ts +74 -74
- package/src/integrations/oauth/server/credentials.ts +43 -43
- package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -327
- package/src/integrations/webhook-endpoints/api-schemas.ts +103 -103
- package/src/integrations/webhook-endpoints/types.ts +58 -58
- package/src/knowledge/README.md +32 -32
- package/src/knowledge/__tests__/queries.test.ts +626 -535
- package/src/knowledge/format.ts +99 -99
- package/src/knowledge/index.ts +5 -5
- package/src/knowledge/published.ts +5 -5
- package/src/knowledge/queries.ts +269 -218
- package/src/operations/activities/api-schemas.ts +80 -80
- package/src/operations/activities/types.ts +64 -64
- package/src/organization-model/README.md +149 -149
- package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -210
- package/src/organization-model/__tests__/defaults.test.ts +168 -168
- package/src/organization-model/__tests__/domains/actions.test.ts +78 -56
- package/src/organization-model/__tests__/domains/customers.test.ts +299 -299
- package/src/organization-model/__tests__/domains/entities.test.ts +56 -56
- package/src/organization-model/__tests__/domains/goals.test.ts +493 -493
- package/src/organization-model/__tests__/domains/identity.test.ts +280 -280
- package/src/organization-model/__tests__/domains/navigation.test.ts +268 -268
- package/src/organization-model/__tests__/domains/offerings.test.ts +414 -414
- package/src/organization-model/__tests__/domains/policies.test.ts +323 -323
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +293 -293
- package/src/organization-model/__tests__/domains/resources.test.ts +382 -283
- package/src/organization-model/__tests__/domains/roles.test.ts +463 -463
- package/src/organization-model/__tests__/domains/statuses.test.ts +246 -246
- package/src/organization-model/__tests__/domains/systems.test.ts +209 -209
- package/src/organization-model/__tests__/flatten-additive-merge.test.ts +362 -361
- package/src/organization-model/__tests__/foundation.test.ts +77 -77
- package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -144
- package/src/organization-model/__tests__/graph.test.ts +1246 -887
- package/src/organization-model/__tests__/icons.test.ts +10 -1
- package/src/organization-model/__tests__/knowledge.test.ts +251 -15
- package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -438
- package/src/organization-model/__tests__/migration-helpers.test.ts +591 -591
- package/src/organization-model/__tests__/prospecting-ssot.test.ts +103 -103
- package/src/organization-model/__tests__/recursive-system-schema.test.ts +535 -506
- package/src/organization-model/__tests__/resolve.test.ts +274 -164
- package/src/organization-model/__tests__/schema.test.ts +834 -301
- package/src/organization-model/__tests__/surface-projection.test.ts +284 -284
- package/src/organization-model/catalogs/lead-gen.ts +144 -144
- package/src/organization-model/content-kinds/config.ts +36 -36
- package/src/organization-model/content-kinds/index.ts +76 -72
- package/src/organization-model/content-kinds/pipeline.ts +68 -68
- package/src/organization-model/content-kinds/registry.ts +44 -44
- package/src/organization-model/content-kinds/status.ts +71 -71
- package/src/organization-model/content-kinds/template.ts +83 -83
- package/src/organization-model/content-kinds/types.ts +117 -117
- package/src/organization-model/contracts.ts +27 -27
- package/src/organization-model/defaults.ts +40 -50
- package/src/organization-model/domains/actions.ts +333 -239
- package/src/organization-model/domains/customers.ts +78 -78
- package/src/organization-model/domains/entities.ts +144 -144
- package/src/organization-model/domains/goals.ts +83 -83
- package/src/organization-model/domains/knowledge.ts +117 -101
- package/src/organization-model/domains/navigation.ts +139 -139
- package/src/organization-model/domains/offerings.ts +71 -71
- package/src/organization-model/domains/policies.ts +102 -102
- package/src/organization-model/domains/projects.ts +14 -14
- package/src/organization-model/domains/prospecting.ts +395 -395
- package/src/organization-model/domains/resources.ts +167 -132
- package/src/organization-model/domains/roles.ts +96 -96
- package/src/organization-model/domains/sales.test.ts +218 -218
- package/src/organization-model/domains/sales.ts +380 -380
- package/src/organization-model/domains/shared.ts +63 -63
- package/src/organization-model/domains/statuses.ts +339 -339
- package/src/organization-model/domains/systems.ts +217 -172
- package/src/organization-model/foundation.ts +75 -75
- package/src/organization-model/graph/build.ts +1016 -888
- package/src/organization-model/graph/index.ts +4 -4
- package/src/organization-model/graph/link.ts +10 -10
- package/src/organization-model/graph/schema.ts +76 -70
- package/src/organization-model/graph/types.ts +73 -67
- package/src/organization-model/helpers.ts +289 -241
- package/src/organization-model/icons.ts +78 -66
- package/src/organization-model/index.ts +130 -128
- package/src/organization-model/migration-helpers.ts +247 -244
- package/src/organization-model/ontology.ts +661 -0
- package/src/organization-model/organization-graph.mdx +110 -90
- package/src/organization-model/organization-model.mdx +226 -219
- package/src/organization-model/published.ts +289 -235
- package/src/organization-model/resolve.ts +146 -91
- package/src/organization-model/schema.ts +790 -671
- package/src/organization-model/surface-projection.ts +212 -212
- package/src/organization-model/types.ts +177 -167
- package/src/platform/api/types.ts +38 -38
- package/src/platform/constants/versions.ts +3 -3
- package/src/platform/index.ts +23 -23
- package/src/platform/registry/__tests__/command-view.test.ts +10 -10
- package/src/platform/registry/__tests__/resource-link.test.ts +35 -35
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +20 -20
- package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -245
- package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2053
- package/src/platform/registry/__tests__/validation.test.ts +1347 -1347
- package/src/platform/registry/command-view.ts +10 -10
- package/src/platform/registry/index.ts +103 -103
- package/src/platform/registry/resource-link.ts +32 -32
- package/src/platform/registry/resource-registry.ts +890 -890
- package/src/platform/registry/serialization.ts +295 -295
- package/src/platform/registry/serialized-types.ts +166 -166
- package/src/platform/registry/stats-types.ts +68 -68
- package/src/platform/registry/types.ts +425 -425
- package/src/platform/registry/validation.ts +745 -745
- package/src/platform/utils/__tests__/validation.test.ts +1084 -1084
- package/src/platform/utils/validation.ts +425 -425
- package/src/projects/api-schemas.test.ts +39 -39
- package/src/projects/api-schemas.ts +291 -291
- package/src/reference/_generated/contracts.md +2101 -2096
- package/src/reference/glossary.md +76 -76
- package/src/scaffold-registry/__tests__/index.test.ts +206 -206
- package/src/scaffold-registry/__tests__/schema.test.ts +166 -166
- package/src/scaffold-registry/index.ts +392 -392
- package/src/scaffold-registry/schema.ts +243 -243
- package/src/server.ts +289 -289
- package/src/supabase/database.types.ts +3153 -3153
- package/src/test-utils/README.md +37 -37
- package/src/test-utils/entities.ts +108 -108
- package/src/test-utils/fixtures/memberships.ts +82 -82
- package/src/test-utils/index.ts +12 -12
- package/src/test-utils/organization-model.ts +65 -65
- package/src/test-utils/published.ts +6 -6
- package/src/test-utils/rls/RLSTestContext.ts +588 -588
- package/src/test-utils/test-utils.test.ts +44 -44
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
// Phase 4 (D8): DEFAULT_ORGANIZATION_MODEL_SALES no longer exported — pipeline data moved to
|
|
3
|
-
// system.content. CRM_PIPELINE_DEFINITION is retained as the Stateful pipeline shape
|
|
4
|
-
// for CRM business logic (separate from the OM content nodes).
|
|
5
|
-
import { CRM_PIPELINE_DEFINITION, LEAD_GEN_PIPELINE_DEFINITIONS } from '../../organization-model/domains/sales'
|
|
6
|
-
import { ActivityEventSchema } from './activity-events'
|
|
7
|
-
import { DealStageSchema, TransitionItemRequestSchema } from './api-schemas'
|
|
8
|
-
import { deriveActions } from './derive-actions'
|
|
9
|
-
import type { DealStage } from './types'
|
|
10
|
-
|
|
11
|
-
const DEAL_STAGES = [
|
|
12
|
-
'interested',
|
|
13
|
-
'proposal',
|
|
14
|
-
'closing',
|
|
15
|
-
'closed_won',
|
|
16
|
-
'closed_lost',
|
|
17
|
-
'nurturing'
|
|
18
|
-
] as const satisfies readonly DealStage[]
|
|
19
|
-
|
|
20
|
-
function deal(stageKey: string | null, stateKey: string | null = null): Parameters<typeof deriveActions>[0] {
|
|
21
|
-
return { stage_key: stageKey, state_key: stateKey } as Parameters<typeof deriveActions>[0]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe('CRM deal action derivation', () => {
|
|
25
|
-
it('derives the exact base actions for interested deals', () => {
|
|
26
|
-
expect(deriveActions(deal('interested'))).toEqual([
|
|
27
|
-
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
28
|
-
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
29
|
-
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
30
|
-
])
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it.each([
|
|
34
|
-
['discovery_replied', { key: 'send_link', label: 'Send Booking Link' }],
|
|
35
|
-
['discovery_link_sent', { key: 'send_nudge', label: 'Send Nudge' }],
|
|
36
|
-
['discovery_booking_cancelled', { key: 'rebook', label: 'Rebook' }]
|
|
37
|
-
] as const)('adds the expected workflow action for interested/%s', (stateKey, expectedAction) => {
|
|
38
|
-
const expected = [
|
|
39
|
-
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
40
|
-
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
41
|
-
{ key: 'move_to_nurturing', label: 'Move to Nurturing' },
|
|
42
|
-
expectedAction
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
expect(deriveActions(deal('interested', stateKey))).toEqual(expected)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('adds nudge and no-show actions for interested/discovery_nudging', () => {
|
|
49
|
-
expect(deriveActions(deal('interested', 'discovery_nudging'))).toEqual([
|
|
50
|
-
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
51
|
-
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
52
|
-
{ key: 'move_to_nurturing', label: 'Move to Nurturing' },
|
|
53
|
-
{ key: 'send_nudge', label: 'Send Nudge' },
|
|
54
|
-
{ key: 'mark_no_show', label: 'Mark No-Show' }
|
|
55
|
-
])
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('derives exact proposal and closing transitions', () => {
|
|
59
|
-
expect(deriveActions(deal('proposal'))).toEqual([
|
|
60
|
-
{ key: 'move_to_closing', label: 'Move to Closing' },
|
|
61
|
-
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
62
|
-
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
63
|
-
])
|
|
64
|
-
|
|
65
|
-
expect(deriveActions(deal('closing'))).toEqual([
|
|
66
|
-
{ key: 'move_to_closed_won', label: 'Close Won' },
|
|
67
|
-
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
68
|
-
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
69
|
-
])
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it.each(['closed_won', 'closed_lost', 'nurturing', 'legacy_stage', null] as const)(
|
|
73
|
-
'derives no actions for terminal or non-canonical stage %s',
|
|
74
|
-
(stageKey) => {
|
|
75
|
-
expect(deriveActions(deal(stageKey))).toEqual([])
|
|
76
|
-
}
|
|
77
|
-
)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
describe('ActivityEventSchema', () => {
|
|
81
|
-
const timestamp = '2026-04-27T12:34:56.000Z'
|
|
82
|
-
|
|
83
|
-
// Platform events only (8 members). Domain events (reply_received, booking_nudge_sent, etc.)
|
|
84
|
-
// live in @repo/elevasis-operations as CrmDomainActivityEventSchema.
|
|
85
|
-
// See Open Decision #5 in crm-action-system.mdx for rationale.
|
|
86
|
-
it.each([
|
|
87
|
-
[{ type: 'stage_change', timestamp, stageBefore: 'interested', stageAfter: 'proposal', reason: 'qualified' }],
|
|
88
|
-
[{ type: 'state_change', timestamp, stateBefore: null, stateAfter: 'discovery_replied' }],
|
|
89
|
-
[{ type: 'action_taken', timestamp, actionKey: 'send_link', payload: { channel: 'email' } }],
|
|
90
|
-
[{ type: 'approval_created', timestamp, commandId: 'cmd_123', dealStageBefore: 'proposal' }],
|
|
91
|
-
[{ type: 'approval_resolved', timestamp, commandId: 'cmd_123', resolution: 'superseded' }],
|
|
92
|
-
[{ type: 'approval_stale', timestamp, commandId: 'cmd_123', dealStageAfter: 'closing' }],
|
|
93
|
-
[{ type: 'task_created', timestamp, taskId: 'task_123' }],
|
|
94
|
-
[{ type: 'deal_created', timestamp }]
|
|
95
|
-
])('accepts expected %s events', (event) => {
|
|
96
|
-
expect(ActivityEventSchema.safeParse(event).success).toBe(true)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it.each([
|
|
100
|
-
[{ type: 'deal_created', timestamp: 'not-a-date' }],
|
|
101
|
-
[{ type: 'unknown_event', timestamp }],
|
|
102
|
-
[{ type: 'stage_change', timestamp, stageBefore: 'interested' }],
|
|
103
|
-
[{ type: 'approval_resolved', timestamp, commandId: 'cmd_123', resolution: 'approved' }],
|
|
104
|
-
[{ type: 'booking_nudge_sent', timestamp, followupDay: '2' }],
|
|
105
|
-
[{ type: 'action_taken', timestamp }]
|
|
106
|
-
])('rejects malformed event payload %o', (event) => {
|
|
107
|
-
expect(ActivityEventSchema.safeParse(event).success).toBe(false)
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
describe('CRM stage and transition vocabulary contracts', () => {
|
|
112
|
-
// Phase 4 (D8): DEFAULT_ORGANIZATION_MODEL_SALES.pipelines removed.
|
|
113
|
-
// CRM_PIPELINE_DEFINITION (StatefulPipelineDefinition) is the retained Stateful-trait
|
|
114
|
-
// pipeline shape used by CRM business logic. stageKey → DealStageSchema alignment
|
|
115
|
-
// is now verified against CRM_PIPELINE_DEFINITION.stages[*].stageKey.
|
|
116
|
-
it('keeps DealStage, DealStageSchema, and CRM_PIPELINE_DEFINITION stages aligned', () => {
|
|
117
|
-
const crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey)
|
|
118
|
-
|
|
119
|
-
expect(crmStageKeys).toEqual([...DEAL_STAGES])
|
|
120
|
-
expect(DealStageSchema.options).toEqual([...DEAL_STAGES])
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('accepts every canonical CRM deal stage in transition requests', () => {
|
|
124
|
-
for (const stageKey of DEAL_STAGES) {
|
|
125
|
-
expect(
|
|
126
|
-
TransitionItemRequestSchema.safeParse({
|
|
127
|
-
pipelineKey: CRM_PIPELINE_DEFINITION.pipelineKey,
|
|
128
|
-
stageKey,
|
|
129
|
-
stateKey: null,
|
|
130
|
-
expectedUpdatedAt: '2026-04-27T12:34:56.000Z'
|
|
131
|
-
}).success
|
|
132
|
-
).toBe(true)
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('accepts canonical lead-gen stage/state pairs in transition requests', () => {
|
|
137
|
-
for (const pipelineDefinitions of Object.values(LEAD_GEN_PIPELINE_DEFINITIONS)) {
|
|
138
|
-
for (const pipeline of pipelineDefinitions) {
|
|
139
|
-
for (const stage of pipeline.stages) {
|
|
140
|
-
for (const state of stage.states) {
|
|
141
|
-
expect(
|
|
142
|
-
TransitionItemRequestSchema.safeParse({
|
|
143
|
-
pipelineKey: pipeline.pipelineKey,
|
|
144
|
-
stageKey: stage.stageKey,
|
|
145
|
-
stateKey: state.stateKey
|
|
146
|
-
}).success
|
|
147
|
-
).toBe(true)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
})
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
// Phase 4 (D8): DEFAULT_ORGANIZATION_MODEL_SALES no longer exported — pipeline data moved to
|
|
3
|
+
// system.content. CRM_PIPELINE_DEFINITION is retained as the Stateful pipeline shape
|
|
4
|
+
// for CRM business logic (separate from the OM content nodes).
|
|
5
|
+
import { CRM_PIPELINE_DEFINITION, LEAD_GEN_PIPELINE_DEFINITIONS } from '../../organization-model/domains/sales'
|
|
6
|
+
import { ActivityEventSchema } from './activity-events'
|
|
7
|
+
import { DealStageSchema, TransitionItemRequestSchema } from './api-schemas'
|
|
8
|
+
import { deriveActions } from './derive-actions'
|
|
9
|
+
import type { DealStage } from './types'
|
|
10
|
+
|
|
11
|
+
const DEAL_STAGES = [
|
|
12
|
+
'interested',
|
|
13
|
+
'proposal',
|
|
14
|
+
'closing',
|
|
15
|
+
'closed_won',
|
|
16
|
+
'closed_lost',
|
|
17
|
+
'nurturing'
|
|
18
|
+
] as const satisfies readonly DealStage[]
|
|
19
|
+
|
|
20
|
+
function deal(stageKey: string | null, stateKey: string | null = null): Parameters<typeof deriveActions>[0] {
|
|
21
|
+
return { stage_key: stageKey, state_key: stateKey } as Parameters<typeof deriveActions>[0]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('CRM deal action derivation', () => {
|
|
25
|
+
it('derives the exact base actions for interested deals', () => {
|
|
26
|
+
expect(deriveActions(deal('interested'))).toEqual([
|
|
27
|
+
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
28
|
+
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
29
|
+
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
30
|
+
])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it.each([
|
|
34
|
+
['discovery_replied', { key: 'send_link', label: 'Send Booking Link' }],
|
|
35
|
+
['discovery_link_sent', { key: 'send_nudge', label: 'Send Nudge' }],
|
|
36
|
+
['discovery_booking_cancelled', { key: 'rebook', label: 'Rebook' }]
|
|
37
|
+
] as const)('adds the expected workflow action for interested/%s', (stateKey, expectedAction) => {
|
|
38
|
+
const expected = [
|
|
39
|
+
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
40
|
+
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
41
|
+
{ key: 'move_to_nurturing', label: 'Move to Nurturing' },
|
|
42
|
+
expectedAction
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
expect(deriveActions(deal('interested', stateKey))).toEqual(expected)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('adds nudge and no-show actions for interested/discovery_nudging', () => {
|
|
49
|
+
expect(deriveActions(deal('interested', 'discovery_nudging'))).toEqual([
|
|
50
|
+
{ key: 'move_to_proposal', label: 'Move to Proposal' },
|
|
51
|
+
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
52
|
+
{ key: 'move_to_nurturing', label: 'Move to Nurturing' },
|
|
53
|
+
{ key: 'send_nudge', label: 'Send Nudge' },
|
|
54
|
+
{ key: 'mark_no_show', label: 'Mark No-Show' }
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('derives exact proposal and closing transitions', () => {
|
|
59
|
+
expect(deriveActions(deal('proposal'))).toEqual([
|
|
60
|
+
{ key: 'move_to_closing', label: 'Move to Closing' },
|
|
61
|
+
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
62
|
+
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
expect(deriveActions(deal('closing'))).toEqual([
|
|
66
|
+
{ key: 'move_to_closed_won', label: 'Close Won' },
|
|
67
|
+
{ key: 'move_to_closed_lost', label: 'Close Lost' },
|
|
68
|
+
{ key: 'move_to_nurturing', label: 'Move to Nurturing' }
|
|
69
|
+
])
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it.each(['closed_won', 'closed_lost', 'nurturing', 'legacy_stage', null] as const)(
|
|
73
|
+
'derives no actions for terminal or non-canonical stage %s',
|
|
74
|
+
(stageKey) => {
|
|
75
|
+
expect(deriveActions(deal(stageKey))).toEqual([])
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe('ActivityEventSchema', () => {
|
|
81
|
+
const timestamp = '2026-04-27T12:34:56.000Z'
|
|
82
|
+
|
|
83
|
+
// Platform events only (8 members). Domain events (reply_received, booking_nudge_sent, etc.)
|
|
84
|
+
// live in @repo/elevasis-operations as CrmDomainActivityEventSchema.
|
|
85
|
+
// See Open Decision #5 in crm-action-system.mdx for rationale.
|
|
86
|
+
it.each([
|
|
87
|
+
[{ type: 'stage_change', timestamp, stageBefore: 'interested', stageAfter: 'proposal', reason: 'qualified' }],
|
|
88
|
+
[{ type: 'state_change', timestamp, stateBefore: null, stateAfter: 'discovery_replied' }],
|
|
89
|
+
[{ type: 'action_taken', timestamp, actionKey: 'send_link', payload: { channel: 'email' } }],
|
|
90
|
+
[{ type: 'approval_created', timestamp, commandId: 'cmd_123', dealStageBefore: 'proposal' }],
|
|
91
|
+
[{ type: 'approval_resolved', timestamp, commandId: 'cmd_123', resolution: 'superseded' }],
|
|
92
|
+
[{ type: 'approval_stale', timestamp, commandId: 'cmd_123', dealStageAfter: 'closing' }],
|
|
93
|
+
[{ type: 'task_created', timestamp, taskId: 'task_123' }],
|
|
94
|
+
[{ type: 'deal_created', timestamp }]
|
|
95
|
+
])('accepts expected %s events', (event) => {
|
|
96
|
+
expect(ActivityEventSchema.safeParse(event).success).toBe(true)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it.each([
|
|
100
|
+
[{ type: 'deal_created', timestamp: 'not-a-date' }],
|
|
101
|
+
[{ type: 'unknown_event', timestamp }],
|
|
102
|
+
[{ type: 'stage_change', timestamp, stageBefore: 'interested' }],
|
|
103
|
+
[{ type: 'approval_resolved', timestamp, commandId: 'cmd_123', resolution: 'approved' }],
|
|
104
|
+
[{ type: 'booking_nudge_sent', timestamp, followupDay: '2' }],
|
|
105
|
+
[{ type: 'action_taken', timestamp }]
|
|
106
|
+
])('rejects malformed event payload %o', (event) => {
|
|
107
|
+
expect(ActivityEventSchema.safeParse(event).success).toBe(false)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('CRM stage and transition vocabulary contracts', () => {
|
|
112
|
+
// Phase 4 (D8): DEFAULT_ORGANIZATION_MODEL_SALES.pipelines removed.
|
|
113
|
+
// CRM_PIPELINE_DEFINITION (StatefulPipelineDefinition) is the retained Stateful-trait
|
|
114
|
+
// pipeline shape used by CRM business logic. stageKey → DealStageSchema alignment
|
|
115
|
+
// is now verified against CRM_PIPELINE_DEFINITION.stages[*].stageKey.
|
|
116
|
+
it('keeps DealStage, DealStageSchema, and CRM_PIPELINE_DEFINITION stages aligned', () => {
|
|
117
|
+
const crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey)
|
|
118
|
+
|
|
119
|
+
expect(crmStageKeys).toEqual([...DEAL_STAGES])
|
|
120
|
+
expect(DealStageSchema.options).toEqual([...DEAL_STAGES])
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('accepts every canonical CRM deal stage in transition requests', () => {
|
|
124
|
+
for (const stageKey of DEAL_STAGES) {
|
|
125
|
+
expect(
|
|
126
|
+
TransitionItemRequestSchema.safeParse({
|
|
127
|
+
pipelineKey: CRM_PIPELINE_DEFINITION.pipelineKey,
|
|
128
|
+
stageKey,
|
|
129
|
+
stateKey: null,
|
|
130
|
+
expectedUpdatedAt: '2026-04-27T12:34:56.000Z'
|
|
131
|
+
}).success
|
|
132
|
+
).toBe(true)
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('accepts canonical lead-gen stage/state pairs in transition requests', () => {
|
|
137
|
+
for (const pipelineDefinitions of Object.values(LEAD_GEN_PIPELINE_DEFINITIONS)) {
|
|
138
|
+
for (const pipeline of pipelineDefinitions) {
|
|
139
|
+
for (const stage of pipeline.stages) {
|
|
140
|
+
for (const state of stage.states) {
|
|
141
|
+
expect(
|
|
142
|
+
TransitionItemRequestSchema.safeParse({
|
|
143
|
+
pipelineKey: pipeline.pipelineKey,
|
|
144
|
+
stageKey: stage.stageKey,
|
|
145
|
+
stateKey: state.stateKey
|
|
146
|
+
}).success
|
|
147
|
+
).toBe(true)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
})
|