@elevasis/sdk 1.24.0 → 1.26.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 (66) hide show
  1. package/dist/cli.cjs +875 -834
  2. package/dist/index.d.ts +4857 -4547
  3. package/dist/index.js +564 -2338
  4. package/dist/node/index.d.ts +693 -1356
  5. package/dist/node/index.js +1 -1
  6. package/dist/test-utils/index.d.ts +4186 -4139
  7. package/dist/test-utils/index.js +694 -2769
  8. package/dist/types/worker/adapters/clickup.d.ts +22 -0
  9. package/dist/types/worker/adapters/index.d.ts +1 -0
  10. package/dist/types/worker/index.d.ts +3 -2
  11. package/dist/types/worker/platform.d.ts +2 -2
  12. package/dist/worker/index.js +427 -2803
  13. package/package.json +2 -2
  14. package/reference/_navigation.md +11 -1
  15. package/reference/_reference-manifest.json +70 -0
  16. package/reference/claude-config/rules/organization-model.md +12 -1
  17. package/reference/claude-config/rules/organization-os.md +12 -1
  18. package/reference/claude-config/skills/om/SKILL.md +13 -5
  19. package/reference/claude-config/skills/om/operations/codify-level-a.md +109 -100
  20. package/reference/claude-config/skills/om/operations/customers.md +10 -6
  21. package/reference/claude-config/skills/om/operations/features.md +7 -3
  22. package/reference/claude-config/skills/om/operations/goals.md +10 -6
  23. package/reference/claude-config/skills/om/operations/identity.md +8 -5
  24. package/reference/claude-config/skills/om/operations/labels.md +17 -1
  25. package/reference/claude-config/skills/om/operations/offerings.md +11 -7
  26. package/reference/claude-config/skills/om/operations/roles.md +11 -7
  27. package/reference/claude-config/skills/om/operations/techStack.md +10 -2
  28. package/reference/claude-config/sync-notes/2026-05-20-om-define-helpers.md +32 -0
  29. package/reference/claude-config/sync-notes/2026-05-22-access-model-and-right-panel.md +43 -0
  30. package/reference/claude-config/sync-notes/2026-05-22-lead-gen-tenant-config.md +40 -0
  31. package/reference/claude-config/sync-notes/2026-05-22-org-model-multi-file-split.md +61 -0
  32. package/reference/cli-management.mdx +539 -0
  33. package/reference/cli.mdx +579 -808
  34. package/reference/concepts.mdx +134 -146
  35. package/reference/deployment/api.mdx +296 -297
  36. package/reference/deployment/command-center.mdx +208 -209
  37. package/reference/deployment/index.mdx +194 -195
  38. package/reference/deployment/provided-features.mdx +110 -107
  39. package/reference/deployment/ui-execution.mdx +249 -250
  40. package/reference/framework/index.mdx +111 -195
  41. package/reference/framework/resource-documentation.mdx +90 -0
  42. package/reference/framework/tutorial-system.mdx +135 -135
  43. package/reference/getting-started.mdx +141 -142
  44. package/reference/index.mdx +95 -106
  45. package/reference/packages/ui/src/auth/README.md +6 -6
  46. package/reference/platform-tools/adapters-integration.mdx +300 -301
  47. package/reference/platform-tools/adapters-platform.mdx +552 -553
  48. package/reference/platform-tools/index.mdx +216 -217
  49. package/reference/platform-tools/type-safety.mdx +82 -82
  50. package/reference/resources/index.mdx +348 -349
  51. package/reference/resources/patterns.mdx +446 -449
  52. package/reference/resources/types.mdx +115 -116
  53. package/reference/roadmap.mdx +164 -165
  54. package/reference/rules/organization-model.md +14 -0
  55. package/reference/runtime.mdx +172 -173
  56. package/reference/scaffold/operations/propagation-pipeline.md +1 -1
  57. package/reference/scaffold/recipes/customize-crm-actions.md +45 -46
  58. package/reference/scaffold/recipes/extend-crm.md +253 -255
  59. package/reference/scaffold/recipes/extend-lead-gen.md +130 -77
  60. package/reference/scaffold/recipes/index.md +43 -44
  61. package/reference/scaffold/reference/contracts.md +1275 -1432
  62. package/reference/scaffold/reference/glossary.md +8 -6
  63. package/reference/scaffold/ui/feature-flags-and-gating.md +59 -46
  64. package/reference/scaffold/ui/feature-shell.mdx +11 -11
  65. package/reference/scaffold/ui/recipes.md +24 -24
  66. package/reference/troubleshooting.mdx +222 -223
@@ -1,258 +1,256 @@
1
1
  <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
2
2
  <!-- Regenerate: pnpm scaffold:sync -->
3
3
 
4
- ---
5
- title: Build and Extend CRM
6
- description: Map the CRM platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, action definitions, workflow adapters, contracts, and org-model extension boundaries.
7
- ---
8
-
9
- # Build and Extend CRM
10
-
11
- Use this recipe when a downstream project wants to build on the shared CRM instead of forking it.
12
-
13
- Good trigger phrases:
14
-
15
- - "Add a CRM reports page."
16
- - "Build a custom deal workspace."
17
- - "Read and update deals from a workflow."
18
- - "Add a Send Quote button."
19
- - "Change the CRM pipeline stages for this business."
20
-
21
- CRM is a layered platform surface, not one component:
22
-
23
- - **Organization OS:** System access, sales pipeline semantics, quick access, and labels live in the organization model.
24
- - **Shared UI:** CRM pages, sidebars, workbench panels, overview widgets, and Kanban/detail components live in `@elevasis/ui`.
25
- - **Headless hooks:** deal, company, contact, note, task, list, transition, and action hooks live under `@elevasis/ui/hooks`.
26
- - **Action system:** `ActionDef`, `DEFAULT_CRM_ACTIONS`, `deriveActions`, and provider-level `crmActions` configure deal actions.
27
- - **Workflow adapters:** `crm` and `acqDb` from `@elevasis/sdk/worker` let workflows read and mutate CRM/acquisition data through platform tools.
28
- - **Contracts:** generated contract docs expose the current CRM shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
29
-
30
- ## Decision Table
31
-
32
- | User wants | Start here | Notes |
33
- | --- | --- | --- |
34
- | Change CRM System availability, labels, pipeline stages, or resource descriptors | `core/config/organization-model.ts` | Treat this as Organization OS work. Use the project's configure ceremony if available. |
35
- | Add CRM sidebar nav or a CRM route | `@elevasis/ui/features/crm` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
36
- | Wrap a shared CRM page with project chrome | `DealsListPage`, `DealDetailPage`, `CrmOverview` from `@elevasis/ui/features/crm` | Keep route files thin and put project-specific logic in local feature modules. |
37
- | Build a custom deal page | `useDealDetail`, `useDealNotes`, `useDealTasks`, `useExecuteAction` from `@elevasis/ui/hooks` | Use hooks for platform data and compose your own UI. |
38
- | Add, hide, or replace deal action buttons | [customize-crm-actions.md](customize-crm-actions.md) | Start with the shared `crmActions` provider path; use project-owned UI when a custom workflow path is outside platform-known/default action dispatch constraints. |
39
- | Read or mutate CRM data inside a workflow | `crm` or `acqDb` from `@elevasis/sdk/worker` | `organizationId` is injected server-side by the platform dispatcher. Do not pass it from workflow code. |
40
- | Add a new persisted CRM column or table | Platform/API migration work, not just scaffold work | Update DB, core schemas/types, API service/handlers, hooks, docs, and scaffold contracts together. |
41
-
42
- ## Published CRM Surfaces
43
-
44
- | Surface | Import from | Use for |
45
- | --- | --- | --- |
46
- | `crmManifest`, `CRM_ITEMS`, `CrmSidebar`, `CrmSidebarTop`, `CrmSidebarMiddle` | `@elevasis/ui/features/crm` | Feature registration and sidebar composition |
47
- | `CrmOverview`, `DealsListPage`, `DealDetailPage`, `CompanyDetailPage` | `@elevasis/ui/features/crm` | Shared CRM pages you can route to or wrap |
48
- | `MyTasksPanel`, `SavedViewsPanel`, `QuickCreateActions` | `@elevasis/ui/features/crm` | Workbench/sidebar panels for custom CRM sidebars |
49
- | `PipelineFunnelWidget`, `ActivityFeedWidget`, `MetricsStrip` | `@elevasis/ui/features/crm` | Overview widgets for custom dashboards |
50
- | `KanbanBoard`, `DealKanbanCard`, `DealDrawer` | `@elevasis/ui/components` | Lower-level CRM deal UI primitives |
51
- | `useDeals`, `useDealDetail`, `useTransitionItem`, `useExecuteAction`, `useDealNotes`, `useDealTasks` | `@elevasis/ui/hooks` | Headless deal and task data access |
52
- | `useCompanies`, `useContacts`, `useLists`, `useBatchTelemetry` | `@elevasis/ui/hooks` | Acquisition substrate data access |
53
- | `ElevasisUIProvider`, `ElevasisCoreProvider`, `useElevasisServices` | `@elevasis/ui/provider` | Provider setup, API access, and organization context |
54
- | `ActionDef`, `DEFAULT_CRM_ACTIONS`, `deriveActions` | `@elevasis/sdk` | Deal action configuration and render-time derivation |
55
- | `crm`, `acqDb` | `@elevasis/sdk/worker` | Workflow-side CRM/acquisition platform adapters |
56
-
57
- Read the generated contracts before changing typed boundaries:
58
-
59
- `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`
60
-
61
- Look for the **CRM Platform Primitives** section. It includes deal stages, deal rows, task shapes, API schemas, action definitions, and the focused CRM workflow adapter map. The broader acquisition/list adapter maps live under **Lead Gen Platform Primitives**.
62
-
63
- Deal list and detail responses include a server-derived `priority` object. Use `deal.priority.bucketKey`, `rank`, `label`, `reason`, `latestActivityAt`, and `nextActionAt` when composing custom deal workspaces or workflow-side follow-up logic instead of re-deriving priority from `updated_at`.
64
-
65
- ## 1. Extend CRM Navigation or Sidebar
66
-
67
- For a simple nav addition, extend `CRM_ITEMS` and override the CRM system manifest:
68
-
69
- ```tsx
70
- // ui/src/routes/__root.tsx
71
- import { crmManifest, CRM_ITEMS, CrmSidebar, CrmSidebarMiddle } from '@elevasis/ui/features/crm'
72
- import type { SystemModule } from '@elevasis/ui/provider'
73
- import type { NavItem } from '@elevasis/ui/layout'
74
- import { IconFileText } from '@tabler/icons-react'
75
-
76
- const customCrmItems: NavItem[] = [
77
- ...CRM_ITEMS,
78
- { label: 'Reports', to: '/crm/reports', icon: IconFileText, exact: false }
79
- ]
80
-
81
- const CustomCrmSidebar = () => (
82
- <CrmSidebar>
83
- <CrmSidebarMiddle items={customCrmItems} />
84
- </CrmSidebar>
85
- )
86
-
87
- export const customCrmManifest: SystemModule = {
88
- ...crmManifest,
89
- sidebar: CustomCrmSidebar
90
- }
91
- ```
92
-
93
- Then replace `crmManifest` with `customCrmManifest` in the local `SYSTEM_MANIFESTS` array and add the matching route under `ui/src/routes/crm/`.
94
-
95
- For structural changes, compose `CrmSidebarTop`, `SubshellNavList`, `SubshellSidebarSection`, `MyTasksPanel`, and `QuickCreateActions`. The full sidebar decision tree lives in `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
96
-
97
- ## 2. Wrap Shared CRM Pages
98
-
99
- If the shared page is close, keep it and wrap it:
100
-
101
- ```tsx
102
- // ui/src/routes/crm/deals.index.tsx
103
- import { createFileRoute } from '@tanstack/react-router'
104
- import { DealsListPage } from '@elevasis/ui/features/crm'
105
- import { Stack } from '@mantine/core'
106
- import { ProjectAnnouncementBanner } from '@/lib/components/ProjectAnnouncementBanner'
107
-
108
- export const Route = createFileRoute('/crm/deals/')({
109
- component: DealsRoute
110
- })
111
-
112
- function DealsRoute() {
113
- return (
114
- <Stack gap={0}>
115
- <ProjectAnnouncementBanner context="crm-deals" />
116
- <DealsListPage />
117
- </Stack>
118
- )
119
- }
120
- ```
121
-
122
- Use the same pattern for `CrmOverview`, `DealDetailPage`, and `CompanyDetailPage`.
123
-
124
- ## 3. Build a Custom Deal Page
125
-
126
- When the project needs custom layout or additional workflows, use the hooks directly:
127
-
128
- ```tsx
129
- import { Button, Group, Stack, Textarea } from '@mantine/core'
130
- import { useState } from 'react'
131
- import { useDealDetail, useDealNotes, useCreateDealNote, useExecuteAction } from '@elevasis/ui/hooks'
132
-
133
- export function CustomDealWorkspace({ dealId }: { dealId: string }) {
134
- const { data: deal, isLoading } = useDealDetail(dealId)
135
- const { data: notes = [] } = useDealNotes(dealId)
136
- const createNote = useCreateDealNote()
137
- const executeAction = useExecuteAction({ dealId })
138
- const [body, setBody] = useState('')
139
-
140
- if (isLoading) return null
141
- if (!deal) return <div>Deal not found</div>
142
-
143
- return (
144
- <Stack>
145
- <h1>{deal.contact_email}</h1>
146
- <Group>
147
- <Button onClick={() => executeAction.mutate({ key: 'move_to_proposal' })}>
148
- Move to Proposal
149
- </Button>
150
- </Group>
151
- <Textarea value={body} onChange={(event) => setBody(event.currentTarget.value)} />
152
- <Button onClick={() => createNote.mutate({ dealId, body })}>Add Note</Button>
153
- <pre>{JSON.stringify(notes, null, 2)}</pre>
154
- </Stack>
155
- )
156
- }
157
- ```
158
-
159
- `useExecuteAction` is for platform-known/default action keys. Start custom action UI with the shared `crmActions` provider path; when a project-owned workflow is outside that server-dispatched action set, call `/execute` or `/execute-async` through `useElevasisServices`, or follow [customize-crm-actions.md](customize-crm-actions.md).
160
-
161
- ## 4. Read and Mutate CRM Data in Workflows
162
-
163
- Inside deployed workflows, use worker adapters instead of browser hooks or direct database access:
164
-
165
- ```ts
166
- // operations/src/sales/follow-up-stale-deals.ts
167
- import type { WorkflowDefinition } from '@elevasis/sdk'
168
- import { crm } from '@elevasis/sdk/worker'
169
- import { resourceDescriptors } from '@core/config/organization-model'
170
- import { z } from 'zod'
171
-
172
- const inputSchema = z.object({
173
- stage: z.string().default('proposal')
174
- })
175
-
176
- const outputSchema = z.object({
177
- touched: z.number()
178
- })
179
-
180
- export const followUpStaleDealsWorkflow: WorkflowDefinition = {
181
- config: {
182
- resource: resourceDescriptors.followUpStaleDeals,
183
- resourceId: resourceDescriptors.followUpStaleDeals.id,
184
- name: 'Follow Up Stale Deals',
185
- type: resourceDescriptors.followUpStaleDeals.kind,
186
- version: '1.0.0',
187
- status: 'dev',
188
- },
189
- contract: { inputSchema, outputSchema },
190
- steps: {
191
- followUp: {
192
- id: 'followUp',
193
- name: 'Follow Up',
194
- inputSchema,
195
- outputSchema,
196
- next: null,
197
- handler: async (input) => {
198
- const deals = await crm.listDeals({ stage: input.stage })
199
-
200
- for (const deal of deals) {
201
- if (!['follow_up_due', 'stale'].includes(deal.priority.bucketKey)) continue
202
-
203
- await crm.createDealTask({
204
- dealId: deal.id,
205
- title: 'Follow up',
206
- kind: 'email'
207
- })
208
- await crm.recordActivity({
209
- dealId: deal.id,
210
- type: 'workflow.follow_up_task_created',
211
- title: 'Follow-up task created',
212
- payload: { workflow: 'follow-up-stale-deals' }
213
- })
214
- }
215
-
216
- return { touched: deals.length }
217
- }
218
- }
219
- },
220
- entryPoint: 'followUp'
221
- }
222
- ```
223
-
224
- Use `crm` for focused CRM deal reads, notes, tasks, activity, and cleanup. Use `acqDb` when the workflow needs the broader acquisition substrate: companies, contacts, lists, list-stage transitions, enrichment data, social posts, or lower-level deal sync methods.
225
-
226
- ## 5. Customize Pipeline Semantics
227
-
228
- CRM System identity is `sales.crm`, but the organization-model domain is `sales`.
229
-
230
- For stage labels or stage sets, update the project model:
231
-
232
- `core/config/organization-model.ts`
233
-
234
- Keep these boundaries straight:
235
-
236
- - Org-model sales pipelines describe business semantics.
237
- - `DealStage` and platform action defaults describe the current shared platform deal state vocabulary.
238
- - UI wrappers can relabel and route around shared surfaces, but changing persisted platform stages requires coordinated core/API/UI updates.
239
- - Do not add `sales.actions` to the org model in v1. Deal action customization is covered by [customize-crm-actions.md](customize-crm-actions.md).
240
-
241
- ## Verify
242
-
243
- Run the checks for the surfaces you touched:
244
-
245
- ```bash
246
- pnpm -C ui run check
247
- pnpm -C operations run check
248
- pnpm -C operations exec elevasis-sdk check
249
- ```
250
-
251
- If you changed platform-level CRM contracts in the monorepo, the platform maintainer must also regenerate and verify scaffold output:
252
-
253
- ```bash
254
- pnpm scaffold:sync
255
- pnpm scaffold:verify
256
- ```
257
-
258
-
4
+ ---
5
+ title: Build and Extend CRM
6
+ description: Map the CRM platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, action definitions, workflow adapters, contracts, and org-model extension boundaries.
7
+ ---
8
+
9
+ # Build and Extend CRM
10
+
11
+ Use this recipe when a downstream project wants to build on the shared CRM instead of forking it.
12
+
13
+ Good trigger phrases:
14
+
15
+ - "Add a CRM reports page."
16
+ - "Build a custom deal workspace."
17
+ - "Read and update deals from a workflow."
18
+ - "Add a Send Quote button."
19
+ - "Change the CRM pipeline stages for this business."
20
+
21
+ CRM is a layered platform surface, not one component:
22
+
23
+ - **Organization OS:** System access, sales pipeline semantics, quick access, and labels live in the organization model.
24
+ - **Shared UI:** CRM pages, sidebars, workbench panels, overview widgets, and Kanban/detail components live in `@elevasis/ui`.
25
+ - **Headless hooks:** deal, company, contact, note, task, list, transition, and action hooks live under `@elevasis/ui/hooks`.
26
+ - **Action system:** `ActionDef`, `deriveActions`, and the caller-supplied provider-level `crmActions` catalog configure deal actions. The published `@elevasis/sdk` surface ships no default Elevasis action catalog -- projects supply their own `ActionDef[]`.
27
+ - **Workflow adapters:** `crm` and `acqDb` from `@elevasis/sdk/worker` let workflows read and mutate CRM/acquisition data through platform tools.
28
+ - **Contracts:** generated contract docs expose the current CRM shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
29
+
30
+ ## Decision Table
31
+
32
+ | User wants | Start here | Notes |
33
+ | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
+ | Change CRM System availability, labels, pipeline stages, or resource descriptors | `core/config/organization-model.ts` | Treat this as Organization OS work. Use the project's configure ceremony if available. |
35
+ | Add CRM sidebar nav or a CRM route | `@elevasis/ui/features/crm` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
36
+ | Wrap a shared CRM page with project chrome | `DealsListPage`, `DealDetailPage`, `CrmOverview` from `@elevasis/ui/features/crm` | Keep route files thin and put project-specific logic in local feature modules. |
37
+ | Build a custom deal page | `useDealDetail`, `useDealNotes`, `useDealTasks`, `useExecuteAction` from `@elevasis/ui/hooks` | Use hooks for platform data and compose your own UI. |
38
+ | Add, hide, or replace deal action buttons | [customize-crm-actions.md](customize-crm-actions.md) | Start with the shared `crmActions` provider path; use project-owned UI when a custom workflow path is outside platform-known/default action dispatch constraints. |
39
+ | Read or mutate CRM data inside a workflow | `crm` or `acqDb` from `@elevasis/sdk/worker` | `organizationId` is injected server-side by the platform dispatcher. Do not pass it from workflow code. |
40
+ | Add a new persisted CRM column or table | Platform/API migration work, not just scaffold work | Update DB, core schemas/types, API service/handlers, hooks, docs, and scaffold contracts together. |
41
+
42
+ ## Published CRM Surfaces
43
+
44
+ | Surface | Import from | Use for |
45
+ | ---------------------------------------------------------------------------------------------------- | --------------------------- | ---------------------------------------------------- |
46
+ | `crmManifest`, `CRM_ITEMS`, `CrmSidebar`, `CrmSidebarTop`, `CrmSidebarMiddle` | `@elevasis/ui/features/crm` | Feature registration and sidebar composition |
47
+ | `CrmOverview`, `DealsListPage`, `DealDetailPage`, `CompanyDetailPage` | `@elevasis/ui/features/crm` | Shared CRM pages you can route to or wrap |
48
+ | `MyTasksPanel`, `SavedViewsPanel`, `QuickCreateActions` | `@elevasis/ui/features/crm` | Workbench/sidebar panels for custom CRM sidebars |
49
+ | `PipelineFunnelWidget`, `ActivityFeedWidget`, `MetricsStrip` | `@elevasis/ui/features/crm` | Overview widgets for custom dashboards |
50
+ | `KanbanBoard`, `DealKanbanCard`, `DealDrawer` | `@elevasis/ui/components` | Lower-level CRM deal UI primitives |
51
+ | `useDeals`, `useDealDetail`, `useTransitionItem`, `useExecuteAction`, `useDealNotes`, `useDealTasks` | `@elevasis/ui/hooks` | Headless deal and task data access |
52
+ | `useCompanies`, `useContacts`, `useLists`, `useBatchTelemetry` | `@elevasis/ui/hooks` | Acquisition substrate data access |
53
+ | `ElevasisUIProvider`, `ElevasisCoreProvider`, `useElevasisServices` | `@elevasis/ui/provider` | Provider setup, API access, and organization context |
54
+ | `ActionDef`, `deriveActions` | `@elevasis/sdk` | Deal action configuration and render-time derivation |
55
+ | `crm`, `acqDb` | `@elevasis/sdk/worker` | Workflow-side CRM/acquisition platform adapters |
56
+
57
+ Read the generated contracts before changing typed boundaries:
58
+
59
+ `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`
60
+
61
+ Look for the **CRM Platform Primitives** section. It includes deal stages, deal rows, task shapes, API schemas, action definitions, and the focused CRM workflow adapter map. The broader acquisition/list adapter maps live under **Lead Gen Platform Primitives**.
62
+
63
+ Deal list and detail responses include a server-derived `priority` object. Use `deal.priority.bucketKey`, `rank`, `label`, `reason`, `latestActivityAt`, and `nextActionAt` when composing custom deal workspaces or workflow-side follow-up logic instead of re-deriving priority from `updated_at`.
64
+
65
+ ## 1. Extend CRM Navigation or Sidebar
66
+
67
+ For a simple nav addition, extend `CRM_ITEMS` and override the CRM system manifest:
68
+
69
+ ```tsx
70
+ // ui/src/routes/__root.tsx
71
+ import { crmManifest, CRM_ITEMS, CrmSidebar, CrmSidebarMiddle } from '@elevasis/ui/features/crm'
72
+ import type { SystemModule } from '@elevasis/ui/provider'
73
+ import type { NavItem } from '@elevasis/ui/layout'
74
+ import { IconFileText } from '@tabler/icons-react'
75
+
76
+ const customCrmItems: NavItem[] = [
77
+ ...CRM_ITEMS,
78
+ { label: 'Reports', to: '/crm/reports', icon: IconFileText, exact: false }
79
+ ]
80
+
81
+ const CustomCrmSidebar = () => (
82
+ <CrmSidebar>
83
+ <CrmSidebarMiddle items={customCrmItems} />
84
+ </CrmSidebar>
85
+ )
86
+
87
+ export const customCrmManifest: SystemModule = {
88
+ ...crmManifest,
89
+ sidebar: CustomCrmSidebar
90
+ }
91
+ ```
92
+
93
+ Then replace `crmManifest` with `customCrmManifest` in the local `SYSTEM_MANIFESTS` array and add the matching route under `ui/src/routes/crm/`.
94
+
95
+ For structural changes, compose `CrmSidebarTop`, `SubshellNavList`, `SubshellSidebarSection`, `MyTasksPanel`, and `QuickCreateActions`. The full sidebar decision tree lives in `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
96
+
97
+ ## 2. Wrap Shared CRM Pages
98
+
99
+ If the shared page is close, keep it and wrap it:
100
+
101
+ ```tsx
102
+ // ui/src/routes/crm/deals.index.tsx
103
+ import { createFileRoute } from '@tanstack/react-router'
104
+ import { DealsListPage } from '@elevasis/ui/features/crm'
105
+ import { Stack } from '@mantine/core'
106
+ import { ProjectAnnouncementBanner } from '@/lib/components/ProjectAnnouncementBanner'
107
+
108
+ export const Route = createFileRoute('/crm/deals/')({
109
+ component: DealsRoute
110
+ })
111
+
112
+ function DealsRoute() {
113
+ return (
114
+ <Stack gap={0}>
115
+ <ProjectAnnouncementBanner context="crm-deals" />
116
+ <DealsListPage />
117
+ </Stack>
118
+ )
119
+ }
120
+ ```
121
+
122
+ Use the same pattern for `CrmOverview`, `DealDetailPage`, and `CompanyDetailPage`.
123
+
124
+ ## 3. Build a Custom Deal Page
125
+
126
+ When the project needs custom layout or additional workflows, use the hooks directly:
127
+
128
+ ```tsx
129
+ import { Button, Group, Stack, Textarea } from '@mantine/core'
130
+ import { useState } from 'react'
131
+ import { useDealDetail, useDealNotes, useCreateDealNote, useExecuteAction } from '@elevasis/ui/hooks'
132
+
133
+ export function CustomDealWorkspace({ dealId }: { dealId: string }) {
134
+ const { data: deal, isLoading } = useDealDetail(dealId)
135
+ const { data: notes = [] } = useDealNotes(dealId)
136
+ const createNote = useCreateDealNote()
137
+ const executeAction = useExecuteAction({ dealId })
138
+ const [body, setBody] = useState('')
139
+
140
+ if (isLoading) return null
141
+ if (!deal) return <div>Deal not found</div>
142
+
143
+ return (
144
+ <Stack>
145
+ <h1>{deal.contact_email}</h1>
146
+ <Group>
147
+ <Button onClick={() => executeAction.mutate({ key: 'move_to_proposal' })}>
148
+ Move to Proposal
149
+ </Button>
150
+ </Group>
151
+ <Textarea value={body} onChange={(event) => setBody(event.currentTarget.value)} />
152
+ <Button onClick={() => createNote.mutate({ dealId, body })}>Add Note</Button>
153
+ <pre>{JSON.stringify(notes, null, 2)}</pre>
154
+ </Stack>
155
+ )
156
+ }
157
+ ```
158
+
159
+ `useExecuteAction` is for platform-known/default action keys. Start custom action UI with the shared `crmActions` provider path; when a project-owned workflow is outside that server-dispatched action set, call `/execute` or `/execute-async` through `useElevasisServices`, or follow [customize-crm-actions.md](customize-crm-actions.md).
160
+
161
+ ## 4. Read and Mutate CRM Data in Workflows
162
+
163
+ Inside deployed workflows, use worker adapters instead of browser hooks or direct database access:
164
+
165
+ ```ts
166
+ // operations/src/sales/follow-up-stale-deals.ts
167
+ import type { WorkflowDefinition } from '@elevasis/sdk'
168
+ import { crm } from '@elevasis/sdk/worker'
169
+ import { resourceDescriptors } from '@core/config/organization-model'
170
+ import { z } from 'zod'
171
+
172
+ const inputSchema = z.object({
173
+ stage: z.string().default('proposal')
174
+ })
175
+
176
+ const outputSchema = z.object({
177
+ touched: z.number()
178
+ })
179
+
180
+ export const followUpStaleDealsWorkflow: WorkflowDefinition = {
181
+ config: {
182
+ resource: resourceDescriptors.followUpStaleDeals,
183
+ resourceId: resourceDescriptors.followUpStaleDeals.id,
184
+ name: 'Follow Up Stale Deals',
185
+ type: resourceDescriptors.followUpStaleDeals.kind,
186
+ version: '1.0.0',
187
+ status: 'dev',
188
+ },
189
+ contract: { inputSchema, outputSchema },
190
+ steps: {
191
+ followUp: {
192
+ id: 'followUp',
193
+ name: 'Follow Up',
194
+ inputSchema,
195
+ outputSchema,
196
+ next: null,
197
+ handler: async (input) => {
198
+ const deals = await crm.listDeals({ stage: input.stage })
199
+
200
+ for (const deal of deals) {
201
+ if (!['follow_up_due', 'stale'].includes(deal.priority.bucketKey)) continue
202
+
203
+ await crm.createDealTask({
204
+ dealId: deal.id,
205
+ title: 'Follow up',
206
+ kind: 'email'
207
+ })
208
+ await crm.recordActivity({
209
+ dealId: deal.id,
210
+ type: 'workflow.follow_up_task_created',
211
+ title: 'Follow-up task created',
212
+ payload: { workflow: 'follow-up-stale-deals' }
213
+ })
214
+ }
215
+
216
+ return { touched: deals.length }
217
+ }
218
+ }
219
+ },
220
+ entryPoint: 'followUp'
221
+ }
222
+ ```
223
+
224
+ Use `crm` for focused CRM deal reads, notes, tasks, activity, and cleanup. Use `acqDb` when the workflow needs the broader acquisition substrate: companies, contacts, lists, list-stage transitions, enrichment data, social posts, or lower-level deal sync methods.
225
+
226
+ ## 5. Customize Pipeline Semantics
227
+
228
+ CRM System identity is `sales.crm`, but the organization-model domain is `sales`.
229
+
230
+ For stage labels or stage sets, update the project model:
231
+
232
+ `core/config/organization-model.ts`
233
+
234
+ Keep these boundaries straight:
235
+
236
+ - Org-model sales pipelines describe business semantics.
237
+ - `DealStage` and platform action defaults describe the current shared platform deal state vocabulary.
238
+ - UI wrappers can relabel and route around shared surfaces, but changing persisted platform stages requires coordinated core/API/UI updates.
239
+ - Do not add `sales.actions` to the org model in v1. Deal action customization is covered by [customize-crm-actions.md](customize-crm-actions.md).
240
+
241
+ ## Verify
242
+
243
+ Run the checks for the surfaces you touched:
244
+
245
+ ```bash
246
+ pnpm -C ui run check
247
+ pnpm -C operations run check
248
+ pnpm -C operations exec elevasis-sdk check
249
+ ```
250
+
251
+ If you changed platform-level CRM contracts in the monorepo, the platform maintainer must also regenerate and verify scaffold output:
252
+
253
+ ```bash
254
+ pnpm scaffold:sync
255
+ pnpm scaffold:verify
256
+ ```