# 2026-05-06 -- CRM OM Spine Migration

## Why this note exists

The CRM deal vocabulary (`stage_key`, `state_key`, `pipeline_key`) is now a fully-realized OM Spine matching the lead-gen list-builder pattern. `CRM_PIPELINE_DEFINITION` becomes the single source of truth: `@elevasis/core` derives `CrmStageKeySchema` and `CrmStateKeySchema` from the catalog, the catalog gains optional `color?` metadata on each stage, and `@elevasis/sdk` re-exports both schemas plus the catalog so external SDK consumers see the same vocabulary as monorepo callers. `@elevasis/ui` rewires the CRM page helpers (`DEAL_STAGE_COLORS`, `DEAL_STAGE_OPTIONS`, `formatDealStageLabel`, `formatDealStateLabel`) to read from the catalog instead of hardcoded maps -- public exports are preserved, behavior is now catalog-driven.

The platform side also closed a long-standing data drift: `pipeline_key='default'` in `acq_deals` is gone; live writers now use `pipeline_key='crm'` matching the catalog's `pipelineKey: 'crm'`. The Elevasis backfill applied directly to prod and dev on 2026-05-06; tenant deal rows are not affected by that backfill and continue to use whatever value tenant code wrote.

## Applies to

- All template-derived projects that consume `@elevasis/core`, `@elevasis/ui`, or `@elevasis/sdk`.
- Projects that customize CRM stages or states in `core/config/organization-model.ts` under the `sales` domain.
- Projects that read or write CRM transitions through `@elevasis/sdk` worker adapters (`acqDb.transitionDeal`, `acqDb.transitionItem`).
- Projects that render CRM pipeline UI from `@elevasis/ui/features/crm`.

## Required actions

1. Pull synced template package baselines through `/git-sync`:
   - `core/package.json`: `@elevasis/core` -> 0.20.0
   - `ui/package.json`: `@elevasis/ui` -> 2.29.0
   - `operations/package.json`: `@elevasis/core` -> 0.20.0 and `@elevasis/sdk` -> 1.19.0

2. Run `pnpm install` and rebuild the project:

   ```bash
   pnpm install
   pnpm -C ui build
   pnpm -C ui exec tsc --noEmit
   pnpm -C operations exec tsc --noEmit
   ```

3. **Optional: adopt `color?` on customized CRM stages.** If `core/config/organization-model.ts` overrides `sales.stages` with custom labels, you may now add an optional `color` field per stage (any Mantine palette key: `blue`, `yellow`, `orange`, `green`, `red`, `grape`, etc.). The shipped `DEAL_STAGE_COLORS` map and CRM kanban UI will read it. Stages without a `color` fall back to the platform default mapping in the catalog.

4. **Optional: tighten project-owned CRM workflow inputs.** New schemas are available from `@elevasis/sdk`:

   ```ts
   import { CrmStageKeySchema, CrmStateKeySchema, CRM_PIPELINE_DEFINITION } from '@elevasis/sdk'
   ```

   Project-authored CRM action workflows that previously used `z.string()` for `toStage` / `toState` can now validate against the catalog-derived enum. The `transitionItem` / `transitionDeal` worker adapters still accept strings, but unknown stage/state keys are rejected at the platform writer layer for `pipelineKey: 'crm'` writers.

5. **No tenant data backfill required.** The `pipeline_key='default'` -> `'crm'` backfill was applied to Elevasis databases only. Tenant `acq_deals` rows are unaffected. If tenant code writes `pipelineKey: 'default'` to `acqDb.transitionDeal`, that behavior is unchanged; only the published catalog declares `'crm'` as canonical and the published schemas validate `'crm'` exclusively for CRM-shaped transitions.

## Verification

After applying the actions above:

- `pnpm -C ui check-types`
- `pnpm -C ui build`
- `pnpm -C ui test`
- `pnpm -C operations check`
- `pnpm -C operations check-types`
- `pnpm -C operations test`
- Browser smoke: open `/crm/pipeline` (or the project's CRM kanban surface) and verify stage labels and column colors render from the catalog. Custom-labeled stages should show the override label; default stages show the platform palette.

## Not handled by /git-sync

- **Tenant CRM action workflows.** If a project authored its own CRM action workflows in `operations/` that import `transitionDeal` / `syncDealStateKeyToDb` directly (rather than `emitCrmTransition`), `/git-sync` does NOT refactor them. The platform-side `emitCrmTransition` factory is internal to `@repo/elevasis-operations` (workspace-internal) and is not part of the published SDK surface. Project-owned workflows continue to call the worker adapters directly; the new validation guard rejects unknown stage/state keys but does not require migration.
- **Customized stage colors.** Existing tenant overrides under `sales.stages[].label` and `sales.stages[].states[]` continue to work unchanged. Adopting the new optional `color` field is a project-by-project decision; `/git-sync` will not infer colors for custom stages.
- **`pipeline_key` data in tenant databases.** If a project has historic `acq_deals` rows with `pipeline_key='default'` and wants to align with the new canonical `'crm'` identity, that is a tenant-managed migration -- not part of this train.
