212 lines
7.3 KiB
Markdown
212 lines
7.3 KiB
Markdown
# 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<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`, 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 `<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.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.
|