Skip to content

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_instances table
  • Automatic Compensation: Rollback on failures with detailed error tracking

Event Structure

All events follow this base structure

typescript
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.

Built with VitePress