# Task EP.1.3 Business Event Foundation - 2026-07-13 ## Scope - introduced canonical Business Event contract - added machine-readable registry, alias resolution, ownership metadata, naming rules, and payload validation - added transport-independent publisher abstraction and in-process dispatcher - added idempotent subscriber handling and unsupported-version detection - published initial Activity lifecycle business events from Activity service layer - documented projection consumer contracts, event sequence matrix, replay readiness, compatibility mapping, and versioning strategy - preserved existing notification, approval, follow-up, dashboard, report, and audit behavior ## Review Summary Reviewed before and during implementation: - `AGENTS.md` - `plans/task-ep.1.3.md` - `docs/standards/task-catalog.md` - `docs/standards/project-foundations.md` - `docs/standards/architecture-rules.md` - `docs/standards/ui-ux-rules.md` - `docs/standards/task-review-checklist.md` - `docs/security/crm-authorization-boundaries.md` - `docs/implementation/task-ep1.1-activity-domain-foundation-2026-07-10.md` - `docs/implementation/task-ep1.2-activity-integration-legacy-followup-adapter-2026-07-13.md` - existing Activity lifecycle service operations - existing notification event service - existing approval notification publication behavior - existing audit-log foundation ## Implementation Summary ### Canonical Contract Added `BusinessEvent` in `src/features/foundation/business-events/types.ts`. The envelope includes: - globally unique `eventId` - registered `eventType` - explicit `schemaVersion` - organization, branch, entity, primary record, and related records - actor, `occurredAt`, `correlationId`, and `causationId` - visibility metadata for product type, pricing sensitivity, and internal-only events - payload and metadata ### Registry And Naming Added `src/features/foundation/business-events/registry.ts`. The registry freezes canonical names and ownership for Activity, Lead, Opportunity, Quotation, Approval, Customer, and PO families. Naming follows lowercase `.` where practical, with compatibility aliases for existing approval notification names such as `approval.step.approved`. Unknown event types are rejected by publisher validation. ### Publisher And Dispatcher Added: - `src/features/foundation/business-events/publisher.ts` - `src/features/foundation/business-events/dispatcher.ts` The initial dispatcher is in-process and transport-independent. It supports independent subscriber registration, no-subscriber dispatch, duplicate detection by `consumerName:eventId`, subscriber isolation, unsupported-version reporting, and publish-many ordering. No Kafka, RabbitMQ, Redis Streams, persistent event store, replay table, or projection table was introduced. ### Initial Activity Event Publishing Activity lifecycle events now publish from `src/features/crm/activities/server/service.ts`, after successful service-layer mutations: - `activity.created` - `activity.assigned` - `activity.reassigned` - `activity.started` - `activity.rescheduled` - `activity.completed` - `activity.cancelled` - `activity.deleted` Route handlers do not publish events directly. Activity payloads redact narrative fields when an Activity is pricing-sensitive or internal-only. Visibility metadata remains available so future consumers can enforce CRM authorization before re-querying source details. Legacy follow-up adapters do not publish events in EP.1.3. ### Event Sequence Matrix Added `BUSINESS_EVENT_SEQUENCE_MATRIX` in `src/features/foundation/business-events/matrices.ts`. It freezes expected order for key operations: - Create Activity - Assign Existing Activity - Start Activity - Reschedule Activity - Complete Activity - Cancel Activity - Convert Lead - Submit Approval - Receive PO ### Event Consumer Matrix Added `BUSINESS_EVENT_CONSUMER_MATRIX` in `src/features/foundation/business-events/matrices.ts`. Consumers are explicitly non-owning: - Timeline - Calendar - Dashboard - Notification - My Day - Relationship Health - Forecast All listed projection consumers are forbidden from mutating source-domain lifecycle state. ### Replay Contracts Added `src/features/foundation/business-events/replay.ts`. Replay is contract-only in EP.1.3: - request must be organization-scoped - dry-run defaults to true - ordering is `occurred_at_then_event_id` - idempotency is required - no replay route or persistent event store was added ### Existing Event Compatibility Added `src/features/foundation/business-events/compatibility.ts`. Existing approval notification event behavior remains untouched. Compatibility aliases map current names to canonical business event names where needed: - `approval.step.approved` -> `approval.step-approved` - `approval.step.rejected` -> `approval.step-rejected` ## Versioning Strategy - Every event includes `schemaVersion`. - Additive optional payload fields can remain on the same event type and schema version when existing consumers are unaffected. - Incompatible semantic changes require a new schema version. - Consumers can declare supported versions per event type. - Unsupported versions are reported by the dispatcher and do not silently process. - Deprecated event definitions must specify `replacementEventType`. ## Ordering And Idempotency Rules - Global ordering across all domains is not guaranteed. - Related events in one operation share `correlationId`. - Child events use `causationId` when one event directly triggers another. - Consumers must not rely on undocumented timing. - Dispatcher duplicate handling is in-memory for EP.1.3 tests and contracts only. - Persistent checkpointing remains a future projection-foundation concern. ## Observability Hooks The dispatch result captures: - event id and type - dispatch status - dispatch duration - subscriber name - subscriber status - subscriber duration - subscriber error message - duplicate and unsupported-version outcomes Structured persistence of these observations is intentionally deferred until persistent event/projection infrastructure is approved. ## Projection Readiness Ready for EP.1.4 to define projection storage and consumers using: - `BusinessEvent` - `BusinessEventConsumer` - `BusinessEventPublisher` - `BusinessEventDispatcher` - event registry definitions - sequence matrix - consumer matrix - replay contract Not implemented in EP.1.3: - Timeline projection - Calendar projection - Dashboard projection replacement - Notification expansion - My Day - Manager Workspace - Executive Workspace - Relationship Health - Forecast projection - Automation engine - external broker - persistent replay engine - projection storage tables ## Verification - `npm run typecheck` - `node --disable-warning=ExperimentalWarning --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test src/features/foundation/business-events/*.test.ts src/features/crm/activities/server/business-events.test.ts` ## Residual Risks - Business events are currently in-process only; no cross-process delivery guarantee exists. - No persistent event store exists, so replay remains a contract and testing surface only. - Subscriber failures will fail publisher dispatch; no production subscriber is registered in EP.1.3. - Existing approval notifications still use the current notification event service and are mapped for compatibility rather than migrated.