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.