Table of Contents

Tagging

Tags provide a flexible way to organize, categorize, and identify events and observers (reactors, reducers, projections, read models) within Chronicle. By applying the [Tag] or [Tags] attribute, you can assign one or more tags that describe the purpose, domain, or context of your artifacts.

Note: Both [Tag] and [Tags] attributes can be used interchangeably. Use whichever feels more natural, or mix them - all tags will be merged together.

Overview

Tags are strings that can be attached to:

  • Events - both statically (via attributes) and dynamically (when appending)
  • Reactors - for organizing and filtering reactive behaviors
  • Reducers - for categorizing state aggregation logic
  • Projections - for organizing view models and read models
  • Read Models - for categorizing data models

Tags are stored with event metadata and observer definitions, enabling powerful filtering, querying, and organizational capabilities.

Tagging Events

Events can be tagged in two ways: statically using attributes, or dynamically when appending events.

Static Event Tags

Apply the [Tag] or [Tags] attribute to your event types to assign static tags that will always be associated with that event type:

using Cratis.Chronicle;

[Tag("analytics", "user-action")]
public record UserLoggedIn(string UserId, DateTimeOffset LoggedInAt);

// Or using Tags attribute (plural) for convenience
[Tags("analytics", "user-action")]
public record UserLoggedIn(string UserId, DateTimeOffset LoggedInAt);

// Mix both Tag and Tags attributes
[Tag("security")]
[Tags("audit")]
public record UserPasswordChanged(string UserId, DateTimeOffset ChangedAt);

Dynamic Event Tags

When appending events, you can provide additional tags that will be merged with any static tags:

await eventSequence.Append(
    eventSourceId,
    new UserLoggedIn("user123", DateTimeOffset.UtcNow),
    tags: ["production", "critical"]);

In this example, the event will have four tags: ["analytics", "user-action", "production", "critical"].

Tags in Event Context

All tags (both static and dynamic) are available on the EventContext when processing events:

public class UserAnalyticsReducer : IReducerFor<UserAnalytics>
{
    public UserAnalytics On(UserLoggedIn @event, EventContext context)
    {
        // Access tags from the event context
        if (context.Tags.Contains("critical"))
        {
            // Handle critical events differently
        }
        
        return analytics;
    }
}

Tagging Observers

Observers (reactors, reducers, and projections) can be tagged to organize and categorize them:

Single Tag

[Tag("Notifications")]
public class OrderConfirmationReactor { }

Multiple Tags (Single Attribute)

You can use either [Tag] or [Tags] (plural) for convenience:

[Tag("Notifications", "Customer", "Email")]
public class CustomerNotificationReactor { }

// Or using Tags attribute (plural)
[Tags("Notifications", "Customer", "Email")]
public class CustomerNotificationReactor { }

Multiple Tags (Multiple Attributes)

[Tag("Integration")]
[Tag("ExternalAPI")]
[Tag("Inventory")]
public class InventorySyncReactor { }

Mixed Approach

You can mix both [Tag] and [Tags] attributes - all tags will be merged:

[Tag("Notifications", "SMS")]
[Tags("Customer")]
public class SmsNotificationReactor { }

// Or mix single and multiple attributes
[Tag("Integration")]
[Tags("ExternalAPI", "Inventory")]
public class InventorySyncReactor { }

Tagging Read Models

Read models and projections can also be tagged:

[Tag("Reporting", "Analytics")]
public class SalesReport
{
    public decimal TotalSales { get; set; }
    public int OrderCount { get; set; }
}

Best Practices

  • Use meaningful names: Choose tag names that clearly describe the purpose or domain
  • Be consistent: Establish tag naming conventions across your organization
  • Don't over-tag: Apply only relevant tags; too many can reduce their usefulness
  • Group related artifacts: Use tags to group events and observers that serve similar purposes
  • Consider hierarchies: Use dot notation for hierarchical tags (e.g., "customer.registration", "customer.profile")

Common Tagging Patterns

Here are some common patterns for organizing tags:

By Domain

[Tag("Sales")]
[Tag("Inventory")]
[Tag("Customer")]
[Tag("Shipping")]

By Purpose

[Tag("Analytics")]
[Tag("Reporting")]
[Tag("Integration")]
[Tag("Alerting")]
[Tag("Monitoring")]
[Tag("Automation")]

By Integration Type

[Tag("Notifications")]
[Tag("ExternalAPI")]
[Tag("MessageQueue")]
[Tag("FileSystem")]

By Communication Channel

[Tag("Email")]
[Tag("SMS")]
[Tag("Push")]
[Tag("Webhook")]

By Stakeholder

[Tag("Customer")]
[Tag("Operations")]
[Tag("Finance")]
[Tag("Support")]
[Tag("Executive")]

By Environment or Context

// Dynamic tags when appending
tags: ["production", "critical"]
tags: ["development", "testing"]
tags: ["migration", "batch-process"]

Using Tags

Tags stored in the event store and observer definitions can be used for:

  • Filtering and searching for specific events or observers
  • Organizing artifacts in administrative interfaces
  • Generating documentation about your system
  • Managing deployments by tag
  • Monitoring and alerting based on tag groups
  • Controlling activation of observers by tag
  • Analyzing event patterns and flows
  • Creating tag-based subscriptions or filters

Note: The specific querying and filtering capabilities depend on your Chronicle setup and tooling.