Skip to content
EventFabric CQRS Framework

Events

Events represent facts - things that have already happened in the system.

Events are immutable records of state changes that occurred in the application. They enable event-driven architectures, event sourcing, and asynchronous processing.

An in Depth Example

This guide also has an in depth example of a working application built with EventFabric. Combining DDD, CQRS and Event Sourcing.

Check out the In Depth Example page to learn how everything is connected and works out in a real-world application.

  • Immutable Facts: Events represent things that already happened and cannot be changed
  • Past Tense: Event names use past tense (e.g., “UserInvited”, not “InviteUser”)
  • Observable: Other parts of the system can subscribe and react to events
  • Type-Safe: Events are fully typed and validated using Zod

An event in EventFabric follows the CloudEvents specification and consists of:

type Event<TData = unknown> = {
    specversion: "1.0";
    id: string;
    correlationid: string;
    time: string;
    source: string;
    type: string;
    subject: string;
    data: TData;
    datacontenttype?: string;
    dataschema?: string;
};
PropertyDescription
specversionThe CloudEvents specification version (always '1.0')
idA globally unique identifier for the event
correlationidA unique identifier to correlate this event with related messages
timeISO 8601 timestamp when the event was created
sourceA URI reference identifying the system creating the event
typeThe event type following CloudEvents naming (e.g., at.overlap.nimbus.user-invited)
subjectAn identifier for the entity the event is about (e.g., /users/123)
dataThe event payload containing the business data
datacontenttypeOptional MIME type of the data (defaults to application/json)
dataschemaOptional URL to the schema the data adheres to

Unlike commands and queries, events require a subject field.
Events use subjects to organize and identify the entities they relate to:

// Subject examples
"/users/123"; // Specific user
"/orders/456"; // Specific order
"/users/123/orders/456"; // Order belonging to a user

EventFabric provides a base Zod schema for validating events:

import { eventSchema } from "@eventfabric-cqrs/core";
import { z } from "zod";

// Extend the base schema with your specific event type and data
const userInvitedEventSchema = eventSchema.extend({
    type: z.literal("at.overlap.nimbus.user-invited"),
    data: z.object({
        _id: z.string(),
        email: z.string(),
        firstName: z.string(),
        lastName: z.string(),
    }),
});

type UserInvitedEvent = z.infer<typeof userInvitedEventSchema>;

You can create events using the createEvent() helper:

import { createEvent } from "@eventfabric-cqrs/core";
import { UserInvitedEvent } from "./userInvited.event.ts";

const event = createEvent<UserInvitedEvent>({
    type: "at.overlap.nimbus.user-invited",
    source: "nimbus.overlap.at",
    correlationid: command.correlationid,
    subject: `/users/${userState._id}`,
    data: userState,
});

The createEvent() helper automatically generates default values for:

  • id - A unique ULID
  • correlationid - A unique ULID (if not provided)
  • time - Current ISO timestamp
  • specversion - Always '1.0'
  • datacontenttype - Defaults to 'application/json'

Event names should describe what happened, not what should happen:

// ✅ Good - Past tense
UserInvitedEvent;
OrderShippedEvent;
PaymentProcessedEvent;

// ❌ Bad - Imperative
InviteUserEvent;
ShipOrderEvent;
ProcessPaymentEvent;

Always pass correlation IDs from commands to events for tracing:

const event = createEvent<UserInvitedEvent>({
    type: USER_INVITED_EVENT_TYPE,
    source: "nimbus.overlap.at",
    correlationid: command.correlationid, // Always propagate
    data: state,
});

Subjects should be hierarchical and meaningful:

// ✅ Good - Hierarchical and clear
`/users/${userId}``/users/${userId}/orders/${orderId}``/organizations/${orgId}/members/${memberId}` // ❌ Bad - Flat and unclear
`user-${userId}``order_${orderId}`;

Events are published and subscribed to using the EventBus. See the EventBus documentation for details on publishing and subscribing to events.