@elevasis/core 0.13.0 → 0.14.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 +1 -1
- package/dist/index.js +9 -2
- package/dist/organization-model/index.d.ts +1 -1
- package/dist/organization-model/index.js +9 -2
- package/dist/test-utils/index.d.ts +463 -377
- package/dist/test-utils/index.js +9 -2
- package/package.json +1 -1
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2324 -0
- package/src/business/acquisition/activity-events.test.ts +250 -0
- package/src/business/acquisition/activity-events.ts +7 -65
- package/src/business/acquisition/api-schemas.test.ts +1180 -0
- package/src/business/acquisition/api-schemas.ts +1075 -859
- package/src/business/acquisition/crm-state-actions.test.ts +160 -0
- package/src/business/acquisition/derive-actions.test.ts +518 -0
- package/src/business/acquisition/derive-actions.ts +103 -90
- package/src/business/acquisition/index.ts +149 -111
- package/src/business/acquisition/stateful.ts +30 -0
- package/src/business/acquisition/types.ts +44 -77
- package/src/execution/engine/index.ts +437 -434
- package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -360
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -186
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -338
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -210
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -0
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -134
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -75
- package/src/execution/engine/tools/integration/service.test.ts +34 -9
- package/src/execution/engine/tools/integration/service.ts +6 -3
- package/src/execution/engine/tools/lead-service-types.ts +945 -888
- package/src/execution/engine/tools/platform/acquisition/types.ts +266 -260
- package/src/execution/engine/tools/registry.ts +701 -699
- package/src/execution/engine/tools/tool-maps.ts +816 -791
- package/src/execution/engine/workflow/types.ts +11 -0
- package/src/organization-model/contracts.ts +4 -4
- package/src/organization-model/domains/navigation.ts +62 -62
- package/src/organization-model/domains/sales.ts +272 -0
- package/src/organization-model/published.ts +21 -21
- package/src/organization-model/resolve.ts +21 -8
- package/src/platform/constants/versions.ts +1 -1
- package/src/reference/_generated/contracts.md +2324 -0
- package/src/supabase/database.types.ts +2958 -2886
|
@@ -82,6 +82,17 @@ export interface WorkflowDefinition {
|
|
|
82
82
|
* If provided, workflow appears in Execution Runner UI
|
|
83
83
|
*/
|
|
84
84
|
interface?: ExecutionInterface
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Lead-gen processing stage this workflow implements (optional).
|
|
88
|
+
* Must match a key in the platform lead-gen stage catalog.
|
|
89
|
+
* Used by org-os graph derivation to surface workflow→stage edges and
|
|
90
|
+
* by pipeline_config validation to confirm each catalog stage has an
|
|
91
|
+
* implementing workflow before a list is activated.
|
|
92
|
+
*
|
|
93
|
+
* Example: stageImplemented: 'verified' on the email-verification workflow.
|
|
94
|
+
*/
|
|
95
|
+
stageImplemented?: string
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
/**
|
|
@@ -9,7 +9,7 @@ export const MONITORING_FEATURE_ID = 'monitoring' as const
|
|
|
9
9
|
export const SETTINGS_FEATURE_ID = 'settings' as const
|
|
10
10
|
export const SEO_FEATURE_ID = 'seo' as const
|
|
11
11
|
|
|
12
|
-
export const SALES_PIPELINE_SURFACE_ID = 'crm.pipeline' as const
|
|
13
|
-
export const PROSPECTING_LISTS_SURFACE_ID = 'lead-gen.lists' as const
|
|
14
|
-
export const OPERATIONS_COMMAND_VIEW_SURFACE_ID = 'operations.command-view' as const
|
|
15
|
-
export const SETTINGS_ROLES_SURFACE_ID = 'settings.roles' as const
|
|
12
|
+
export const SALES_PIPELINE_SURFACE_ID = 'crm.pipeline' as const
|
|
13
|
+
export const PROSPECTING_LISTS_SURFACE_ID = 'lead-gen.lists' as const
|
|
14
|
+
export const OPERATIONS_COMMAND_VIEW_SURFACE_ID = 'operations.command-view' as const
|
|
15
|
+
export const SETTINGS_ROLES_SURFACE_ID = 'settings.roles' as const
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
import {
|
|
3
|
-
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
4
|
-
PROJECTS_VIEW_CAPABILITY_ID,
|
|
5
|
-
PROJECTS_FEATURE_ID,
|
|
6
|
-
PROJECTS_INDEX_SURFACE_ID,
|
|
7
|
-
SETTINGS_ROLES_SURFACE_ID
|
|
8
|
-
} from '../contracts'
|
|
2
|
+
import {
|
|
3
|
+
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
4
|
+
PROJECTS_VIEW_CAPABILITY_ID,
|
|
5
|
+
PROJECTS_FEATURE_ID,
|
|
6
|
+
PROJECTS_INDEX_SURFACE_ID,
|
|
7
|
+
SETTINGS_ROLES_SURFACE_ID
|
|
8
|
+
} from '../contracts'
|
|
9
9
|
import { DescriptionSchema, IconNameSchema, LabelSchema, ModelIdSchema, PathSchema, ReferenceIdsSchema } from './shared'
|
|
10
10
|
|
|
11
11
|
export const SurfaceTypeSchema = z.enum(['page', 'dashboard', 'graph', 'detail', 'list', 'settings'])
|
|
@@ -15,10 +15,10 @@ export const SurfaceDefinitionSchema = z.object({
|
|
|
15
15
|
label: LabelSchema,
|
|
16
16
|
path: PathSchema,
|
|
17
17
|
surfaceType: SurfaceTypeSchema,
|
|
18
|
-
description: DescriptionSchema.optional(),
|
|
19
|
-
enabled: z.boolean().default(true),
|
|
20
|
-
devOnly: z.boolean().optional(),
|
|
21
|
-
icon: IconNameSchema.optional(),
|
|
18
|
+
description: DescriptionSchema.optional(),
|
|
19
|
+
enabled: z.boolean().default(true),
|
|
20
|
+
devOnly: z.boolean().optional(),
|
|
21
|
+
icon: IconNameSchema.optional(),
|
|
22
22
|
featureId: ModelIdSchema.optional(),
|
|
23
23
|
featureIds: ReferenceIdsSchema,
|
|
24
24
|
entityIds: ReferenceIdsSchema,
|
|
@@ -92,16 +92,16 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
|
|
|
92
92
|
resourceIds: [],
|
|
93
93
|
capabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
|
|
94
94
|
},
|
|
95
|
-
{
|
|
96
|
-
id: OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
97
|
-
label: 'Command View',
|
|
98
|
-
path: '/operations/command-view',
|
|
99
|
-
surfaceType: 'graph',
|
|
100
|
-
enabled: true,
|
|
101
|
-
devOnly: true,
|
|
102
|
-
featureId: 'operations',
|
|
103
|
-
featureIds: ['operations'],
|
|
104
|
-
entityIds: [],
|
|
95
|
+
{
|
|
96
|
+
id: OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
97
|
+
label: 'Command View',
|
|
98
|
+
path: '/operations/command-view',
|
|
99
|
+
surfaceType: 'graph',
|
|
100
|
+
enabled: true,
|
|
101
|
+
devOnly: true,
|
|
102
|
+
featureId: 'operations',
|
|
103
|
+
featureIds: ['operations'],
|
|
104
|
+
entityIds: [],
|
|
105
105
|
resourceIds: [],
|
|
106
106
|
capabilityIds: ['operations.command-view']
|
|
107
107
|
},
|
|
@@ -261,45 +261,45 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
|
|
|
261
261
|
resourceIds: [],
|
|
262
262
|
capabilityIds: []
|
|
263
263
|
},
|
|
264
|
-
{
|
|
265
|
-
id: 'settings.appearance',
|
|
266
|
-
label: 'Appearance',
|
|
267
|
-
path: '/settings/appearance',
|
|
264
|
+
{
|
|
265
|
+
id: 'settings.appearance',
|
|
266
|
+
label: 'Appearance',
|
|
267
|
+
path: '/settings/appearance',
|
|
268
|
+
surfaceType: 'settings',
|
|
269
|
+
enabled: true,
|
|
270
|
+
featureId: 'settings',
|
|
271
|
+
featureIds: ['settings'],
|
|
272
|
+
entityIds: [],
|
|
273
|
+
resourceIds: [],
|
|
274
|
+
capabilityIds: []
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: SETTINGS_ROLES_SURFACE_ID,
|
|
278
|
+
label: 'My Roles',
|
|
279
|
+
path: '/settings/roles',
|
|
268
280
|
surfaceType: 'settings',
|
|
269
281
|
enabled: true,
|
|
270
282
|
featureId: 'settings',
|
|
271
283
|
featureIds: ['settings'],
|
|
272
284
|
entityIds: [],
|
|
273
|
-
resourceIds: [],
|
|
274
|
-
capabilityIds: []
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
id:
|
|
278
|
-
label: '
|
|
279
|
-
path: '/settings/
|
|
280
|
-
surfaceType: 'settings',
|
|
281
|
-
enabled: true,
|
|
282
|
-
featureId: 'settings',
|
|
283
|
-
featureIds: ['settings'],
|
|
284
|
-
entityIds: [],
|
|
285
|
-
resourceIds: [],
|
|
286
|
-
capabilityIds: []
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
id: 'settings.organization',
|
|
290
|
-
label: 'Organization',
|
|
291
|
-
path: '/settings/organization',
|
|
285
|
+
resourceIds: [],
|
|
286
|
+
capabilityIds: []
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
id: 'settings.organization',
|
|
290
|
+
label: 'Organization',
|
|
291
|
+
path: '/settings/organization',
|
|
292
292
|
surfaceType: 'settings',
|
|
293
293
|
enabled: true,
|
|
294
294
|
featureId: 'settings',
|
|
295
295
|
featureIds: ['settings'],
|
|
296
296
|
entityIds: [],
|
|
297
|
-
resourceIds: [],
|
|
298
|
-
capabilityIds: []
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
id: 'settings.credentials',
|
|
302
|
-
label: 'Credentials',
|
|
297
|
+
resourceIds: [],
|
|
298
|
+
capabilityIds: []
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
id: 'settings.credentials',
|
|
302
|
+
label: 'Credentials',
|
|
303
303
|
path: '/settings/credentials',
|
|
304
304
|
surfaceType: 'settings',
|
|
305
305
|
enabled: true,
|
|
@@ -355,12 +355,12 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
|
|
|
355
355
|
},
|
|
356
356
|
{
|
|
357
357
|
id: 'primary-operations',
|
|
358
|
-
label: 'Operations',
|
|
359
|
-
placement: 'primary',
|
|
360
|
-
surfaceIds: [
|
|
361
|
-
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
362
|
-
'operations.overview',
|
|
363
|
-
'operations.resources',
|
|
358
|
+
label: 'Operations',
|
|
359
|
+
placement: 'primary',
|
|
360
|
+
surfaceIds: [
|
|
361
|
+
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
362
|
+
'operations.overview',
|
|
363
|
+
'operations.resources',
|
|
364
364
|
'operations.command-queue',
|
|
365
365
|
'operations.sessions',
|
|
366
366
|
'operations.task-scheduler'
|
|
@@ -385,12 +385,12 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
|
|
|
385
385
|
label: 'Settings',
|
|
386
386
|
placement: 'bottom',
|
|
387
387
|
surfaceIds: [
|
|
388
|
-
'settings.account',
|
|
389
|
-
'settings.appearance',
|
|
390
|
-
SETTINGS_ROLES_SURFACE_ID,
|
|
391
|
-
'settings.organization',
|
|
392
|
-
'settings.credentials',
|
|
393
|
-
'settings.api-keys',
|
|
388
|
+
'settings.account',
|
|
389
|
+
'settings.appearance',
|
|
390
|
+
SETTINGS_ROLES_SURFACE_ID,
|
|
391
|
+
'settings.organization',
|
|
392
|
+
'settings.credentials',
|
|
393
|
+
'settings.api-keys',
|
|
394
394
|
'settings.webhooks',
|
|
395
395
|
'settings.deployments'
|
|
396
396
|
]
|
|
@@ -92,3 +92,275 @@ export const DEFAULT_ORGANIZATION_MODEL_SALES: z.infer<typeof OrganizationModelS
|
|
|
92
92
|
}
|
|
93
93
|
]
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Lead-Gen Stateful Pipeline Definitions (Decision N8, Wave 4)
|
|
98
|
+
//
|
|
99
|
+
// Defines the (pipeline_key, stage_key, state_key) vocabulary for the three
|
|
100
|
+
// entities that carry the Stateful trait via Track B:
|
|
101
|
+
// - acq_lists (pipeline_key='lead-gen', stage_key='lifecycle')
|
|
102
|
+
// - acq_list_members (pipeline_key='lead-gen', stages: outreach / prospecting / qualification)
|
|
103
|
+
// - acq_list_companies (pipeline_key='lead-gen', stages: outreach / prospecting / qualification)
|
|
104
|
+
//
|
|
105
|
+
// DB columns (pipeline_key, stage_key, state_key) remain free-form text with no
|
|
106
|
+
// CHECK constraint — new states can be introduced without a migration (Decision N8).
|
|
107
|
+
// These definitions are the org-specific source of truth consumed by UI and tooling.
|
|
108
|
+
//
|
|
109
|
+
// State vocabularies sourced from the post-restructure sales tree (W3 canonical):
|
|
110
|
+
// outreach/:
|
|
111
|
+
// - personalized (instantly-personalization.ts → contacts)
|
|
112
|
+
// - uploaded (instantly-upload.ts → contacts)
|
|
113
|
+
// - interested (instantly-reply-handler.ts → contacts, initial reply transition)
|
|
114
|
+
// prospecting/:
|
|
115
|
+
// - populated (apify-acquire.ts, apify-scrape.ts → companies)
|
|
116
|
+
// - extracted (website-extract.ts → companies)
|
|
117
|
+
// - discovered (email-discovery.ts, anymailfinder-enrich.ts → contacts)
|
|
118
|
+
// - verified (email-verification.ts → contacts)
|
|
119
|
+
// qualification/:
|
|
120
|
+
// - qualified (company-qualification.ts → companies)
|
|
121
|
+
//
|
|
122
|
+
// The 'pending' state is the W2 backfill default (coalesce(stage, 'pending')).
|
|
123
|
+
// It is valid in any stage and represents "not yet processed by a workflow step".
|
|
124
|
+
// ============================================================================
|
|
125
|
+
|
|
126
|
+
/** One state within a stage — minimal shape: key + display label. */
|
|
127
|
+
export interface StatefulStateDefinition {
|
|
128
|
+
/** Matches state_key values written by workflow steps. */
|
|
129
|
+
stateKey: string
|
|
130
|
+
label: string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** One stage within a pipeline — has a stage_key and an ordered list of valid states. */
|
|
134
|
+
export interface StatefulStageDefinition {
|
|
135
|
+
/** Matches stage_key values written by workflow steps. */
|
|
136
|
+
stageKey: string
|
|
137
|
+
label: string
|
|
138
|
+
states: StatefulStateDefinition[]
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Pipeline definition for a single entity participating in the Stateful trait.
|
|
143
|
+
* Parallel to acq_deals' pipeline_key concept but structured for lead-gen entities.
|
|
144
|
+
*/
|
|
145
|
+
export interface StatefulPipelineDefinition {
|
|
146
|
+
/** Matches pipeline_key values in the database (e.g. 'lead-gen'). */
|
|
147
|
+
pipelineKey: string
|
|
148
|
+
label: string
|
|
149
|
+
/** Entity this pipeline applies to (e.g. 'acq.list', 'acq.list-member', 'acq.list-company'). */
|
|
150
|
+
entityKey: string
|
|
151
|
+
stages: StatefulStageDefinition[]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Find a pipeline definition by pipeline_key within an array of definitions.
|
|
156
|
+
* Preferred over direct array indexing since the model is array-based (not keyed).
|
|
157
|
+
*/
|
|
158
|
+
export function findPipeline(
|
|
159
|
+
definitions: StatefulPipelineDefinition[],
|
|
160
|
+
pipelineKey: string
|
|
161
|
+
): StatefulPipelineDefinition | undefined {
|
|
162
|
+
return definitions.find((def) => def.pipelineKey === pipelineKey)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Common states that appear across multiple stages. */
|
|
166
|
+
const PENDING_STATE: StatefulStateDefinition = { stateKey: 'pending', label: 'Pending' }
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Lead-gen pipeline definition for acq_list_members (contacts).
|
|
170
|
+
* Three stages matching the post-restructure sales subdomain tree.
|
|
171
|
+
*
|
|
172
|
+
* Note: members visit outreach and prospecting states depending on which
|
|
173
|
+
* workflow last processed them. stage_key is set per-transition by the workflow.
|
|
174
|
+
*/
|
|
175
|
+
export const ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE: StatefulPipelineDefinition = {
|
|
176
|
+
pipelineKey: 'lead-gen',
|
|
177
|
+
label: 'Lead Generation',
|
|
178
|
+
entityKey: 'acq.list-member',
|
|
179
|
+
stages: [
|
|
180
|
+
{
|
|
181
|
+
stageKey: 'outreach',
|
|
182
|
+
label: 'Outreach',
|
|
183
|
+
states: [
|
|
184
|
+
PENDING_STATE,
|
|
185
|
+
{ stateKey: 'personalized', label: 'Personalized' },
|
|
186
|
+
{ stateKey: 'uploaded', label: 'Uploaded' },
|
|
187
|
+
{ stateKey: 'interested', label: 'Interested' }
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
stageKey: 'prospecting',
|
|
192
|
+
label: 'Prospecting',
|
|
193
|
+
states: [
|
|
194
|
+
PENDING_STATE,
|
|
195
|
+
{ stateKey: 'discovered', label: 'Discovered' },
|
|
196
|
+
{ stateKey: 'verified', label: 'Verified' }
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
stageKey: 'qualification',
|
|
201
|
+
label: 'Qualification',
|
|
202
|
+
states: [PENDING_STATE]
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Lead-gen pipeline definition for acq_list_companies.
|
|
209
|
+
* Three stages matching the post-restructure sales subdomain tree.
|
|
210
|
+
*
|
|
211
|
+
* Note: companies visit prospecting and qualification states depending on which
|
|
212
|
+
* workflow last processed them. stage_key is set per-transition by the workflow.
|
|
213
|
+
*/
|
|
214
|
+
export const ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE: StatefulPipelineDefinition = {
|
|
215
|
+
pipelineKey: 'lead-gen',
|
|
216
|
+
label: 'Lead Generation',
|
|
217
|
+
entityKey: 'acq.list-company',
|
|
218
|
+
stages: [
|
|
219
|
+
{
|
|
220
|
+
stageKey: 'outreach',
|
|
221
|
+
label: 'Outreach',
|
|
222
|
+
states: [PENDING_STATE]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
stageKey: 'prospecting',
|
|
226
|
+
label: 'Prospecting',
|
|
227
|
+
states: [
|
|
228
|
+
PENDING_STATE,
|
|
229
|
+
{ stateKey: 'populated', label: 'Populated' },
|
|
230
|
+
{ stateKey: 'extracted', label: 'Extracted' }
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
stageKey: 'qualification',
|
|
235
|
+
label: 'Qualification',
|
|
236
|
+
states: [PENDING_STATE, { stateKey: 'qualified', label: 'Qualified' }]
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* All lead-gen pipeline definitions indexed by entity key.
|
|
243
|
+
* Use findPipeline() to locate a definition by pipeline_key within any of these arrays.
|
|
244
|
+
*/
|
|
245
|
+
export const LEAD_GEN_PIPELINE_DEFINITIONS: Record<string, StatefulPipelineDefinition[]> = {
|
|
246
|
+
'acq.list-member': [ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE],
|
|
247
|
+
'acq.list-company': [ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE]
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// Lead-Gen Stage Catalog (Slice C — flag-based processing model)
|
|
252
|
+
//
|
|
253
|
+
// Canonical set of processing stage keys for the flag-based model that replaces
|
|
254
|
+
// the stateful trait on acq_list_members and acq_list_companies. Each key maps
|
|
255
|
+
// to a flag in the processing_state jsonb column (bare boolean per Decision #7).
|
|
256
|
+
//
|
|
257
|
+
// Sources:
|
|
258
|
+
// ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE → personalized, uploaded, interested,
|
|
259
|
+
// discovered, verified
|
|
260
|
+
// ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE → populated, extracted, qualified
|
|
261
|
+
// Design plan hint (lead-gen-domain-cleanup.mdx §4) → scraped, enriched
|
|
262
|
+
//
|
|
263
|
+
// Wave 2 will validate pipeline_config.stages[].key against this catalog at
|
|
264
|
+
// list-create/update time. Each lead-gen workflow in operations will declare
|
|
265
|
+
// stageImplemented: '<key>' in its WorkflowDefinition (Slice D-2).
|
|
266
|
+
// ============================================================================
|
|
267
|
+
|
|
268
|
+
/** One entry in the lead-gen stage catalog. */
|
|
269
|
+
export interface LeadGenStageCatalogEntry {
|
|
270
|
+
/** Matches the flag key written into processing_state jsonb (e.g. 'scraped'). */
|
|
271
|
+
key: string
|
|
272
|
+
/** Human-readable label for UI display. */
|
|
273
|
+
label: string
|
|
274
|
+
/** Short description of what this stage represents. */
|
|
275
|
+
description: string
|
|
276
|
+
/** Canonical pipeline order for UI sorting. Lower = earlier in the funnel. */
|
|
277
|
+
order: number
|
|
278
|
+
/** Which entity's processing_state jsonb carries this flag. */
|
|
279
|
+
entity: 'company' | 'contact'
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Canonical lead-gen processing stage catalog.
|
|
284
|
+
* Keys are the flag names written by workflow steps into processing_state jsonb.
|
|
285
|
+
*
|
|
286
|
+
* Ordered roughly by pipeline progression (prospecting → outreach → qualification).
|
|
287
|
+
*/
|
|
288
|
+
export const LEAD_GEN_STAGE_CATALOG: Record<string, LeadGenStageCatalogEntry> = {
|
|
289
|
+
// Prospecting — company population
|
|
290
|
+
scraped: {
|
|
291
|
+
key: 'scraped',
|
|
292
|
+
label: 'Scraped',
|
|
293
|
+
description: 'Company was scraped from a source directory (Apify actor run).',
|
|
294
|
+
order: 1,
|
|
295
|
+
entity: 'company'
|
|
296
|
+
},
|
|
297
|
+
populated: {
|
|
298
|
+
key: 'populated',
|
|
299
|
+
label: 'Populated',
|
|
300
|
+
description: 'Company record populated with structured data from scrape results.',
|
|
301
|
+
order: 2,
|
|
302
|
+
entity: 'company'
|
|
303
|
+
},
|
|
304
|
+
extracted: {
|
|
305
|
+
key: 'extracted',
|
|
306
|
+
label: 'Extracted',
|
|
307
|
+
description: 'Website content extracted and parsed for company intelligence.',
|
|
308
|
+
order: 3,
|
|
309
|
+
entity: 'company'
|
|
310
|
+
},
|
|
311
|
+
enriched: {
|
|
312
|
+
key: 'enriched',
|
|
313
|
+
label: 'Enriched',
|
|
314
|
+
description: 'Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).',
|
|
315
|
+
order: 4,
|
|
316
|
+
entity: 'company'
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
// Prospecting — contact discovery
|
|
320
|
+
discovered: {
|
|
321
|
+
key: 'discovered',
|
|
322
|
+
label: 'Discovered',
|
|
323
|
+
description: 'Contact email address discovered via an email-discovery workflow.',
|
|
324
|
+
order: 5,
|
|
325
|
+
entity: 'contact'
|
|
326
|
+
},
|
|
327
|
+
verified: {
|
|
328
|
+
key: 'verified',
|
|
329
|
+
label: 'Verified',
|
|
330
|
+
description: 'Contact email address verified as deliverable (email verification workflow).',
|
|
331
|
+
order: 6,
|
|
332
|
+
entity: 'contact'
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
// Qualification
|
|
336
|
+
qualified: {
|
|
337
|
+
key: 'qualified',
|
|
338
|
+
label: 'Qualified',
|
|
339
|
+
description: 'Company passed the ICP qualification rubric (company-qualification workflow).',
|
|
340
|
+
order: 7,
|
|
341
|
+
entity: 'company'
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// Outreach
|
|
345
|
+
personalized: {
|
|
346
|
+
key: 'personalized',
|
|
347
|
+
label: 'Personalized',
|
|
348
|
+
description: 'Outreach message personalized for the contact (Instantly personalization workflow).',
|
|
349
|
+
order: 8,
|
|
350
|
+
entity: 'contact'
|
|
351
|
+
},
|
|
352
|
+
uploaded: {
|
|
353
|
+
key: 'uploaded',
|
|
354
|
+
label: 'Uploaded',
|
|
355
|
+
description: 'Contact uploaded to an Instantly campaign for outreach.',
|
|
356
|
+
order: 9,
|
|
357
|
+
entity: 'contact'
|
|
358
|
+
},
|
|
359
|
+
interested: {
|
|
360
|
+
key: 'interested',
|
|
361
|
+
label: 'Interested',
|
|
362
|
+
description: 'Contact replied with a positive signal (Instantly reply-handler transition).',
|
|
363
|
+
order: 10,
|
|
364
|
+
entity: 'contact'
|
|
365
|
+
}
|
|
366
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { OrganizationModelSchema } from './schema'
|
|
2
|
-
export { FeatureSchema, NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/features'
|
|
3
|
-
export { LinkSchema } from './graph/link'
|
|
2
|
+
export { FeatureSchema, NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/features'
|
|
3
|
+
export { LinkSchema } from './graph/link'
|
|
4
4
|
export { TechStackEntrySchema } from './domains/shared'
|
|
5
5
|
export {
|
|
6
6
|
PROJECTS_FEATURE_ID,
|
|
@@ -11,12 +11,12 @@ export {
|
|
|
11
11
|
OPERATIONS_FEATURE_ID,
|
|
12
12
|
MONITORING_FEATURE_ID,
|
|
13
13
|
SETTINGS_FEATURE_ID,
|
|
14
|
-
SEO_FEATURE_ID,
|
|
15
|
-
SALES_PIPELINE_SURFACE_ID,
|
|
16
|
-
PROSPECTING_LISTS_SURFACE_ID,
|
|
17
|
-
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
18
|
-
SETTINGS_ROLES_SURFACE_ID
|
|
19
|
-
} from './contracts'
|
|
14
|
+
SEO_FEATURE_ID,
|
|
15
|
+
SALES_PIPELINE_SURFACE_ID,
|
|
16
|
+
PROSPECTING_LISTS_SURFACE_ID,
|
|
17
|
+
OPERATIONS_COMMAND_VIEW_SURFACE_ID,
|
|
18
|
+
SETTINGS_ROLES_SURFACE_ID
|
|
19
|
+
} from './contracts'
|
|
20
20
|
export { DEFAULT_ORGANIZATION_MODEL } from './defaults'
|
|
21
21
|
export {
|
|
22
22
|
DEFAULT_ORGANIZATION_MODEL_STATUSES,
|
|
@@ -57,25 +57,25 @@ export type {
|
|
|
57
57
|
OrganizationModelCustomerFirmographics,
|
|
58
58
|
OrganizationModelCustomers,
|
|
59
59
|
OrganizationModelCustomerSegment,
|
|
60
|
-
OrganizationModelFeature,
|
|
61
|
-
OrganizationModelGoals,
|
|
62
|
-
OrganizationModelKeyResult,
|
|
63
|
-
OrganizationModelObjective,
|
|
60
|
+
OrganizationModelFeature,
|
|
61
|
+
OrganizationModelGoals,
|
|
62
|
+
OrganizationModelKeyResult,
|
|
63
|
+
OrganizationModelObjective,
|
|
64
64
|
OrganizationModelOfferings,
|
|
65
65
|
OrganizationModelOperationEntry,
|
|
66
66
|
OrganizationModelOperationSemanticClass,
|
|
67
67
|
OrganizationModelOperations,
|
|
68
|
-
OrganizationModelPricingModel,
|
|
69
|
-
OrganizationModelProduct,
|
|
70
|
-
OrganizationModelRole,
|
|
68
|
+
OrganizationModelPricingModel,
|
|
69
|
+
OrganizationModelProduct,
|
|
70
|
+
OrganizationModelRole,
|
|
71
71
|
OrganizationModelTechStackEntry,
|
|
72
72
|
OrganizationModelRoles,
|
|
73
|
-
OrganizationModelStatuses,
|
|
74
|
-
OrganizationModelStatusEntry,
|
|
75
|
-
OrganizationModelStatusSemanticClass,
|
|
76
|
-
NodeIdPath,
|
|
77
|
-
NodeIdString
|
|
78
|
-
} from './types'
|
|
73
|
+
OrganizationModelStatuses,
|
|
74
|
+
OrganizationModelStatusEntry,
|
|
75
|
+
OrganizationModelStatusSemanticClass,
|
|
76
|
+
NodeIdPath,
|
|
77
|
+
NodeIdString
|
|
78
|
+
} from './types'
|
|
79
79
|
|
|
80
80
|
export type {
|
|
81
81
|
FoundationBranding,
|
|
@@ -31,11 +31,24 @@ function deepMerge<T>(base: T, override: DeepPartial<T> | undefined): T {
|
|
|
31
31
|
return result as T
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function defineOrganizationModel<T extends DeepPartial<OrganizationModel>>(model: T): T {
|
|
35
|
-
return model
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function resolveOrganizationModel(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
export function defineOrganizationModel<T extends DeepPartial<OrganizationModel>>(model: T): T {
|
|
35
|
+
return model
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function resolveOrganizationModel(
|
|
39
|
+
override?: DeepPartial<OrganizationModel>,
|
|
40
|
+
organizationId?: string
|
|
41
|
+
): OrganizationModel {
|
|
42
|
+
const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override)
|
|
43
|
+
const model = OrganizationModelSchema.parse(merged)
|
|
44
|
+
|
|
45
|
+
if (!model.sales?.pipelines || model.sales.pipelines.length === 0) {
|
|
46
|
+
const orgLabel = organizationId ? `Organization ${organizationId}` : 'Organization'
|
|
47
|
+
throw new Error(
|
|
48
|
+
`${orgLabel} has no sales pipeline configuration. ` +
|
|
49
|
+
`This indicates an incomplete provisioning state. Run org provisioning to seed defaults.`
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return model
|
|
54
|
+
}
|