Events Overview
Event-Driven Architecture
FundlyHub uses a comprehensive event system to track all state changes across the platform. Events are immutable, versioned, and provide a complete audit trail.
What are Domain Events?
Domain events represent significant occurrences within the Fundly platform. Each event is:
- Immutable: Once published, events cannot be changed
- Versioned: Events follow semantic versioning for backward compatibility
- Timestamped: Each event includes precise Unix timestamp
- Correlated: Events can be linked via correlation IDs for tracing
- Validated: All events are validated against Zod schemas
Event Domains
Events are organized into six domain categories (54 total events)
Admin Events
User management (suspend, delete), campaign approval/rejection, featuring, role assignment
7 admin action events
Event Infrastructure
Hybrid Event Bus
The system uses a distributed event-driven architecture with CQRS and Saga orchestration:
- Events Database: All events persisted to the dedicated Events PostgreSQL database
- Redis Streams: Distributed event streaming for scalable processing
- Background Workers: Dedicated Node.js processors for async event handling
- Event Middleware: Logging, validation, idempotency, circuit breakers
CQRS Read Models
Optimized projection tables in the Analytics Database for fast reads:
- campaign_summary_projection: Denormalized campaign data for list views
- campaign_stats_projection: Real-time aggregated statistics and analytics
- campaign_search_projection: Full-text search with tsvector indexing
Saga Orchestration
Complex workflows managed by saga patterns with compensation logic:
- CampaignCreationSaga: Orchestrates multi-step campaign creation (validation → creation → role update → projections)
- Saga State Management: Tracked in
saga_instancestable - Automatic Compensation: Rollback on failures with detailed error tracking
Event Structure
All events follow this base structure
interface DomainEvent<T extends EventPayload> {
readonly id: string; // UUID v4
readonly type: string; // e.g., 'user.registered'
readonly timestamp: number; // Unix timestamp
readonly version: string; // Semantic version
readonly correlationId?: string; // For event tracing
readonly causationId?: string; // Event that caused this
readonly metadata?: Record<string, any>;
readonly payload: T; // Domain-specific data
}Backend Development Note
For developers working on backend, event publishing and subscription is handled via the EventBus service. See the Backend Architecture documentation for more details.