# OpenSpec Change: enterprise-react-campaigns - **Change ID**: enterprise-react-campaigns - **Package**: `@suaveplan/react-campaigns` - **Category**: react - **Target path**: `react/platform/react-campaigns` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/react-campaigns.md` --- ## Summary Deliver `@suaveplan/react-campaigns` on genesis from scratch at enterprise quality. React UI layer on top of `@suaveplan/campaigns`: five-step `CampaignBuilder` wizard (basics → audience → template → schedule → review), `CampaignList`, `CampaignDetail`, `CampaignAnalytics`, `CampaignStatusBadge`, `AudienceSelector`, and three hooks (`useCampaign`, `useCampaignList`, `useCampaignStats`). Genesis fixes the `useCampaign.update` contract (main branch re-fetched instead of calling engine update), removes the module-scoped default engine in favour of `CampaignEngineProvider`, splits `campaign-builder.tsx` past the 300-line limit into per-step subcomponents, and adds missing tests for `campaign-builder`, `campaign-detail`, and `use-campaign-stats`. --- ## Current-state audit (genesis) Package does not exist on genesis — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `CampaignUiError` | | `@suaveplan/campaigns` (`workspace:^`) | Campaign engine, schemas, store | | `@suaveplan/react-translate` (`workspace:^`) | i18n for all UI strings | | `@suaveplan/react-error-boundary` (`workspace:^`) | `CampaignsErrorBoundary` | | `@opentelemetry/api` (`catalog:observability`) | `campaign.*` counters + spans | | `zod` (`catalog:forms`) | Boundary validation | | `tslib` (`catalog:build`) | TS helpers | External: React 18 peer. --- ## Preserved public API surface ```ts // Provider CampaignEngineProvider, useCampaignEngine // Components CampaignBuilder, CampaignList, CampaignDetail, CampaignAnalytics, CampaignStatusBadge, AudienceSelector, CampaignsErrorBoundary // Hooks useCampaign, useCampaignList, useCampaignStats // Types AudienceGroup, CampaignBuilderProps, CampaignListProps, CampaignDetailProps, CampaignAnalyticsProps, CampaignStatusBadgeProps, AudienceSelectorProps, UseCampaignOptions, UseCampaignReturn, UseCampaignListOptions, UseCampaignListReturn, UseCampaignStatsOptions, UseCampaignStatsReturn ``` --- ## New additions for genesis 1. **`CampaignUiError`** — codes: `CAMPAIGN_ENGINE_MISSING`, `CAMPAIGN_UPDATE_FAILED`, `CAMPAIGN_SEND_FAILED`. 2. **`CampaignEngineProvider`** — React context replacing module-scoped `defaultEngine`; every hook resolves engine via context or throws `CampaignUiError(CAMPAIGN_ENGINE_MISSING)` in dev. 3. **`useCampaign.update` fix** — calls real engine update path (main branch re-fetched instead of updating). 4. **`CampaignBuilder` split** — per-step subcomponents in `steps/` keeping top-level file under 250 lines. 5. **`CampaignsErrorBoundary`** — exported wrapper via `@suaveplan/react-error-boundary`. 6. **Missing tests** — `campaign-builder`, `campaign-detail`, `use-campaign-stats` all fully covered. 7. **OTel counters** — `campaign.created`, `campaign.sent`, `campaign.cancelled`, `campaign.duplicated`. 8. **Draft auto-save** — debounced save in `CampaignBuilder` with local restore on mount. 9. **Playwright E2E** — wizard happy path, list filter + pagination, keyboard-only, mobile viewport. --- ## File layout ```text react/platform/react-campaigns/ package.json tsconfig.json vitest.config.ts src/ index.ts types/ provider/ campaign-engine-provider/ (tsx + md + test + index) components/ campaign-builder/ campaign-builder.tsx + types + md + test + stories + index steps/ basics.tsx audience.tsx template.tsx schedule.tsx review.tsx campaign-list/ (tsx + types + md + test + stories + index) campaign-detail/ (tsx + types + md + test + stories + index) campaign-analytics/ (tsx + types + md + test + stories + index) campaign-status-badge/ (tsx + types + md + test + stories + index) audience-selector/ (tsx + types + md + test + stories + index) hooks/ use-campaign/ use-campaign-list/ use-campaign-stats/ e2e/ campaigns.spec.ts ```