← Back to Documentation

Event-Driven Architecture

ARO uses direct event dispatch to connect feature sets. No complex pub/sub patterns, no subscriptions, no event streams. Just emit an event to a feature set by name.

The ARO Philosophy

Events should be simple. Emit to a feature set name, receive in the <event> variable. That's it. No configuration, no subscription management, no event bus complexity.

Event Emission

Use the <Emit> action to dispatch events to other feature sets. The target is simply the feature set name.

(* Creating a user and emitting events *)
(Create User: Registration) {
    <Extract> the <data> from the <request: body>.
    <Create> the <user: User> with <data>.
    <Store> the <user> in the <user-repository>.

    (* Emit to a specific feature set by name *)
    <Emit> to <Send Welcome Email> with {
        email: <user: email>,
        name: <user: name>
    }.

    <Return> a <Created: status> with <user>.
}

Receiving Events

Feature sets receive events in the <event> variable. Access fields using the familiar qualifier syntax.

(Send Welcome Email: Notifications) {
    <Extract> the <email> from the <event: email>.
    <Extract> the <name> from the <event: name>.

    <Send> the <welcome-email> to the <email> with {
        subject: "Welcome!",
        body: "Hello ${<name>}, welcome to our service!"
    }.

    <Return> an <OK: status> for the <notification>.
}

Multiple Event Handlers

A single action can emit to multiple feature sets, enabling clean separation of concerns. Each handler runs independently.

(createOrder: E-Commerce) {
    <Extract> the <userId> from the <request: body>.
    <Extract> the <items> from the <request: body>.

    <Create> the <order: Order> with {
        id: <generated-id>,
        userId: <userId>,
        items: <items>,
        status: "placed"
    }.

    <Store> the <order> in the <order-repository>.

    (* Dispatch events to multiple handlers *)
    <Emit> to <Send Order Confirmation> with <order>.
    <Emit> to <Update Inventory> with { items: <items> }.
    <Emit> to <Track Revenue> with { amount: <order: total> }.

    <Return> a <Created: status> with <order>.
}

Event Handlers

Each handler is a standard feature set that receives the event data:

(Send Order Confirmation: Notifications) {
    <Extract> the <orderId> from the <event: id>.
    <Extract> the <userEmail> from the <event: userEmail>.

    <Send> the <email> to the <userEmail> with {
        subject: "Order Confirmed",
        body: "Your order ${<orderId>} has been placed."
    }.

    <Return> an <OK: status> for the <confirmation>.
}

(Update Inventory: Inventory Management) {
    <Extract> the <items> from the <event: items>.

    for each <item> in <items> {
        <Decrement> the <stock> for the <item: productId>.
    }

    <Return> an <OK: status> for the <inventory>.
}

(Track Revenue: Analytics) {
    <Extract> the <amount> from the <event: amount>.
    <Increment> the <daily-revenue> by <amount>.
    <Return> an <OK: status> for the <analytics>.
}

Why This Approach?

Simplicity

No event bus configuration. No subscription management. No event type hierarchies. Just emit to a name, receive in <event>.

Clarity

The target feature set is explicit in the code. You can see exactly where events go without tracing through configuration files.

Decoupling

Event emitters don't need to know how handlers are implemented. Handlers can be added, removed, or modified independently.

Repository Observers

Repository observers are a special kind of event handler that automatically react to repository changes. When data is stored, updated, or deleted from a repository, observers receive the change details including both old and new values.

Observer Syntax

Create an observer by naming your feature set's business activity as {repository-name} Observer:

(* Audit all user changes *)
(Audit Changes: user-repository Observer) {
    <Extract> the <changeType> from the <event: changeType>.
    <Extract> the <newValue> from the <event: newValue>.
    <Extract> the <oldValue> from the <event: oldValue>.

    <Log> <changeType> to the <console>.
    <Return> an <OK: status> for the <audit>.
}

Event Payload

Observers receive an event with the following fields:

Deleting from Repositories

Use the <Delete> action with a where clause to remove items:

(deleteUser: User API) {
    <Extract> the <userId> from the <pathParameters: id>.
    <Delete> the <user> from the <user-repository> where id = <userId>.
    <Return> an <OK: status> with { deleted: <userId> }.
}

Learn More

See the full event dispatch specification in ARO-0012: Simple Event Dispatch and repository observers in ARO-0032: Repositories.