Learn · 02 of 5

The four patterns

Four recurring causal shapes organize Event Modeling workflows.

PatternCore questionTypical flowHuman?External boundary?HCL workflow
State ChangeWhat does someone want to change?Screen/API → Command → EventOftenNo requirementstate_change
State ViewWhat does someone need to know?Event → Read Model → ScreenOftenNo requirementstate_view
AutomationWhat should the system do next by itself?Internal Event → Read Model/Processor → Command → EventNoNo external event inputautomation
TranslationHow is another context's fact translated into the model's language?External Event → Read Model/Processor → Command → Internal EventNoYestranslation

Quick check: which pattern turns intent into fact, and which turns facts into an answer?

State Change

A user or other trigger wants something to happen. The system evaluates the Command. If accepted, one or more Events record the resulting facts.

Screen / API -> Command -> Event actor "scheduler" { auth_required = true } bounded_context "appointments" { aggregate "appointment" { } event "appointment_added" { aggregate = aggregate.appointment } } state_change "schedule_appointment" { screen "schedule_appointment_ui" { actor = actor.scheduler to = [command.add_appointment] } command "add_appointment" { aggregate = aggregate.appointments.appointment to = [event.appointments.appointment_added] } }

The bounded context owns the Event. The workflow references it. An API-triggered Command can use api_endpoint instead of a Screen.

State View

Facts already exist. A Read Model folds or interprets those facts so a user or API can answer one question.

Event -> Read Model -> Screen actor "calendar_user" { auth_required = true } bounded_context "appointments" { event "appointment_added" { } } state_view "view_calendar" { readmodel "calendar" { question = "Which appointments are on the calendar?" from = [event.appointments.appointment_added] to = [screen.calendar_ui] } screen "calendar_ui" { actor = actor.calendar_user } }

Catalog Event to Read Model is written as readmodel.from. Read Model to Screen is written as readmodel.to.

Scenario: GIVEN Event(s) → THEN Read Model.

Automation

The system reacts to its own internal facts and issues a new Command without a user screen.

Internal Event -> Read Model -> Processor -> Command -> Event bounded_context "appointments" { event "appointment_added" { } } bounded_context "weather" { event "weather_predicted_for_appointment" { } } automation "add_weather_forecast" { readmodel "appointments_without_weather_forecast" { question = "Which appointments still need a weather forecast?" from = [event.appointments.appointment_added] to = [processor.weather_processor] } processor "weather_processor" { to = [command.add_weather_forecast] } command "add_weather_forecast" { to = [event.weather.weather_predicted_for_appointment] } }

An Automation consumes internal Events. External input belongs in a Translation.

Translation

Another context or external system speaks in its own language. A Translation takes an external fact and turns it into a Command/Event in the receiving context's language.

External Event -> Read Model / Processor -> Command -> Internal Event system "weather_provider" { external = true } bounded_context "weather_provider" { external = true owner = system.weather_provider event "weather_forecast_changed" { } } bounded_context "weather" { event "updated_weather_prediction" { } } translation "translate_weather_change" { readmodel "changed_predictions" { question = "Which external weather predictions changed?" from = [event.weather_provider.weather_forecast_changed] to = [processor.translator] } processor "translator" { to = [command.translate_changed_weather] } command "translate_changed_weather" { to = [event.weather.updated_weather_prediction] } }

A Translation consumes an Event from an external bounded context. A Processor may receive that Event directly when no Read Model is needed.