Skip to content

CloudEvents

EvidentSource uses the CloudEvents specification as its core event format. CloudEvents is a specification for describing event data in a common way, enabling interoperability across services, platforms, and systems.

CloudEvents provides:

  • Standardization: A vendor-neutral specification backed by the CNCF
  • Interoperability: Easy integration with other CloudEvents-compatible systems
  • Flexibility: Support for various content types and transport protocols
  • Extensibility: Custom attributes for domain-specific needs

Every CloudEvent in EvidentSource must have these attributes:

AttributeTypeDescription
idStringUnique identifier for the event
sourceURI-referenceIdentifies the context in which the event occurred
specversionStringCloudEvents specification version (always “1.0”)
typeStringType of event related to the source

EvidentSource supports these optional CloudEvents attributes:

AttributeTypeDescription
datacontenttypeStringContent type of the data (default: “application/json”)
dataschemaURISchema that the data adheres to
subjectStringSubject of the event in the context of the source
timeTimestampWhen the event occurred (ISO 8601)
dataAnyThe event payload
{
"specversion": "1.0",
"id": "45a8b444-3d5f-4a6e-b55d-1c5e0b2e4a89",
"source": "https://example.com/orders",
"type": "com.example.orders.OrderCreated",
"subject": "order-12345",
"time": "2024-01-15T10:30:00Z",
"datacontenttype": "application/json",
"dataschema": "https://example.com/schemas/order-created/v1",
"data": {
"orderId": "12345",
"customerId": "67890",
"totalAmount": 99.99,
"currency": "USD"
}
}

The source attribute identifies the system or component that generated the event:

  • Use URIs for global uniqueness: https://api.example.com/order-service
  • Or use simple identifiers for internal systems: order-service
  • Be consistent within your domain

The type attribute describes what happened:

  • Use reverse-DNS notation: com.example.orders.OrderCreated
  • Or use simple descriptive names: OrderCreated
  • Include version if needed: com.example.orders.OrderCreated.v2

The subject provides additional context:

  • Typically identifies the entity the event is about
  • Examples: order-12345, customer-67890, product-abc
  • Enables efficient filtering and indexing

The time attribute represents when the event occurred:

  • Use ISO 8601 format with timezone
  • Represents business time (when the event happened in the real world)
  • Different from recordedtime (when EvidentSource stored the event)

The most common format for event data:

{
"specversion": "1.0",
"id": "...",
"source": "inventory-service",
"type": "InventoryUpdated",
"datacontenttype": "application/json",
"data": {
"productId": "SKU-123",
"quantity": 42,
"location": "warehouse-1"
}
}

For binary payloads, use base64 encoding:

{
"specversion": "1.0",
"id": "...",
"source": "document-service",
"type": "DocumentScanned",
"datacontenttype": "application/pdf",
"data_base64": "JVBERi0xLjQKJdPr6eEKMSAwIG9i..."
}

EvidentSource stores events in structured mode:

  • Events are stored as complete CloudEvents objects
  • All attributes are preserved and queryable
  • Enables rich filtering and indexing
  • Use UUIDs for guaranteed uniqueness
  • Never reuse event IDs
  • EvidentSource enforces unique IDs per database
val eventId = UUID.randomUUID().toString()

Choose meaningful source identifiers:

// Good examples
"https://api.acme.com/order-service"
"order-service.production"
"acme.orders"
// Avoid
"service1"
"backend"
"system"

Use consistent, descriptive event types:

// Domain.Entity.Action pattern
"com.acme.orders.OrderCreated"
"com.acme.orders.OrderShipped"
"com.acme.inventory.StockDepleted"
// Simple Entity.Action pattern
"Order.Created"
"Order.Shipped"
"Inventory.Depleted"

Plan for schema changes:

  1. Use dataschema: Reference versioned schemas
  2. Add, don’t remove: New fields should be optional
  3. Version when breaking: Create new event types for incompatible changes
  4. Document changes: Maintain schema documentation

EvidentSource indexes events by key attributes:

// Query by source
EventSelector(stream = "order-service")
// Query by type
EventSelector(eventType = "OrderCreated")
// Query by subject
EventSelector(subject = "order-12345")
// Combine attributes
EventSelector(
stream = "order-service",
eventType = "OrderCreated",
subject = "order-12345"
)

Use CloudEvents attributes for routing:

when (event.type) {
"OrderCreated" -> handleOrderCreated(event)
"OrderShipped" -> handleOrderShipped(event)
"OrderCancelled" -> handleOrderCancelled(event)
}

Filter events based on attributes:

events.filter { event ->
event.source == "order-service" &&
event.type.startsWith("Order") &&
event.time?.isAfter(startDate) == true
}

Use subject for correlation:

// All events for a specific order
val orderEvents = client.queryEvents(
EventQuery(
eventSelection = EventSelection(
selectors = listOf(
EventSelector(subject = "order-12345")
)
)
)
)

EvidentSource automatically adds:

  • recordedtime: When the event was stored
  • revision: The event’s revision number

These are exposed as CloudEvents extensions and can be accessed alongside standard attributes.