@elevasis/sdk 1.14.1 → 1.15.1

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.
@@ -0,0 +1,56 @@
1
+ # Template WorkOS Hardcode + Strict Dev Port
2
+
3
+ ## Why this note exists
4
+
5
+ The template UI no longer reads WorkOS configuration from `VITE_WORKOS_*` env vars. WorkOS `clientId`, `redirectUri`, and `signoutUri` are hardcoded in a new file `ui/src/config/workos.ts` so a freshly bootstrapped template runs without any UI `.env` setup. The Vite dev server now uses `strictPort: true` on port `4300` so a second `pnpm -C ui dev` on the same machine fails fast instead of silently drifting to another port.
6
+
7
+ This sync moves three pieces into derived projects:
8
+
9
+ - `ui/src/config/workos.ts` -- new merge-baseline file holding `clientId`, `redirectUri`, `signoutUri`
10
+ - `ui/src/main.tsx` and `ui/src/routes/__root.tsx` -- merge-regions updates that import `WORKOS_CONFIG` from `@/config/workos` instead of reading `import.meta.env.VITE_WORKOS_*`
11
+ - `ui/vite.config.ts` -- `strictPort: true` added next to `port: 4300`
12
+ - `ui/.env.example` -- WorkOS section removed (replaced with a single comment pointing at `ui/src/config/workos.ts`)
13
+ - `.claude/rules/ui.md` and `CLAUDE.md` -- prose updated; project-owned `CLAUDE.md` is verify-only and the project keeps its own narrative
14
+
15
+ `nirvana-marketing` and `ZentaraHQ` already received `ui/src/config/workos.ts`, the `strictPort` flag, and the `.claude/rules/ui.md` baseline as prep-gate repairs in the previous train. This note formally attributes those changes to an owning task doc and covers any remaining template-derived projects.
16
+
17
+ ## Applies to
18
+
19
+ Template-derived projects that:
20
+
21
+ - run a WorkOS-authenticated UI from `ui/src/main.tsx` and `ui/src/routes/__root.tsx`
22
+ - run the Vite dev server on port `4300`
23
+ - have a project-owned `ui/src/config/workos.ts` (created via prep-gate repair) or are seeing it land for the first time on this sync
24
+ - maintain a `ui/.env` file that previously set `VITE_WORKOS_CLIENT_ID`, `VITE_WORKOS_REDIRECT_URI`, or `VITE_WORKOS_SIGNOUT_URI`
25
+
26
+ Projects with no WorkOS surface or no Vite dev server are not affected.
27
+
28
+ ## Required actions
29
+
30
+ 1. Pull template changes with `/git-sync` after this train publishes so the WorkOS hardcode and strict-port baselines reach the project's UI shell.
31
+
32
+ 2. Confirm the project's `ui/src/config/workos.ts` reflects the WorkOS client ID the project should authenticate against. The template ships the platform team's dev-tier `clientId`; client-facing projects must overwrite that value with the project's own WorkOS client ID before going to production. Edit the literal in `ui/src/config/workos.ts` -- no env vars are involved.
33
+
34
+ 3. Stop providing `VITE_WORKOS_CLIENT_ID`, `VITE_WORKOS_REDIRECT_URI`, and `VITE_WORKOS_SIGNOUT_URI` in `ui/.env`. They are no longer read. Delete the entries to keep the file honest. The WorkOS values now live in `ui/src/config/workos.ts`.
35
+
36
+ 4. Confirm `ui/vite.config.ts` carries `strictPort: true` next to `server.port: 4300`. If a second dev server starts on the same port, expect a hard failure instead of a drift to `4301`.
37
+
38
+ 5. If the project hand-rolled an env-vars notice component or a `REQUIRED_ENV_VARS` array around WorkOS, remove it. `createElevasisApp` no longer needs the `MissingEnvNotice` prop now that `clientId` is always truthy.
39
+
40
+ ## Verification
41
+
42
+ After upgrading:
43
+
44
+ - `pnpm -C ui check-types` and `pnpm -C ui build` pass with `WORKOS_CONFIG` imported from `@/config/workos`.
45
+ - `pnpm -C ui dev` boots on `4300`. Starting a second `pnpm -C ui dev` in another terminal fails with a port-in-use error instead of incrementing to `4301`.
46
+ - WorkOS sign-in and sign-out still round-trip through the project's WorkOS tenant. Sign-out lands on the URL configured in `ui/src/config/workos.ts` (`signoutUri`).
47
+ - `grep -r VITE_WORKOS_ ui/src` returns nothing.
48
+
49
+ ## Not handled by /git-sync
50
+
51
+ `/git-sync` does not:
52
+
53
+ - delete `VITE_WORKOS_*` entries from project-local `ui/.env` files
54
+ - overwrite `ui/src/config/workos.ts` if the project has already customized the `clientId` for a non-default WorkOS tenant (the file is merge-baseline; customizations are preserved)
55
+ - update WorkOS dashboard redirect URIs or CORS origins for projects that run the dev server on a non-`4300` port; if the project changed the dev port, it must also change the WorkOS dashboard accordingly
56
+ - redeploy any project-owned operations bundle; this train is UI-shell only
@@ -1,70 +1,70 @@
1
- ---
2
- title: Scaffold Reference
3
- description: Universal scaffold documentation for Elevasis SDK projects -- recipes, patterns, architecture, and reference materials that apply to all workspaces.
4
- ---
1
+ ---
2
+ title: Scaffold Reference
3
+ description: Universal scaffold documentation for Elevasis SDK projects -- recipes, patterns, architecture, and reference materials that apply to all workspaces.
4
+ ---
5
5
  <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
6
6
  <!-- Regenerate: pnpm scaffold:sync -->
7
7
 
8
-
9
- ## Overview
10
-
11
- This scaffold reference contains universal documentation that applies to all Elevasis SDK projects. Content is organized by package ownership:
12
-
13
- - **recipes/** -- Cross-package pathway recipes (add a feature, add a resource, gating patterns)
14
- - **ui/** -- UI patterns, feature shell architecture, composition, and customization
15
- - **core/** -- Organization model architecture, graph layer, and semantic contracts
16
- - **operations/** -- Workflow authoring patterns and adapter usage
17
- - **reference/** -- Glossary, auto-generated contracts, and feature registry
18
-
19
- ## Quick Navigation
20
-
21
- ### Pathway Recipes
22
-
23
- - [Add a Feature](./recipes/add-a-feature.md) -- end-to-end from org model key through manifest, routes, gating
24
- - [Add a Resource](./recipes/add-a-resource.md) -- author and deploy a workflow or agent
25
- - [Extend a Base Entity](./recipes/extend-a-base-entity.md) -- add project-specific metadata to canonical entity shapes via the TMeta slot
26
- - [Gate by Feature or Admin](./recipes/gate-by-feature-or-admin.md) -- decision table for access control patterns
27
- - [Build and Extend CRM](./recipes/extend-crm.md) -- map CRM UI pages, hooks, actions, workflow adapters, contracts, and org-model boundaries
28
- - [Build and Extend Lead Gen](./recipes/extend-lead-gen.md) -- map lead-gen UI pages, hooks, list/member state, artifacts, touchpoints, workflow adapters, contracts, and org-model boundaries
29
- - [Customize CRM Actions](./recipes/customize-crm-actions.md) -- add, hide, or replace CRM deal actions, use the shared `crmActions` provider path, and understand workflow dispatch constraints
30
-
31
- ### UI Patterns
32
-
33
- - [UI Recipes](./ui/recipes.md) -- copy-paste recipes for pages, nav items, components, theme tokens
34
- - [Feature Flags & Gating](./ui/feature-flags-and-gating.md) -- three-concept model for feature access
35
- - [Customizing Features](./ui/customization.md) -- sidebar composition via manifest overrides
36
- - [Feature Shell & Provider](./ui/feature-shell.mdx) -- FeatureModule manifest contract, provider runtime
37
- - [Composition & Extensibility](./ui/composition-extensibility.mdx) -- layout primitives, router abstraction
38
-
39
- ### Core Architecture
40
-
41
- - [Organization Model](./core/organization-model.mdx) -- semantic contract, schema, authoring helpers
42
- - [Organization Graph](./core/organization-graph.mdx) -- graph derivation, node/edge taxonomy, lenses
43
-
44
- ### Operations
45
-
46
- - [Workflow Recipes](./operations/workflow-recipes.md) -- workflow anatomy, adapter patterns, trigger patterns
47
- - [Propagation Pipeline](./operations/propagation-pipeline.md) -- three-layer sync pipeline, verification checks, integration points
48
- - [Scaffold Maintenance](./operations/scaffold-maintenance.md) -- content placement, auto-generation, adding new scaffold docs
49
-
50
- ### Reference
51
-
52
- - [Glossary](./reference/glossary.md) -- term definitions for Organization OS concepts
53
- - [Contracts](./reference/contracts.md) -- auto-generated TypeScript contract shapes
54
- - [Feature Registry](./reference/feature-registry.md) -- auto-generated feature manifest catalog
55
-
56
- ## Source Locations
57
-
58
- Content is co-located with its owning package and copied here during SDK build:
59
-
60
- | Bundle Path | Source Location | Owner |
61
- | --------------------------------------------- | --------------------------------------------------------- | --------------- |
62
- | `scaffold/recipes/` | `packages/sdk/docs/scaffold/recipes/` | SDK |
63
- | `scaffold/operations/` | `packages/sdk/docs/scaffold/operations/` | SDK |
64
- | `scaffold/operations/propagation-pipeline.md` | `packages/sdk/docs/scaffold/operations/` | SDK |
65
- | `scaffold/operations/scaffold-maintenance.md` | `packages/sdk/docs/scaffold/operations/` | SDK |
66
- | `scaffold/ui/` | `packages/ui/src/scaffold/` | UI |
67
- | `scaffold/core/` | `packages/core/src/organization-model/` | Core |
68
- | `scaffold/reference/glossary.md` | `packages/core/src/reference/glossary.md` | Core |
69
- | `scaffold/reference/contracts.md` | `packages/core/src/reference/_generated/contracts.md` | Core (auto-gen) |
70
- | `scaffold/reference/feature-registry.md` | `packages/ui/src/scaffold/_generated/feature-registry.md` | UI (auto-gen) |
8
+
9
+ ## Overview
10
+
11
+ This scaffold reference contains universal documentation that applies to all Elevasis SDK projects. Content is organized by package ownership:
12
+
13
+ - **recipes/** -- Cross-package pathway recipes (add a feature, add a resource, gating patterns)
14
+ - **ui/** -- UI patterns, feature shell architecture, composition, and customization
15
+ - **core/** -- Organization model architecture, graph layer, and semantic contracts
16
+ - **operations/** -- Workflow authoring patterns and adapter usage
17
+ - **reference/** -- Glossary, auto-generated contracts, and feature registry
18
+
19
+ ## Quick Navigation
20
+
21
+ ### Pathway Recipes
22
+
23
+ - [Add a Feature](./recipes/add-a-feature.md) -- end-to-end from org model key through manifest, routes, gating
24
+ - [Add a Resource](./recipes/add-a-resource.md) -- author and deploy a workflow or agent
25
+ - [Extend a Base Entity](./recipes/extend-a-base-entity.md) -- add project-specific metadata to canonical entity shapes via the TMeta slot
26
+ - [Gate by Feature or Admin](./recipes/gate-by-feature-or-admin.md) -- decision table for access control patterns
27
+ - [Build and Extend CRM](./recipes/extend-crm.md) -- map CRM UI pages, hooks, actions, workflow adapters, contracts, and org-model boundaries
28
+ - [Build and Extend Lead Gen](./recipes/extend-lead-gen.md) -- map lead-gen UI pages, hooks, list/member state, artifacts, workflow adapters, contracts, and org-model boundaries
29
+ - [Customize CRM Actions](./recipes/customize-crm-actions.md) -- add, hide, or replace CRM deal actions, use the shared `crmActions` provider path, and understand workflow dispatch constraints
30
+
31
+ ### UI Patterns
32
+
33
+ - [UI Recipes](./ui/recipes.md) -- copy-paste recipes for pages, nav items, components, theme tokens
34
+ - [Feature Flags & Gating](./ui/feature-flags-and-gating.md) -- three-concept model for feature access
35
+ - [Customizing Features](./ui/customization.md) -- sidebar composition via manifest overrides
36
+ - [Feature Shell & Provider](./ui/feature-shell.mdx) -- FeatureModule manifest contract, provider runtime
37
+ - [Composition & Extensibility](./ui/composition-extensibility.mdx) -- layout primitives, router abstraction
38
+
39
+ ### Core Architecture
40
+
41
+ - [Organization Model](./core/organization-model.mdx) -- semantic contract, schema, authoring helpers
42
+ - [Organization Graph](./core/organization-graph.mdx) -- graph derivation, node/edge taxonomy, lenses
43
+
44
+ ### Operations
45
+
46
+ - [Workflow Recipes](./operations/workflow-recipes.md) -- workflow anatomy, adapter patterns, trigger patterns
47
+ - [Propagation Pipeline](./operations/propagation-pipeline.md) -- three-layer sync pipeline, verification checks, integration points
48
+ - [Scaffold Maintenance](./operations/scaffold-maintenance.md) -- content placement, auto-generation, adding new scaffold docs
49
+
50
+ ### Reference
51
+
52
+ - [Glossary](./reference/glossary.md) -- term definitions for Organization OS concepts
53
+ - [Contracts](./reference/contracts.md) -- auto-generated TypeScript contract shapes
54
+ - [Feature Registry](./reference/feature-registry.md) -- auto-generated feature manifest catalog
55
+
56
+ ## Source Locations
57
+
58
+ Content is co-located with its owning package and copied here during SDK build:
59
+
60
+ | Bundle Path | Source Location | Owner |
61
+ | --------------------------------------------- | --------------------------------------------------------- | --------------- |
62
+ | `scaffold/recipes/` | `packages/sdk/docs/scaffold/recipes/` | SDK |
63
+ | `scaffold/operations/` | `packages/sdk/docs/scaffold/operations/` | SDK |
64
+ | `scaffold/operations/propagation-pipeline.md` | `packages/sdk/docs/scaffold/operations/` | SDK |
65
+ | `scaffold/operations/scaffold-maintenance.md` | `packages/sdk/docs/scaffold/operations/` | SDK |
66
+ | `scaffold/ui/` | `packages/ui/src/scaffold/` | UI |
67
+ | `scaffold/core/` | `packages/core/src/organization-model/` | Core |
68
+ | `scaffold/reference/glossary.md` | `packages/core/src/reference/glossary.md` | Core |
69
+ | `scaffold/reference/contracts.md` | `packages/core/src/reference/_generated/contracts.md` | Core (auto-gen) |
70
+ | `scaffold/reference/feature-registry.md` | `packages/ui/src/scaffold/_generated/feature-registry.md` | UI (auto-gen) |
@@ -69,12 +69,10 @@ A minimal entry looks like:
69
69
  Workflows backing CRM actions use worker adapters instead of raw Supabase calls. The acquisition adapter is imported as `acqDb` from `@elevasis/sdk/worker` and exposes the action-workflow helpers:
70
70
 
71
71
  - `acqDb.transitionDeal({ dealId, toStage, toState? })` -- moves a deal to a new stage, optionally updating state_key.
72
- - `acqDb.recordDealActivity({ dealId, type, title, description?, payload? })` -- appends an entry to `acq_deal_activity_log`.
73
- - `acqDb.recordTouchpoint({ dealId, direction, channel, kind, payload, contactId, sourceExecutionId })` -- writes an `acq_touchpoints` row for outbound/inbound audit.
72
+ - `acqDb.recordDealActivity({ dealId, type, title, description?, payload? })` -- appends an entry to the deal's `activity_log` JSONB column. Use this for outbound/inbound audit and lifecycle events.
74
73
  - `acqDb.loadDeal({ dealId })` -- returns the deal row joined with contact and company.
75
- - `acqDb.listDealTouchpoints({ dealId, kind?, limit? })` -- returns touchpoint history for a deal.
76
74
 
77
- These wrap existing `LeadService` logic -- they are extraction, not new business logic. The separate `crm` adapter also exposes focused CRM methods such as `crm.recordActivity(...)`; use `acqDb` for action workflows that need deal transitions, touchpoints, and the broader acquisition substrate.
75
+ These wrap existing `LeadService` logic -- they are extraction, not new business logic. The separate `crm` adapter also exposes focused CRM methods such as `crm.recordActivity(...)`; use `acqDb` for action workflows that need deal transitions and the broader acquisition substrate.
78
76
 
79
77
  ## Override a Default Action
80
78
 
@@ -121,7 +119,7 @@ export const moveToProposalWorkflow: WorkflowDefinition = {
121
119
  }
122
120
  ```
123
121
 
124
- To add side effects (create a task, send a Slack message, record a touchpoint), extend the handler before the `return`. The `resourceId` must match the action's `workflowId` in `DEFAULT_CRM_ACTIONS` from `@elevasis/sdk` exactly.
122
+ To add side effects (create a task, send a Slack message, log a deal activity), extend the handler before the `return`. The `resourceId` must match the action's `workflowId` in `DEFAULT_CRM_ACTIONS` from `@elevasis/sdk` exactly.
125
123
 
126
124
  Register the workflow in the operations manifest:
127
125
 
@@ -205,7 +203,7 @@ This controls the shared `DealDetailPage` and `DealDrawer` action row.
205
203
 
206
204
  For a brand-new action key that calls a project-owned workflow, define the workflow first.
207
205
 
208
- If the action sends email, writes to another channel, or otherwise touches a customer, use `acqDb.recordTouchpoint` inside the workflow handler to write an audit row. For an advanced Instantly-thread-aware variant that prefers in-thread replies and falls back to fresh outbound, use the production CRM workflow summary as the canonical example: `apps/docs/content/docs/in-progress/active-development/sdk-changes/crm/crm-current-state-assessment.mdx`.
206
+ If the action sends email, writes to another channel, or otherwise touches a customer, use `acqDb.recordDealActivity` inside the workflow handler to append an audit entry to the deal's `activity_log`. For an advanced Instantly-thread-aware variant that prefers in-thread replies and falls back to fresh outbound, see the canonical CRM action examples in `external/elevasis/operations/src/sales/crm/actions/`.
209
207
 
210
208
  ### Define the Workflow Contract
211
209
 
@@ -272,14 +270,11 @@ export const sendQuoteWorkflow: WorkflowDefinition = {
272
270
  html: `<p>Your quote is ready. Reply to this email with questions.</p>`
273
271
  })
274
272
 
275
- await acqDb.recordTouchpoint({
273
+ await acqDb.recordDealActivity({
276
274
  dealId,
277
- direction: 'outbound',
278
- channel: 'email',
279
- kind: 'quote_sent',
280
- payload: { triggered_by_action: 'send_quote' },
281
- contactId: deal.contact.id,
282
- sourceExecutionId: context.executionId
275
+ type: 'quote_sent',
276
+ title: 'Sent quote',
277
+ payload: { triggered_by_action: 'send_quote', channel: 'email' }
283
278
  })
284
279
 
285
280
  return {
@@ -394,6 +389,36 @@ export function CustomDealPage({ dealId }: { dealId: string }) {
394
389
  }
395
390
  ```
396
391
 
392
+ ## CRM State-Key Source of Truth
393
+
394
+ `CRM_PIPELINE_DEFINITION` in `packages/core/src/organization-model/domains/sales.ts` is the single canonical source for CRM `state_key` values. It exports a `StatefulPipelineDefinition` that enumerates every valid state per stage (e.g. `interested` → `discovery_replied`, `discovery_link_sent`, `discovery_nudging`, etc.). Named per-state constants (`CRM_DISCOVERY_REPLIED_STATE`, `CRM_DISCOVERY_LINK_SENT_STATE`, and siblings) are also exported for use in conditional logic.
395
+
396
+ Import via `@repo/core/organization-model`:
397
+
398
+ ```ts
399
+ import {
400
+ CRM_PIPELINE_DEFINITION,
401
+ CRM_DISCOVERY_REPLIED_STATE,
402
+ getValidStatesForStage
403
+ } from '@repo/core/organization-model'
404
+
405
+ const validStates = getValidStatesForStage(CRM_PIPELINE_DEFINITION, 'interested')
406
+ // [{ stateKey: 'discovery_replied', label: '...' }, ...]
407
+ ```
408
+
409
+ Workflows that write `state_key` should import from this definition rather than hardcoding string literals. This keeps the vocabulary in one place and lets the API validate against the allowed set for a deal's current stage.
410
+
411
+ **Current gap:** `@elevasis/core` v0.13.0 does not yet expose the `organization-model` subpath. Until a new release ships that export, hardcoded strings in `external/elevasis/operations/...` are tracked as follow-up. Document usages with a `// TODO: replace with CRM_PIPELINE_DEFINITION import once @elevasis/core exposes organization-model` comment so they are easy to find.
412
+
413
+ ## Activity Log Conventions
414
+
415
+ The `acq_deal_activity_log` table uses a `kind` field to distinguish how a state transition was initiated. Two values are relevant for CRM state changes:
416
+
417
+ - `state_change` -- written by workflow steps (e.g. `crm-send-booking-link.ts` transitioning to `discovery_link_sent`). Carries an `action_taken` payload identifying the workflow.
418
+ - `state_changed_manually` -- written by the `PATCH /api/deals/:dealId/state` route when an operator edits `state_key` directly from the UI. Carries the user id and the before/after state. This is a pure column update with no workflow side-effects.
419
+
420
+ When reading the audit trail, use `kind` to distinguish automated pipeline progression from manual repair operations. Do not conflate the two when building reports or alerting rules.
421
+
397
422
  ## Verify
398
423
 
399
424
  Run the relevant checks from the project root:
@@ -58,7 +58,9 @@ Read the generated contracts before changing typed boundaries:
58
58
 
59
59
  `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`
60
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**.
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`.
62
64
 
63
65
  ## 1. Extend CRM Navigation or Sidebar
64
66
 
@@ -192,13 +194,15 @@ export const followUpStaleDealsWorkflow: WorkflowDefinition = {
192
194
  outputSchema,
193
195
  next: null,
194
196
  handler: async (input) => {
195
- const deals = await crm.listDeals({ stage: input.stage })
196
-
197
- for (const deal of deals) {
198
- await crm.createDealTask({
199
- dealId: deal.id,
200
- title: 'Follow up',
201
- kind: 'email'
197
+ const deals = await crm.listDeals({ stage: input.stage })
198
+
199
+ for (const deal of deals) {
200
+ if (!['follow_up_due', 'stale'].includes(deal.priority.bucketKey)) continue
201
+
202
+ await crm.createDealTask({
203
+ dealId: deal.id,
204
+ title: 'Follow up',
205
+ kind: 'email'
202
206
  })
203
207
  await crm.recordActivity({
204
208
  dealId: deal.id,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Build and Extend Lead Gen
3
- description: Map the lead-gen platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, list/member state, artifacts, touchpoints, workflow adapters, contracts, and org-model extension boundaries.
3
+ description: Map the lead-gen platform primitives available to SDK projects: shared UI pages, sidebar composition, data hooks, list/member state, artifacts, workflow adapters, contracts, and org-model extension boundaries.
4
4
  ---
5
5
  <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
6
6
  <!-- Regenerate: pnpm scaffold:sync -->
@@ -15,7 +15,7 @@ Good trigger phrases:
15
15
  - "Add a lead-gen reports page."
16
16
  - "Build a campaign creator surface."
17
17
  - "Customize the lead-gen sidebar."
18
- - "Show artifacts or touchpoints for a campaign."
18
+ - "Show artifacts for a campaign."
19
19
  - "Read or update lead-gen lists from a workflow."
20
20
  - "Change the lead-gen lifecycle for this business."
21
21
 
@@ -23,42 +23,44 @@ Lead gen is a layered platform surface, not one component:
23
23
 
24
24
  - **Organization OS:** prospecting semantics, feature gates, pipeline labels, and quick access live in the organization model.
25
25
  - **Shared UI:** lead-gen overview, lists, list detail, companies, contacts, sidebars, and drawer components live in `@elevasis/ui`.
26
- - **Headless hooks:** lists, companies, contacts, artifacts, touchpoints, list members, transitions, and derived actions live under `@elevasis/ui/hooks`.
27
- - **Acquisition substrate:** `acq_lists`, `acq_companies`, `acq_contacts`, `acq_artifacts`, `acq_touchpoints`, list members, list companies, telemetry, and stateful transition shapes are exposed through generated contracts.
26
+ - **Headless hooks:** lists, companies, contacts, artifacts, list members, transitions, and derived actions live under `@elevasis/ui/hooks`.
27
+ - **Acquisition substrate:** `acq_lists`, `acq_companies`, `acq_contacts`, `acq_artifacts`, list members, list companies, telemetry, and stateful transition shapes are exposed through generated contracts.
28
28
  - **Workflow adapters:** `acqDb` and `list` from `@elevasis/sdk/worker` let workflows read and mutate lead-gen data through platform tools.
29
29
  - **Contracts:** generated contract docs expose the current lead-gen shapes in `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`.
30
30
 
31
31
  ## Decision Table
32
32
 
33
- | User wants | Start here | Notes |
34
- | --- | --- | --- |
35
- | Change lead-gen feature availability, labels, quick access, or pipeline semantics | `core/config/organization-model.ts` plus `core/config/organization-model.examples.ts` | Treat this as Organization OS work. Use the project's configure ceremony if available. |
36
- | Add lead-gen sidebar nav or a lead-gen route | `@elevasis/ui/features/lead-gen` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
37
- | Wrap a shared lead-gen page with project chrome | `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage` | Keep route files thin and put project-specific behavior in local feature modules. |
38
- | Build a custom campaign/list workspace | `useLists`, `useList`, `useListMembers`, `useArtifacts`, `useTouchpoints`, `useTransitionListMember` from `@elevasis/ui/hooks` | Use hooks for platform data and compose your own UI. |
39
- | Render artifacts, touchpoints, or list-member detail | `LeadGenListDetailPage`, `useArtifacts`, `useCreateArtifact`, `useTouchpoints`, `useListMember` | Artifacts and touchpoints are substrate primitives. Keep vertical-specific rendering local until there are repeated use cases. |
40
- | Read or mutate lead-gen data inside a workflow | `acqDb` or `list` from `@elevasis/sdk/worker` | `organizationId` is injected server-side by the platform dispatcher. Do not pass it from workflow code. |
41
- | Add a new persisted lead-gen field, artifact kind, or transition API | Platform/API migration work, not just scaffold work | Update DB, core schemas/types, API service/handlers, hooks, docs, and scaffold contracts together. |
33
+ | User wants | Start here | Notes |
34
+ | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
35
+ | Change lead-gen feature availability, labels, quick access, or pipeline semantics | `core/config/organization-model.ts` plus `core/config/organization-model.examples.ts` | Treat this as Organization OS work. Use the project's configure ceremony if available. |
36
+ | Add lead-gen sidebar nav or a lead-gen route | `@elevasis/ui/features/lead-gen` and `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` | Prefer manifest/sidebar composition. Do not fork shared source first. |
37
+ | Wrap a shared lead-gen page with project chrome | `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `ListBuilderPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage` | Keep route files thin and put project-specific behavior in local feature modules. |
38
+ | Build a custom campaign/list workspace | `ListBuilderPage`, `useLists`, `useList`, `useListProgress`, `useListExecutions`, `useWorkflowExecution`, `useExecutionSSE` from `@elevasis/ui` | Use the shared builder when possible; otherwise compose hooks for platform data and workflow execution. |
39
+ | Render artifacts or list-member detail | `LeadGenListDetailPage`, `useArtifacts`, `useCreateArtifact`, `useListMember` | Artifacts are a substrate primitive. Keep vertical-specific rendering local until there are repeated use cases. |
40
+ | Read or mutate lead-gen data inside a workflow | `acqDb` or `list` from `@elevasis/sdk/worker` | `organizationId` is injected server-side by the platform dispatcher. Do not pass it from workflow code. |
41
+ | Add a new persisted lead-gen field, artifact kind, or transition API | Platform/API migration work, not just scaffold work | Update DB, core schemas/types, API service/handlers, hooks, docs, and scaffold contracts together. |
42
42
 
43
43
  ## Published Lead-Gen Surfaces
44
44
 
45
- | Surface | Import from | Use for |
46
- | --- | --- | --- |
47
- | `leadGenManifest`, `LEAD_GEN_ITEMS`, `LeadGenSidebar`, `LeadGenSidebarTop`, `LeadGenSidebarMiddle` | `@elevasis/ui/features/lead-gen` | Feature registration and sidebar composition |
48
- | `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage` | `@elevasis/ui/features/lead-gen` | Shared lead-gen pages you can route to or wrap |
49
- | `LeadGenRouteShell`, `CompanyDetailModal`, `ContactDetailModal`, `LIST_TEMPLATE_OPTIONS`, `buildListConfig` | `@elevasis/ui/features/lead-gen` | Route shell helpers, detail modals, and list creation config helpers |
50
- | `useLists`, `useList`, `useListsTelemetry`, `useListProgress`, `useListExecutions`, `useCreateList`, `useUpdateList`, `useUpdateListConfig`, `useDeleteList` | `@elevasis/ui/hooks` | Headless list and telemetry data access |
51
- | `useCompanies`, `useCompany`, `useContacts`, `useContact` | `@elevasis/ui/hooks` | Acquisition company/contact data access |
52
- | `useArtifacts`, `useCreateArtifact`, `useTouchpoints`, `useListMembers`, `useListMember` | `@elevasis/ui/hooks` | Lead-gen substrate data access |
53
- | `useTransitionList`, `useTransitionListMember`, `useTransitionListCompany`, `useDeriveActions` | `@elevasis/ui/hooks` | Stateful transition mutations and contextual action derivation |
54
- | `ElevasisUIProvider`, `ElevasisCoreProvider`, `useElevasisServices` | `@elevasis/ui/provider` | Provider setup, API access, and organization context |
55
- | `acqDb`, `list` | `@elevasis/sdk/worker` | Workflow-side acquisition and list-scoped platform adapters |
45
+ | Surface | Import from | Use for |
46
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | -------------------------------------------------------------------- |
47
+ | `leadGenManifest`, `LEAD_GEN_ITEMS`, `LeadGenSidebar`, `LeadGenSidebarTop`, `LeadGenSidebarMiddle` | `@elevasis/ui/features/lead-gen` | Feature registration and sidebar composition |
48
+ | `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `ListBuilderPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage` | `@elevasis/ui/features/lead-gen` | Shared lead-gen pages you can route to or wrap |
49
+ | `ListActionsProvider`, `useListActions`, `ListBuilderWorkflow`, `ListBuilderRegistry`, MVP workflow form components | `@elevasis/ui/features/lead-gen` | List Builder workflow registry, run modal inputs, and project-owned action wiring |
50
+ | `LeadGenRouteShell`, `CompanyDetailModal`, `ContactDetailModal`, `LIST_TEMPLATE_OPTIONS`, `buildListConfig` | `@elevasis/ui/features/lead-gen` | Route shell helpers, detail modals, and list creation config helpers |
51
+ | `useLists`, `useList`, `useListsTelemetry`, `useListProgress`, `useListExecutions`, `useCreateList`, `useUpdateList`, `useUpdateListConfig`, `useDeleteList` | `@elevasis/ui/hooks` | Headless list and telemetry data access |
52
+ | `useWorkflowExecution`, `useExecutionSSE`, `useAddCompaniesToList`, `useRemoveCompaniesFromList`, `useAddContactsToList` | `@elevasis/ui/hooks` | List Builder workflow triggering, live execution tailing, and list membership mutations |
53
+ | `useCompanies`, `useCompany`, `useContacts`, `useContact` | `@elevasis/ui/hooks` | Acquisition company/contact data access |
54
+ | `useArtifacts`, `useCreateArtifact`, `useListMembers`, `useListMember` | `@elevasis/ui/hooks` | Lead-gen substrate data access |
55
+ | `useTransitionList`, `useTransitionListMember`, `useTransitionListCompany`, `useDeriveActions` | `@elevasis/ui/hooks` | Stateful transition mutations and contextual action derivation |
56
+ | `ElevasisUIProvider`, `ElevasisCoreProvider`, `useElevasisServices` | `@elevasis/ui/provider` | Provider setup, API access, organization context, and `listActions` registry injection |
57
+ | `acqDb`, `list` | `@elevasis/sdk/worker` | Workflow-side acquisition and list-scoped platform adapters |
56
58
 
57
59
  Read the generated contracts before changing typed boundaries:
58
60
 
59
61
  `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md`
60
62
 
61
- Look for the **Lead Gen Platform Primitives** section. It includes list shapes, company/contact shapes, list config, telemetry, artifacts, touchpoints, list members, stateful pipeline definitions, and workflow adapter method maps.
63
+ Look for the **Lead Gen Platform Primitives** section. It includes list shapes, company/contact shapes, list config, telemetry, artifacts, list members, stateful pipeline definitions, and workflow adapter method maps.
62
64
 
63
65
  ## 1. Extend Lead-Gen Navigation or Sidebar
64
66
 
@@ -135,19 +137,90 @@ function ListDetailRoute() {
135
137
 
136
138
  Use the same wrapping pattern for `LeadGenOverviewPage`, `LeadGenCompaniesPage`, and `LeadGenContactsPage`.
137
139
 
140
+ For the real-time List Builder workspace, add a thin route that passes the route param into `ListBuilderPage`:
141
+
142
+ ```tsx
143
+ import { createFileRoute } from '@tanstack/react-router'
144
+ import { ListBuilderPage } from '@elevasis/ui/features/lead-gen'
145
+
146
+ export const Route = createFileRoute('/lead-gen/list-builder/$listId')({
147
+ component: ListBuilderRoute
148
+ })
149
+
150
+ function ListBuilderRoute() {
151
+ const { listId } = Route.useParams()
152
+ return <ListBuilderPage listId={listId} />
153
+ }
154
+ ```
155
+
156
+ Register project workflow actions at the provider boundary. The shared UI owns the contract; each project owns workflow ids and form choices:
157
+
158
+ ```tsx
159
+ import {
160
+ CompanyCleanupForm,
161
+ EmailDiscoveryForm,
162
+ EmailVerificationForm,
163
+ WebsiteExtractForm,
164
+ type ListBuilderRegistry
165
+ } from '@elevasis/ui/features/lead-gen'
166
+ import { ElevasisUIProvider } from '@elevasis/ui/provider'
167
+
168
+ const listActions: ListBuilderRegistry = [
169
+ {
170
+ resourceId: 'lgn-04-email-discovery-workflow',
171
+ label: 'Email Discovery',
172
+ description: 'Discover contact email addresses for companies in the list.',
173
+ category: 'enrich',
174
+ stagesAffected: ['discovered'],
175
+ inputForm: EmailDiscoveryForm
176
+ },
177
+ {
178
+ resourceId: 'lgn-05-email-verification-workflow',
179
+ label: 'Email Verification',
180
+ description: 'Verify deliverability for contact emails in the list.',
181
+ category: 'enrich',
182
+ stagesAffected: ['verified'],
183
+ inputForm: EmailVerificationForm
184
+ },
185
+ {
186
+ resourceId: 'lgn-02-website-extract-workflow',
187
+ label: 'Website Extract',
188
+ description: 'Extract website intelligence for companies in the list.',
189
+ category: 'scrape',
190
+ stagesAffected: ['extracted'],
191
+ inputForm: WebsiteExtractForm
192
+ },
193
+ {
194
+ resourceId: 'lgn-company-cleanup-workflow',
195
+ label: 'Company Cleanup',
196
+ description: 'Normalize and clean company records for the list.',
197
+ category: 'utility',
198
+ stagesAffected: ['populated'],
199
+ inputForm: CompanyCleanupForm
200
+ }
201
+ ]
202
+
203
+ export function App() {
204
+ return (
205
+ <ElevasisUIProvider listActions={listActions} {...providerProps}>
206
+ {children}
207
+ </ElevasisUIProvider>
208
+ )
209
+ }
210
+ ```
211
+
138
212
  ## 3. Build a Custom Campaign Workspace
139
213
 
140
214
  When the project needs custom layout or vertical-specific rendering, use the hooks directly:
141
215
 
142
216
  ```tsx
143
217
  import { Badge, Button, Card, Group, Stack, Text } from '@mantine/core'
144
- import { useArtifacts, useList, useListMembers, useTouchpoints, useTransitionListMember } from '@elevasis/ui/hooks'
218
+ import { useArtifacts, useList, useListMembers, useTransitionListMember } from '@elevasis/ui/hooks'
145
219
 
146
220
  export function CampaignWorkspace({ listId }: { listId: string }) {
147
221
  const listQuery = useList(listId)
148
222
  const membersQuery = useListMembers({ listId })
149
223
  const artifactsQuery = useArtifacts({ ownerKind: 'list', ownerId: listId })
150
- const touchpointsQuery = useTouchpoints({ listId })
151
224
  const transitionMember = useTransitionListMember()
152
225
 
153
226
  const list = listQuery.data
@@ -167,7 +240,6 @@ export function CampaignWorkspace({ listId }: { listId: string }) {
167
240
 
168
241
  <Card withBorder>
169
242
  <Text size="sm">Artifacts: {artifactsQuery.data?.artifacts.length ?? 0}</Text>
170
- <Text size="sm">Touchpoints: {touchpointsQuery.data?.touchpoints.length ?? 0}</Text>
171
243
  </Card>
172
244
 
173
245
  {firstMember ? (
@@ -190,7 +262,7 @@ export function CampaignWorkspace({ listId }: { listId: string }) {
190
262
  }
191
263
  ```
192
264
 
193
- Use `useArtifacts({ ownerKind, ownerId })` for durable JSON artifacts like audits, research summaries, snapshots, exports, or model outputs. Use `useTouchpoints({ listId })`, `useTouchpoints({ listMemberId })`, or `useTouchpoints({ contactId })` for timeline-style campaign interactions.
265
+ Use `useArtifacts({ ownerKind, ownerId })` for durable JSON artifacts like audits, research summaries, snapshots, exports, or model outputs.
194
266
 
195
267
  ## 4. Read and Mutate Lead-Gen Data in Workflows
196
268
 
@@ -277,7 +349,7 @@ The platform-side lead-gen stateful vocabulary is defined for:
277
349
 
278
350
  The generated contracts expose `StatefulPipelineDefinition` and `LEAD_GEN_PIPELINE_DEFINITIONS` so downstream agents can inspect the current pipeline/stage/state vocabulary before adding UI labels or workflow transitions.
279
351
 
280
- Changing persisted platform stages, adding new owner kinds, or extending artifact/touchpoint schema requires coordinated core/API/UI updates. Relabeling, route wrapping, sidebar changes, and project-owned rendering usually stay in the downstream project.
352
+ Changing persisted platform stages, adding new owner kinds, or extending artifact schema requires coordinated core/API/UI updates. Relabeling, route wrapping, sidebar changes, and project-owned rendering usually stay in the downstream project.
281
353
 
282
354
  ## Verify
283
355