Tutorial
In this tutorial, you will build a complete e-commerce specification from scratch. By the end, you will have defined data types, enums, a state machine workflow, visitor capabilities, and autonomous agents — all in one Aexol file.
The spec will model an online store with products, orders, payment processing, and automated notifications. You will write it step by step, validating at each stage.
Step 1: Define Data Types
Start with the core data structures. An e-commerce system needs products, orders, and order items.
Create a file named ecommerce.aexol
type Product {
id: string
name: string
description: string
price: number
inStock: boolean
categories: string[]
}
type Order {
id: string
customerId: string
items: OrderItem[]
total: number
status: string
}
type OrderItem {
productId: string
quantity: number
unitPrice: number
}
Product models what you sell — each product has a name, price, stock flag, and category tags. Order groups items under a customer, and OrderItem links each line item to its product.
Notice that Order.status is currently a plain string. You will replace it with a proper enum in the next step.
Step 2: Add Enums
Replace the loose string status with typed enums. Add a payment method enum too.
Define enums and update Order
enum OrderStatus {
pending
payment_received
processing
shipped
delivered
cancelled
}
enum PaymentMethod {
credit_card
debit_card
paypal
bank_transfer
}
type Order {
id: string
customerId: string
items: OrderItem[]
total: number
status: OrderStatus
paymentMethod: PaymentMethod
}
Now Order.status is restricted to exactly six values. The validator will catch typos like OrderStatus.pendng immediately. The PaymentMethod enum gives you a typed way to track how each order was paid.
Step 3: Define a Workflow
Models how an order moves through the system — from placement to delivery.
Add the OrderFlow workflow
workflow OrderFlow {
initial: pending
pending -> payment_received when payment_confirmed
payment_received -> processing when stock_reserved
processing -> shipped when items_packed
shipped -> delivered when customer_confirms
pending -> cancelled when timeout
payment_received -> cancelled when refund_requested
processing -> cancelled when out_of_stock
}
The initial keyword sets pending as the starting state. Each transition has a when condition that describes what event triggers it. Some states (like pending and payment_received) have multiple possible exits — an order can be cancelled at several points, and processing can cancel if stock runs out.
When generated, this workflow produces a state machine class with canTransitionTo() and transitionTo() methods that enforce these rules at runtime.
Step 4: Define Visitors
Visitors model who can do what. Define customer and admin capabilities.
Add visitors with nested capabilities
visitor Customer {
"browse products"
"place orders" {
"view order history"
"track shipments"
"cancel order"
}
"manage profile" {
"update address"
"update payment methods"
}
}
visitor Admin {
"manage inventory" {
"add products"
"edit products"
"remove products"
}
"view all orders"
"manage customers"
"view reports"
"configure system"
}
Nested capabilities (indented quote blocks) model hierarchical access — "cancel order" is a sub-capability under "place orders". This structure helps code generators produce scoped permission checks and role-based access control.
Step 5: Add Agents
Agents model autonomous services that react to system events.
Add three agents
agent InventoryBot {
"reserve stock"
"release stock"
"update stock levels"
"alert low stock"
}
agent NotificationService {
"send order confirmation"
"send shipping update"
"send delivery notification"
"send cancellation notice"
}
agent PaymentProcessor {
"process payment"
"issue refund"
"verify payment method"
}
Each agent declares capabilities as quoted strings. InventoryBot manages stock levels, NotificationService sends customer emails at each workflow transition, and PaymentProcessor handles money. Agents are not visitors — they represent background services, not user-facing roles.
Step 6: Put It All Together
Here is the complete specification with everything combined:
// ── Data Types ──────────────────────────────────────
type Product {
id: string
name: string
description: string
price: number
inStock: boolean
categories: string[]
}
type Order {
id: string
customerId: string
items: OrderItem[]
total: number
status: OrderStatus
paymentMethod: PaymentMethod
}
type OrderItem {
productId: string
quantity: number
unitPrice: number
}
// ── Enums ───────────────────────────────────────────
enum OrderStatus {
pending
payment_received
processing
shipped
delivered
cancelled
}
enum PaymentMethod {
credit_card
debit_card
paypal
bank_transfer
}
// ── Workflow ────────────────────────────────────────
workflow OrderFlow {
initial: pending
pending -> payment_received when payment_confirmed
payment_received -> processing when stock_reserved
processing -> shipped when items_packed
shipped -> delivered when customer_confirms
pending -> cancelled when timeout
payment_received -> cancelled when refund_requested
processing -> cancelled when out_of_stock
}
// ── Visitors ────────────────────────────────────────
visitor Customer {
"browse products"
"place orders" {
"view order history"
"track shipments"
"cancel order"
}
"manage profile" {
"update address"
"update payment methods"
}
}
visitor Admin {
"manage inventory" {
"add products"
"edit products"
"remove products"
}
"view all orders"
"manage customers"
"view reports"
"configure system"
}
// ── Agents ──────────────────────────────────────────
agent InventoryBot {
"reserve stock"
"release stock"
"update stock levels"
"alert low stock"
}
agent NotificationService {
"send order confirmation"
"send shipping update"
"send delivery notification"
"send cancellation notice"
}
agent PaymentProcessor {
"process payment"
"issue refund"
"verify payment method"
}
Validate it with the CLI to confirm everything checks out:
aexol validate ecommerce.aexol
Then generate code in your target language using Studio.
What's Next
- Language Reference — Complete syntax for types, visitors, roles, workflows, and agents
- Workflows & Recipes — Ready-to-use workflow patterns and best practices
- Code Generation — Generate production-ready code from your spec
Key Takeaways
- Types define your data. Start with them — everything else builds on top.
- Enums replace loose strings with typed, validated constants. Use them in type fields and align them with workflow states.
- Workflows model state machines with explicit transitions. Every transition should have a
whencondition that names the real-world trigger. - Visitors define what each actor can do. Nest capabilities to model hierarchical access patterns.
- Agents represent autonomous background services. Keep them separate from visitors — visitors are roles, agents are services.