7.3 KiB
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.mdplans/task-ep.1.3.mddocs/standards/task-catalog.mddocs/standards/project-foundations.mddocs/standards/architecture-rules.mddocs/standards/ui-ux-rules.mddocs/standards/task-review-checklist.mddocs/security/crm-authorization-boundaries.mddocs/implementation/task-ep1.1-activity-domain-foundation-2026-07-10.mddocs/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<TPayload> 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, andcausationId - 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 <entity>.<past-tense-action> 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.tssrc/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.createdactivity.assignedactivity.reassignedactivity.startedactivity.rescheduledactivity.completedactivity.cancelledactivity.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-approvedapproval.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
causationIdwhen 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:
BusinessEventBusinessEventConsumerBusinessEventPublisherBusinessEventDispatcher- 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 typechecknode --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.