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:
- repositoryName - The repository name (e.g., "user-repository")
- changeType - "created", "updated", or "deleted"
- entityId - ID of the changed entity (if available)
- newValue - The new value (nil for deletes)
- oldValue - The previous value (nil for creates)
- timestamp - When the change occurred
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.