← 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.