@elevasis/core 0.4.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 (67) hide show
  1. package/dist/business/entities-published.d.ts +215 -0
  2. package/dist/business/entities-published.js +69 -0
  3. package/dist/index.d.ts +436 -42
  4. package/dist/index.js +601 -50
  5. package/dist/organization-model/index.d.ts +436 -42
  6. package/dist/organization-model/index.js +601 -50
  7. package/package.json +7 -3
  8. package/src/__tests__/publish.test.ts +1 -1
  9. package/src/__tests__/template-foundations-compatibility.test.ts +2 -2
  10. package/src/business/README.md +52 -0
  11. package/src/business/__tests__/entities-published.test.ts +33 -0
  12. package/src/business/acquisition/types.ts +2 -0
  13. package/src/business/entities-published.ts +24 -0
  14. package/src/commands/queue/types/task.ts +3 -3
  15. package/src/execution/engine/index.ts +8 -0
  16. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +2 -3
  17. package/src/execution/engine/tools/registry.ts +26 -24
  18. package/src/execution/engine/tools/tool-maps.ts +13 -9
  19. package/src/execution/engine/workflow/types.ts +2 -3
  20. package/src/organization-model/README.md +16 -12
  21. package/src/organization-model/__tests__/defaults.test.ts +175 -0
  22. package/src/organization-model/__tests__/domains/customers.test.ts +295 -0
  23. package/src/organization-model/__tests__/domains/goals.test.ts +479 -0
  24. package/src/organization-model/__tests__/domains/identity.test.ts +278 -0
  25. package/src/organization-model/__tests__/domains/navigation.test.ts +212 -0
  26. package/src/organization-model/__tests__/domains/offerings.test.ts +419 -0
  27. package/src/organization-model/__tests__/domains/operations.test.ts +203 -0
  28. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +362 -0
  29. package/src/organization-model/__tests__/domains/roles.test.ts +347 -0
  30. package/src/organization-model/__tests__/domains/statuses.test.ts +243 -0
  31. package/src/organization-model/__tests__/foundation.test.ts +105 -0
  32. package/src/organization-model/__tests__/resolve.test.ts +447 -3
  33. package/src/organization-model/__tests__/schema.test.ts +407 -0
  34. package/src/organization-model/contracts.ts +12 -1
  35. package/src/organization-model/defaults.ts +53 -17
  36. package/src/organization-model/domains/customers.ts +75 -0
  37. package/src/organization-model/domains/goals.ts +80 -0
  38. package/src/organization-model/domains/identity.ts +87 -0
  39. package/src/organization-model/domains/navigation.ts +43 -4
  40. package/src/organization-model/domains/offerings.ts +66 -0
  41. package/src/organization-model/domains/operations.ts +85 -0
  42. package/src/organization-model/domains/{delivery.ts → projects.ts} +6 -6
  43. package/src/organization-model/domains/{lead-gen.ts → prospecting.ts} +5 -5
  44. package/src/organization-model/domains/roles.ts +55 -0
  45. package/src/organization-model/domains/sales.ts +94 -0
  46. package/src/organization-model/domains/shared.ts +30 -1
  47. package/src/organization-model/domains/statuses.ts +130 -0
  48. package/src/organization-model/foundation.ts +3 -3
  49. package/src/organization-model/index.ts +3 -3
  50. package/src/organization-model/organization-graph.mdx +1 -0
  51. package/src/organization-model/organization-model.mdx +84 -19
  52. package/src/organization-model/published.ts +62 -4
  53. package/src/organization-model/schema.ts +67 -7
  54. package/src/organization-model/types.ts +31 -7
  55. package/src/platform/constants/versions.ts +1 -1
  56. package/src/platform/registry/types.ts +1 -1
  57. package/src/projects/api-schemas.ts +1 -0
  58. package/src/reference/_generated/contracts.md +116 -8
  59. package/src/reference/glossary.md +25 -4
  60. package/src/requests/__tests__/api-schemas.test.ts +277 -0
  61. package/src/requests/api-schemas.ts +83 -0
  62. package/src/requests/index.ts +1 -0
  63. package/src/supabase/database.types.ts +88 -0
  64. package/src/organization-model/domains/crm.ts +0 -46
  65. /package/src/business/{delivery → projects}/index.ts +0 -0
  66. /package/src/business/{delivery → projects}/types.ts +0 -0
  67. /package/src/business/{crm → sales}/api-schemas.ts +0 -0
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Measurable outcome schema — one trackable result that supports a goal.
5
+ // The field name `keyResults` is used for compatibility with OKR tooling;
6
+ // user-facing surfaces and documentation MUST say "measurable outcomes",
7
+ // never "key results" or "OKR".
8
+ // ---------------------------------------------------------------------------
9
+
10
+ export const KeyResultSchema = z.object({
11
+ /** Stable unique identifier for the measurable outcome (e.g. "kr-revenue-q1"). */
12
+ id: z.string().trim().min(1).max(100),
13
+ /** Plain-language description of this measurable outcome (e.g. "Increase trial-to-paid conversion"). */
14
+ description: z.string().trim().min(1).max(500),
15
+ /**
16
+ * What is being measured — the metric name (e.g. "monthly revenue", "NPS score",
17
+ * "trial-to-paid conversion rate"). Free-form string.
18
+ */
19
+ targetMetric: z.string().trim().min(1).max(200),
20
+ /** Current measured value. Defaults to 0 when not yet tracked. */
21
+ currentValue: z.number().default(0),
22
+ /**
23
+ * Target value to reach for this measurable outcome to be considered achieved.
24
+ * Optional — omit if the outcome is directional (e.g. "reduce churn") without
25
+ * a hard numeric target.
26
+ */
27
+ targetValue: z.number().optional()
28
+ })
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Objective schema — one goal the organization is working toward.
32
+ // User-facing label is "goal"; this schema type is named Objective for
33
+ // structural continuity with OKR tooling. Do NOT expose "OKR", "objective",
34
+ // or "key result" in any user-facing label or documentation.
35
+ //
36
+ // Period fields use ISO 8601 date strings (YYYY-MM-DD). Cross-schema
37
+ // validation (periodEnd > periodStart) is enforced in
38
+ // `OrganizationModelSchema.superRefine()`.
39
+ // ---------------------------------------------------------------------------
40
+
41
+ const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/
42
+
43
+ export const ObjectiveSchema = z.object({
44
+ /** Stable unique identifier for the goal (e.g. "goal-grow-arr-q1-2026"). */
45
+ id: z.string().trim().min(1).max(100),
46
+ /** Plain-language description of what the organization wants to achieve. */
47
+ description: z.string().trim().min(1).max(1000),
48
+ /**
49
+ * Start of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
50
+ * Must be strictly before `periodEnd`.
51
+ */
52
+ periodStart: z.string().regex(ISO_DATE_REGEX, 'periodStart must be an ISO date string (YYYY-MM-DD)'),
53
+ /**
54
+ * End of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
55
+ * Must be strictly after `periodStart`.
56
+ * Enforced via `OrganizationModelSchema.superRefine()`.
57
+ */
58
+ periodEnd: z.string().regex(ISO_DATE_REGEX, 'periodEnd must be an ISO date string (YYYY-MM-DD)'),
59
+ /**
60
+ * List of measurable outcomes that define success for this goal.
61
+ * Defaults to empty array so goals can be declared before outcomes are defined.
62
+ */
63
+ keyResults: z.array(KeyResultSchema).default([])
64
+ })
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Goals domain schema — a collection of goals the organization is pursuing.
68
+ // ---------------------------------------------------------------------------
69
+
70
+ export const GoalsDomainSchema = z.object({
71
+ objectives: z.array(ObjectiveSchema).default([])
72
+ })
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Seed — empty by default; adapters populate with real goal definitions.
76
+ // ---------------------------------------------------------------------------
77
+
78
+ export const DEFAULT_ORGANIZATION_MODEL_GOALS: z.infer<typeof GoalsDomainSchema> = {
79
+ objectives: []
80
+ }
@@ -0,0 +1,87 @@
1
+ import { z } from 'zod'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Business hours — simplest shape that captures weekday ranges.
5
+ // Each day of the week is optional; when present it holds open/close times
6
+ // in "HH:MM" 24-hour format. An empty object (default) means "not configured".
7
+ // ---------------------------------------------------------------------------
8
+
9
+ export const BusinessHoursDaySchema = z.object({
10
+ open: z
11
+ .string()
12
+ .trim()
13
+ .regex(/^\d{2}:\d{2}$/, 'Expected HH:MM format'),
14
+ close: z
15
+ .string()
16
+ .trim()
17
+ .regex(/^\d{2}:\d{2}$/, 'Expected HH:MM format')
18
+ })
19
+
20
+ export const BusinessHoursSchema = z
21
+ .object({
22
+ monday: BusinessHoursDaySchema.optional(),
23
+ tuesday: BusinessHoursDaySchema.optional(),
24
+ wednesday: BusinessHoursDaySchema.optional(),
25
+ thursday: BusinessHoursDaySchema.optional(),
26
+ friday: BusinessHoursDaySchema.optional(),
27
+ saturday: BusinessHoursDaySchema.optional(),
28
+ sunday: BusinessHoursDaySchema.optional()
29
+ })
30
+ .default({})
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Identity domain schema — legal identity, mission/vision, industry anchors,
34
+ // and temporal/geographic context. Distinct from branding (display identity).
35
+ // ---------------------------------------------------------------------------
36
+
37
+ export const IdentityDomainSchema = z.object({
38
+ /** Why the organization exists — one or two plain-language sentences. */
39
+ mission: z.string().trim().max(1000).default(''),
40
+ /** Long-term direction the organization is moving toward. */
41
+ vision: z.string().trim().max(1000).default(''),
42
+ /** Legal registered name of the entity. */
43
+ legalName: z.string().trim().max(200).default(''),
44
+ /**
45
+ * Type of legal entity (e.g. "LLC", "Corporation", "Sole Proprietor",
46
+ * "Non-profit"). Free-form string so it covers any jurisdiction.
47
+ */
48
+ entityType: z.string().trim().max(100).default(''),
49
+ /**
50
+ * Primary jurisdiction of registration or operation
51
+ * (e.g. "United States – Delaware", "Canada – Ontario").
52
+ */
53
+ jurisdiction: z.string().trim().max(200).default(''),
54
+ /**
55
+ * Industry category — broad classification (e.g. "Marketing Agency",
56
+ * "Software / SaaS", "Professional Services").
57
+ */
58
+ industryCategory: z.string().trim().max(200).default(''),
59
+ /**
60
+ * Geographic focus — where the organization primarily operates or serves
61
+ * (e.g. "North America", "Global", "Southeast Asia").
62
+ */
63
+ geographicFocus: z.string().trim().max(200).default(''),
64
+ /**
65
+ * IANA timezone identifier for the organization's primary operating timezone
66
+ * (e.g. "America/Los_Angeles", "Europe/London", "UTC").
67
+ */
68
+ timeZone: z.string().trim().max(100).default('UTC'),
69
+ /** Typical operating hours per day of week. Empty object means not configured. */
70
+ businessHours: BusinessHoursSchema
71
+ })
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Seed — placeholder defaults; external adapters override per organization.
75
+ // ---------------------------------------------------------------------------
76
+
77
+ export const DEFAULT_ORGANIZATION_MODEL_IDENTITY: z.infer<typeof IdentityDomainSchema> = {
78
+ mission: '',
79
+ vision: '',
80
+ legalName: '',
81
+ entityType: '',
82
+ jurisdiction: '',
83
+ industryCategory: '',
84
+ geographicFocus: '',
85
+ timeZone: 'UTC',
86
+ businessHours: {}
87
+ }
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod'
2
- import { DELIVERY_PROJECTS_VIEW_CAPABILITY_ID, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID } from '../contracts'
2
+ import { PROJECTS_VIEW_CAPABILITY_ID, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID } from '../contracts'
3
3
  import { DescriptionSchema, IconNameSchema, LabelSchema, ModelIdSchema, PathSchema, ReferenceIdsSchema } from './shared'
4
4
 
5
5
  export const SurfaceTypeSchema = z.enum(['page', 'dashboard', 'graph', 'detail', 'list', 'settings'])
@@ -20,10 +20,23 @@ export const SurfaceDefinitionSchema = z.object({
20
20
  parentId: ModelIdSchema.optional()
21
21
  })
22
22
 
23
+ /**
24
+ * Core placement values: 'primary' | 'secondary' | 'bottom'.
25
+ *
26
+ * `placement` is intentionally open (`z.string()`) so that per-project adapters can
27
+ * introduce additional placement IDs (e.g. 'pinned', 'spotlight', 'contextual') without
28
+ * forking core. Extension pattern: add the new string literal to the project's
29
+ * `foundations/config/organization-model.ts` adapter — no changes to this file required.
30
+ *
31
+ * `surfaceType` and `resourceType` remain closed enums (UI/runtime invariants).
32
+ */
33
+ export const CORE_PLACEMENT_VALUES = ['primary', 'secondary', 'bottom'] as const
34
+ export type CorePlacement = (typeof CORE_PLACEMENT_VALUES)[number]
35
+
23
36
  export const NavigationGroupSchema = z.object({
24
37
  id: ModelIdSchema,
25
38
  label: LabelSchema,
26
- placement: z.enum(['primary', 'secondary', 'bottom']),
39
+ placement: z.string().trim().min(1).max(50),
27
40
  surfaceIds: z.array(ModelIdSchema).default([])
28
41
  })
29
42
 
@@ -70,7 +83,7 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
70
83
  featureIds: [PROJECTS_FEATURE_ID],
71
84
  entityIds: ['delivery.project'],
72
85
  resourceIds: [],
73
- capabilityIds: [DELIVERY_PROJECTS_VIEW_CAPABILITY_ID]
86
+ capabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
74
87
  },
75
88
  {
76
89
  id: 'operations.organization-graph',
@@ -216,6 +229,30 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
216
229
  resourceIds: [],
217
230
  capabilityIds: []
218
231
  },
232
+ {
233
+ id: 'submitted-requests.list',
234
+ label: 'Submitted Requests',
235
+ path: '/monitoring/requests',
236
+ surfaceType: 'list',
237
+ enabled: true,
238
+ featureId: 'submitted-requests',
239
+ featureIds: ['submitted-requests'],
240
+ entityIds: ['reported_request'],
241
+ resourceIds: [],
242
+ capabilityIds: []
243
+ },
244
+ {
245
+ id: 'submitted-requests.detail',
246
+ label: 'Request Detail',
247
+ path: '/monitoring/requests/:requestId',
248
+ surfaceType: 'detail',
249
+ enabled: true,
250
+ featureId: 'submitted-requests',
251
+ featureIds: ['submitted-requests'],
252
+ entityIds: ['reported_request'],
253
+ resourceIds: [],
254
+ capabilityIds: []
255
+ },
219
256
  {
220
257
  id: 'settings.account',
221
258
  label: 'Account',
@@ -331,7 +368,9 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
331
368
  'monitoring.execution-logs',
332
369
  'monitoring.execution-health',
333
370
  'monitoring.cost-analytics',
334
- 'monitoring.notifications'
371
+ 'monitoring.notifications',
372
+ 'submitted-requests.list',
373
+ 'submitted-requests.detail'
335
374
  ]
336
375
  },
337
376
  {
@@ -0,0 +1,66 @@
1
+ import { z } from 'zod'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Pricing model — the four canonical pricing structures used in B2B SaaS and
5
+ // professional services. "custom" covers bespoke / negotiated pricing.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ export const PricingModelSchema = z.enum(['one-time', 'subscription', 'usage-based', 'custom'])
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Product schema — one entry per distinct offering (product or service).
12
+ // Modeled after Business Model Canvas "Value Propositions" and company profile
13
+ // product/service catalog language. Fields use plain English throughout.
14
+ // ---------------------------------------------------------------------------
15
+
16
+ export const ProductSchema = z.object({
17
+ /** Stable unique identifier for the product (e.g. "product-starter-plan"). */
18
+ id: z.string().trim().min(1).max(100),
19
+ /** Human-readable name shown to agents and in UI (e.g. "Starter Plan"). */
20
+ name: z.string().trim().max(200).default(''),
21
+ /** One or two sentences describing what this product/service delivers. */
22
+ description: z.string().trim().max(2000).default(''),
23
+ /**
24
+ * How this product is priced:
25
+ * - "one-time" — single purchase (setup fee, project fee)
26
+ * - "subscription" — recurring (monthly/annual SaaS, retainer)
27
+ * - "usage-based" — metered by consumption (API calls, seats)
28
+ * - "custom" — negotiated or bespoke pricing
29
+ */
30
+ pricingModel: PricingModelSchema.default('custom'),
31
+ /** Base price amount (≥ 0). Currency unit defined by `currency`. */
32
+ price: z.number().min(0).default(0),
33
+ /**
34
+ * ISO 4217 currency code (e.g. "USD", "EUR", "GBP").
35
+ * Free-form string to accommodate any currency; defaults to "USD".
36
+ */
37
+ currency: z.string().trim().max(10).default('USD'),
38
+ /**
39
+ * IDs of customer segments this product targets.
40
+ * Each id must reference a declared `customers.segments[].id`.
41
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
42
+ */
43
+ targetSegmentIds: z.array(z.string().trim().min(1)).default([]),
44
+ /**
45
+ * Optional: ID of the platform feature responsible for delivering this product.
46
+ * When present, must reference a declared `features[].id`.
47
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
48
+ */
49
+ deliveryFeatureId: z.string().trim().min(1).optional()
50
+ })
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Offerings domain schema — a collection of products and services.
54
+ // ---------------------------------------------------------------------------
55
+
56
+ export const OfferingsDomainSchema = z.object({
57
+ products: z.array(ProductSchema).default([])
58
+ })
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Seed — empty by default; adapters populate with real product definitions.
62
+ // ---------------------------------------------------------------------------
63
+
64
+ export const DEFAULT_ORGANIZATION_MODEL_OFFERINGS: z.infer<typeof OfferingsDomainSchema> = {
65
+ products: []
66
+ }
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Semantic class enum — one value per stateful runtime entity category.
5
+ // Every operation entry declares which category it belongs to via semanticClass.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ export const OperationSemanticClassSchema = z.enum(['queue', 'executions', 'sessions', 'notifications', 'schedules'])
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Operation entry schema
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export const OperationEntrySchema = z.object({
15
+ id: z.string().trim().min(1).max(100),
16
+ label: z.string().trim().min(1).max(120),
17
+ semanticClass: OperationSemanticClassSchema,
18
+ /** Optional reference to the feature that owns this runtime entity. */
19
+ featureId: z.string().trim().min(1).max(100).optional(),
20
+ /**
21
+ * Optional pointer to the status semanticClass values that apply to this
22
+ * entity — ties operations back to the statuses domain for vibe rendering.
23
+ */
24
+ supportedStatusSemanticClass: z.array(z.string().trim().min(1).max(80)).optional()
25
+ })
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Domain schema — a flat array of operation entries
29
+ // ---------------------------------------------------------------------------
30
+
31
+ export const OperationsDomainSchema = z.object({
32
+ entries: z.array(OperationEntrySchema).default([])
33
+ })
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Seed — one entry per stateful runtime entity category.
37
+ // Categories: queue (HITL), executions, sessions, notifications, schedules.
38
+ // ---------------------------------------------------------------------------
39
+
40
+ export const DEFAULT_ORGANIZATION_MODEL_OPERATIONS: z.infer<typeof OperationsDomainSchema> = {
41
+ entries: [
42
+ // --- queue (HITL command queue) ---
43
+ {
44
+ id: 'operations.queue',
45
+ label: 'HITL Queue',
46
+ semanticClass: 'queue',
47
+ featureId: 'operations',
48
+ supportedStatusSemanticClass: ['queue']
49
+ },
50
+
51
+ // --- executions (workflow / agent executions) ---
52
+ {
53
+ id: 'operations.executions',
54
+ label: 'Executions',
55
+ semanticClass: 'executions',
56
+ featureId: 'operations',
57
+ supportedStatusSemanticClass: ['execution']
58
+ },
59
+
60
+ // --- sessions (agent conversation sessions) ---
61
+ {
62
+ id: 'operations.sessions',
63
+ label: 'Sessions',
64
+ semanticClass: 'sessions',
65
+ featureId: 'operations'
66
+ },
67
+
68
+ // --- notifications (platform in-app notifications) ---
69
+ {
70
+ id: 'operations.notifications',
71
+ label: 'Notifications',
72
+ semanticClass: 'notifications',
73
+ featureId: 'monitoring'
74
+ },
75
+
76
+ // --- schedules (task scheduler) ---
77
+ {
78
+ id: 'operations.schedules',
79
+ label: 'Schedules',
80
+ semanticClass: 'schedules',
81
+ featureId: 'operations',
82
+ supportedStatusSemanticClass: ['schedule', 'schedule.run']
83
+ }
84
+ ]
85
+ }
@@ -1,21 +1,21 @@
1
1
  import { z } from 'zod'
2
2
  import { DisplayMetadataSchema, ModelIdSchema } from './shared'
3
3
 
4
- export const DeliveryStateSchema = DisplayMetadataSchema.extend({
4
+ export const ProjectsDomainStateSchema = DisplayMetadataSchema.extend({
5
5
  id: ModelIdSchema,
6
6
  order: z.number().int().min(0)
7
7
  })
8
8
 
9
- export const OrganizationModelDeliverySchema = z.object({
9
+ export const OrganizationModelProjectsSchema = z.object({
10
10
  projectEntityId: ModelIdSchema,
11
11
  milestoneEntityId: ModelIdSchema,
12
12
  taskEntityId: ModelIdSchema,
13
- projectStatuses: z.array(DeliveryStateSchema).min(1),
14
- milestoneStatuses: z.array(DeliveryStateSchema).min(1),
15
- taskStatuses: z.array(DeliveryStateSchema).min(1)
13
+ projectStatuses: z.array(ProjectsDomainStateSchema).min(1),
14
+ milestoneStatuses: z.array(ProjectsDomainStateSchema).min(1),
15
+ taskStatuses: z.array(ProjectsDomainStateSchema).min(1)
16
16
  })
17
17
 
18
- export const DEFAULT_ORGANIZATION_MODEL_DELIVERY: z.infer<typeof OrganizationModelDeliverySchema> = {
18
+ export const DEFAULT_ORGANIZATION_MODEL_PROJECTS: z.infer<typeof OrganizationModelProjectsSchema> = {
19
19
  projectEntityId: 'delivery.project',
20
20
  milestoneEntityId: 'delivery.milestone',
21
21
  taskEntityId: 'delivery.task',
@@ -1,21 +1,21 @@
1
1
  import { z } from 'zod'
2
2
  import { DescriptionSchema, DisplayMetadataSchema, ModelIdSchema } from './shared'
3
3
 
4
- export const LeadGenLifecycleStageSchema = DisplayMetadataSchema.extend({
4
+ export const ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
5
5
  id: ModelIdSchema,
6
6
  order: z.number().int().min(0)
7
7
  })
8
8
 
9
- export const OrganizationModelLeadGenSchema = z.object({
9
+ export const OrganizationModelProspectingSchema = z.object({
10
10
  listEntityId: ModelIdSchema,
11
11
  companyEntityId: ModelIdSchema,
12
12
  contactEntityId: ModelIdSchema,
13
13
  description: DescriptionSchema.optional(),
14
- companyStages: z.array(LeadGenLifecycleStageSchema).min(1),
15
- contactStages: z.array(LeadGenLifecycleStageSchema).min(1)
14
+ companyStages: z.array(ProspectingLifecycleStageSchema).min(1),
15
+ contactStages: z.array(ProspectingLifecycleStageSchema).min(1)
16
16
  })
17
17
 
18
- export const DEFAULT_ORGANIZATION_MODEL_LEAD_GEN: z.infer<typeof OrganizationModelLeadGenSchema> = {
18
+ export const DEFAULT_ORGANIZATION_MODEL_PROSPECTING: z.infer<typeof OrganizationModelProspectingSchema> = {
19
19
  listEntityId: 'leadgen.list',
20
20
  companyEntityId: 'leadgen.company',
21
21
  contactEntityId: 'leadgen.contact',
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Role schema — one entry per distinct role in the organization's chart.
5
+ // Inspired by the EOS Accountability Chart but uses plain-language field names
6
+ // throughout. No EOS jargon: "title" (not seatTitle), "responsibilities"
7
+ // (not accountabilities), "reportsToId", "heldBy".
8
+ //
9
+ // Cross-reference: `reportsToId` (when present) must resolve to another
10
+ // `roles[].id` in the same collection. Enforcement is via
11
+ // `OrganizationModelSchema.superRefine()` — not at the individual schema level.
12
+ // Cycle detection is NOT enforced (known limitation; document if needed).
13
+ // ---------------------------------------------------------------------------
14
+
15
+ export const RoleSchema = z.object({
16
+ /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
17
+ id: z.string().trim().min(1).max(100),
18
+ /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
19
+ title: z.string().trim().min(1).max(200),
20
+ /**
21
+ * List of responsibilities this role owns — plain-language descriptions of
22
+ * what the person in this role is accountable for delivering.
23
+ * Defaults to empty array so minimal role definitions stay concise.
24
+ */
25
+ responsibilities: z.array(z.string().trim().max(500)).default([]),
26
+ /**
27
+ * Optional: ID of another role this role reports to.
28
+ * When present, must reference another `roles[].id` in the same organization.
29
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
30
+ * Absence indicates a top-level role (no reporting line).
31
+ */
32
+ reportsToId: z.string().trim().min(1).max(100).optional(),
33
+ /**
34
+ * Optional: name or email of the person currently holding this role.
35
+ * Free-form string — supports "Alice Johnson", "alice@example.com", or
36
+ * any human-readable identifier. Not validated against any user registry.
37
+ */
38
+ heldBy: z.string().trim().max(200).optional()
39
+ })
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Roles domain schema — a collection of roles.
43
+ // ---------------------------------------------------------------------------
44
+
45
+ export const RolesDomainSchema = z.object({
46
+ roles: z.array(RoleSchema).default([])
47
+ })
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Seed — empty by default; adapters populate with real role definitions.
51
+ // ---------------------------------------------------------------------------
52
+
53
+ export const DEFAULT_ORGANIZATION_MODEL_ROLES: z.infer<typeof RolesDomainSchema> = {
54
+ roles: []
55
+ }
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod'
2
+ import { DescriptionSchema, DisplayMetadataSchema, ModelIdSchema, ReferenceIdsSchema } from './shared'
3
+
4
+ export const SalesStageSemanticClassSchema = z.enum(['open', 'active', 'nurturing', 'closed_won', 'closed_lost'])
5
+
6
+ export const SalesStageSchema = DisplayMetadataSchema.extend({
7
+ id: ModelIdSchema,
8
+ order: z.number().int().min(0),
9
+ semanticClass: SalesStageSemanticClassSchema,
10
+ surfaceIds: ReferenceIdsSchema,
11
+ resourceIds: ReferenceIdsSchema
12
+ })
13
+
14
+ export const SalesPipelineSchema = z.object({
15
+ id: ModelIdSchema,
16
+ label: z.string().trim().min(1).max(120),
17
+ description: DescriptionSchema.optional(),
18
+ entityId: ModelIdSchema,
19
+ stages: z.array(SalesStageSchema).min(1)
20
+ })
21
+
22
+ export const OrganizationModelSalesSchema = z.object({
23
+ entityId: ModelIdSchema,
24
+ defaultPipelineId: ModelIdSchema,
25
+ pipelines: z.array(SalesPipelineSchema).min(1)
26
+ })
27
+
28
+ export const DEFAULT_ORGANIZATION_MODEL_SALES: z.infer<typeof OrganizationModelSalesSchema> = {
29
+ entityId: 'crm.deal',
30
+ defaultPipelineId: 'default',
31
+ pipelines: [
32
+ {
33
+ id: 'default',
34
+ label: 'Default Pipeline',
35
+ entityId: 'crm.deal',
36
+ stages: [
37
+ {
38
+ id: 'interested',
39
+ label: 'Interested',
40
+ color: 'blue',
41
+ order: 1,
42
+ semanticClass: 'open',
43
+ surfaceIds: ['crm.pipeline'],
44
+ resourceIds: []
45
+ },
46
+ {
47
+ id: 'proposal',
48
+ label: 'Proposal',
49
+ color: 'yellow',
50
+ order: 2,
51
+ semanticClass: 'active',
52
+ surfaceIds: ['crm.pipeline'],
53
+ resourceIds: []
54
+ },
55
+ {
56
+ id: 'closing',
57
+ label: 'Closing',
58
+ color: 'lime',
59
+ order: 3,
60
+ semanticClass: 'active',
61
+ surfaceIds: ['crm.pipeline'],
62
+ resourceIds: []
63
+ },
64
+ {
65
+ id: 'closed_won',
66
+ label: 'Closed Won',
67
+ color: 'green',
68
+ order: 4,
69
+ semanticClass: 'closed_won',
70
+ surfaceIds: ['crm.pipeline'],
71
+ resourceIds: []
72
+ },
73
+ {
74
+ id: 'closed_lost',
75
+ label: 'Closed Lost',
76
+ color: 'red',
77
+ order: 5,
78
+ semanticClass: 'closed_lost',
79
+ surfaceIds: ['crm.pipeline'],
80
+ resourceIds: []
81
+ },
82
+ {
83
+ id: 'nurturing',
84
+ label: 'Nurturing',
85
+ color: 'grape',
86
+ order: 6,
87
+ semanticClass: 'nurturing',
88
+ surfaceIds: ['crm.pipeline'],
89
+ resourceIds: []
90
+ }
91
+ ]
92
+ }
93
+ ]
94
+ }
@@ -22,6 +22,33 @@ export const DisplayMetadataSchema = z.object({
22
22
  icon: IconNameSchema.optional()
23
23
  })
24
24
 
25
+ // ---------------------------------------------------------------------------
26
+ // TechStack subsection — optional extension on a ResourceMapping entry that
27
+ // captures external-SaaS integration metadata: which platform, its purpose,
28
+ // credential health, and whether it is the system of record for its domain.
29
+ // Backward-compatible: existing entries without this key parse cleanly.
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export const TechStackEntrySchema = z.object({
33
+ /** Name of the external platform (e.g. "HubSpot", "Stripe", "Notion"). */
34
+ platform: z.string().trim().min(1).max(200),
35
+ /** Free-form description of what this integration is used for. */
36
+ purpose: z.string().trim().min(1).max(500),
37
+ /**
38
+ * Health of the credential backing this integration.
39
+ * - configured: credential present and valid
40
+ * - pending: not yet set up
41
+ * - expired: credential existed but has lapsed
42
+ * - missing: expected but not present
43
+ */
44
+ credentialStatus: z.enum(['configured', 'pending', 'expired', 'missing']),
45
+ /**
46
+ * Whether this integration is the primary system of record for its domain
47
+ * (e.g. HubSpot is SoR for contacts). Defaults to false.
48
+ */
49
+ isSystemOfRecord: z.boolean().default(false)
50
+ })
51
+
25
52
  export const ResourceMappingSchema = DisplayMetadataSchema.extend({
26
53
  id: ModelIdSchema,
27
54
  resourceId: z.string().trim().min(1).max(255),
@@ -29,5 +56,7 @@ export const ResourceMappingSchema = DisplayMetadataSchema.extend({
29
56
  featureIds: ReferenceIdsSchema,
30
57
  entityIds: ReferenceIdsSchema,
31
58
  surfaceIds: ReferenceIdsSchema,
32
- capabilityIds: ReferenceIdsSchema
59
+ capabilityIds: ReferenceIdsSchema,
60
+ /** Optional tech-stack metadata for external-SaaS integrations. */
61
+ techStack: TechStackEntrySchema.optional()
33
62
  })