E-Commerce Orders
Order management with customers, products, money/decimal types, component objects and repeaters, computed line totals, and an order-status state machine.
- Resources
- Customer, Product, Order, OrderItem
- Roles
- admin, manager, clerk, customer
- Features (5)
- soft_deleteauditstate_machinepermissionscomputed_fields
E-commerce order management domain demonstrating advanced ADL features including decimal/money types, component objects, repeaters, computed fields, composite primary keys, versioning, bulk import/export, caching, and custom operations.
Resources
Customer
Buyer profile with UUID primary key.
| Field | Type | Notes |
|---|---|---|
| id | uuid | Primary key |
| firstName | string | Required, max 100 |
| lastName | string | Required, max 100 |
| Required, unique | ||
| phone | phone | |
| createdAt | datetime | Auto-set on create |
| updatedAt | datetime | Auto-set on update |
Computed fields:
fullName(virtual) — concatenation of firstName and lastName, calculated on read, never stored.
Features: search
Product
Catalog item with pricing. Read-heavy reference data with TTL caching.
| Field | Type | Notes |
|---|---|---|
| id | uuid | Primary key |
| sku | string | Required, unique, max 50 |
| name | string | Required, max 200 |
| description | text | |
| unitPrice | decimal | Required, precision 19 / scale 4, min 0 |
| stockQty | integer | Default 0 |
| isActive | boolean | Default true |
| createdAt | datetime | Auto-set on create |
| updatedAt | datetime | Auto-set on update |
Features: search, caching (300s TTL), import, export
Order
The primary resource. Stores a complete order with inline shipping address (component) and line items (repeater).
| Field | Type | Notes |
|---|---|---|
| id | uuid | Primary key |
| customerId | uuid | Required, immutable (FK) |
| customerName | string | Denormalized display name |
| status | enum | OrderStatus, default “pending” |
| notes | text | |
| shippingAddress | component | Inline Address object |
| lineItems | repeater | Array of product line items |
| discountCode | string | Max 50 |
| discountAmount | decimal | Default 0 |
| createdAt | datetime | Auto-set on create |
| updatedAt | datetime | Auto-set on update |
Computed fields:
orderTotal(materialized aggregation) — sum of all related OrderItem subtotals. Recalculated on item create/update/delete.
Features: versioning, audit, export
Audit tracking: status, discountCode, discountAmount, notes, shippingAddress
Custom operations:
POST /:id/duplicate— clones an order with a new ID, resets status to pending.POST /:id/apply-discount— validates and applies a discount code from the Discount resource.
OrderItem
Line item in an order. Uses a composite primary key (orderId + productId).
| Field | Type | Notes |
|---|---|---|
| orderId | uuid | Composite PK part 1, immutable |
| productId | uuid | Composite PK part 2, immutable |
| quantity | integer | Required, min 1 |
| unitPrice | decimal | Required, precision 19 / scale 4 |
| createdAt | datetime | Auto-set on create |
| updatedAt | datetime | Auto-set on update |
Computed fields:
subtotal(materialized) — quantity * unitPrice, recalculated on write when quantity or unitPrice changes.
Discount
Coupon or discount code applied to orders via the apply-discount custom operation.
| Field | Type | Notes |
|---|---|---|
| id | uuid | Primary key |
| code | string | Required, unique, uppercase |
| type | enum | DiscountType (percentage/fixed) |
| value | decimal | Required, min 0 |
| maxUses | integer | Null means unlimited |
| usedCount | integer | Default 0, immutable (engine-managed) |
| expiresAt | datetime | |
| isActive | boolean | Default true |
| createdAt | datetime | Auto-set on create |
| updatedAt | datetime | Auto-set on update |
Relationships
Customer 1──* Order (Customer.orders hasMany Order)
Order *──1 Customer (Order.customer belongsTo Customer)
Order 1──* OrderItem (Order.orderItems hasMany OrderItem, cascade delete)
OrderItem *──1 Order (OrderItem.order belongsTo Order, cascade delete)
OrderItem *──1 Product (OrderItem.product belongsTo Product)
Enums
OrderStatus
A seven-state lifecycle for orders:
| Value | Label | Color |
|---|---|---|
| pending | Pending | #f59e0b |
| confirmed | Confirmed | #3b82f6 |
| processing | Processing | #8b5cf6 |
| shipped | Shipped | #10b981 |
| delivered | Delivered | #22c55e |
| cancelled | Cancelled | #ef4444 |
| refunded | Refunded | #6b7280 |
DiscountType
| Value | Label |
|---|---|
| percentage | Percentage |
| fixed | Fixed |
Shared Objects
- Timestamp —
createdAt(auto on create) andupdatedAt(auto on update), merged into all resources. - Address — street, city, state, postalCode, country; used as a component in Order.shippingAddress.
Roles and Permissions
| Role | Description |
|---|---|
| admin | Full system access, can manage all resources and delete orders |
| customer | End user, can place orders and view own records |
| staff | Internal staff, can view all orders and manage products |
Permission matrix (summary):
| Resource | list | read | create | update | delete |
|---|---|---|---|---|---|
| Customer | customer,admin,staff | customer,admin,staff | authenticated | customer,admin,staff | admin |
| Product | * | * | admin,staff | admin,staff | admin |
| Order | customer,admin,staff | customer,admin,staff | authenticated | customer,admin,staff | admin |
| OrderItem | customer,admin,staff | customer,admin,staff | customer,admin,staff | customer,admin,staff | customer,admin,staff |
| Discount | admin,staff | admin,staff | admin | admin | admin |
Seed Data
The seed file (seed.yaml) provisions:
- 3 roles: admin, customer, staff
- 5 users: admin (Admin123!), alice, bob, carol, diana (Demo123!)
- 5 products: WIDGET-001, WIDGET-002, GADGET-001, GADGET-002, SERVICE-001
- 2 discounts: SAVE10 (10% off), FLAT5 ($5 off)
- 2 customers: Alice Johnson, Bob Smith
- 4 orders: covering delivered, pending, confirmed, and cancelled statuses with varying line items
Usage
Point your kalosd config at this seed:
{
"adl": {
"domain_file": "seeds/orders/domain.yaml"
},
"seeder": {
"seed_file": "seeds/orders/seed.yaml"
}
} Domain definition
View raw (497 lines)Show domain.yaml
# seeds/orders/domain.yaml
#
# Order Management System — ADL Domain Definition
# ADL version: 0.3.1
#
# Resources: Customer, Product, Order, OrderItem, Discount
# Relations: Order belongsTo Customer
# Order hasMany OrderItem (cascade delete)
# OrderItem belongsTo Order
# OrderItem belongsTo Product
# Customer hasMany Order
#
# ADL features exercised:
# Phase 1 — CRUD generation, REST route mapping, RBAC permissions
# Phase 6 — hasMany, belongsTo, ?include=
# Phase 7 — filter, sort, paginate, search, count
# Phase 8 — Rich types: decimal, money, email, phone, datetime, uuid
# Phase 9 — $merge (Timestamp), $ref enums/objects
# Phase 10 — UUID primary keys, composite primary key (OrderItem)
# Phase 12 — Audit trail on Order
# Phase 14 — Field-level permissions, owner checks
#
# New features (first exercised in POC-03):
# component — Shipping address inline on Order
# repeater — Line items stored inline on Order
# computed — Virtual (Customer.fullName), materialized (OrderItem.subtotal),
# aggregation (Order.orderTotal)
# versioning — Full version history on Order
# export — Bulk CSV export of Orders and Products
# import — Bulk product catalog import
# caching — TTL read cache on Product
# custom ops — POST /orders/:id/duplicate, POST /orders/:id/apply-discount
# compositePK — OrderItem keyed by (orderId, productId)
domain:
name: orders
version: "1.0.0"
description: >
Order management system demonstrating advanced ADL features: decimal/money
types, component objects, repeaters, computed fields (virtual, materialized,
aggregation), composite primary keys, versioning, bulk import/export,
caching, and custom operations.
api: {}
# ─── Shared objects ────────────────────────────────────────────
objects:
Timestamp:
createdAt: { type: datetime, autoNow: create }
updatedAt: { type: datetime, autoNow: update }
Address:
street: { type: string, required: true, maxLength: 255 }
city: { type: string, required: true, maxLength: 100 }
state: { type: string, maxLength: 100 }
postalCode: { type: string, maxLength: 20 }
country: { type: country, default: "US" }
# ─── Shared enums ──────────────────────────────────────────────
enums:
OrderStatus:
values:
pending:
label: "Pending"
description: "Order placed, awaiting confirmation"
color: "#f59e0b"
confirmed:
label: "Confirmed"
description: "Order confirmed, preparing for processing"
color: "#3b82f6"
processing:
label: "Processing"
description: "Order is being prepared and packed"
color: "#8b5cf6"
shipped:
label: "Shipped"
description: "Order has been shipped"
color: "#10b981"
delivered:
label: "Delivered"
description: "Order successfully delivered"
color: "#22c55e"
cancelled:
label: "Cancelled"
description: "Order was cancelled"
color: "#ef4444"
refunded:
label: "Refunded"
description: "Order was refunded"
color: "#6b7280"
DiscountType:
values:
percentage:
label: "Percentage"
description: "Discount as a percentage of the total"
fixed:
label: "Fixed"
description: "Fixed amount discount"
# ─── Resources ─────────────────────────────────────────────────
resources:
# ╔══════════════════════════════════════════════════════════════╗
# ║ Customer ║
# ╚══════════════════════════════════════════════════════════════╝
Customer:
description: >
Buyer profile. Demonstrates the virtual computed field feature:
fullName is calculated on read from firstName + lastName and is
never stored in the database.
object:
id:
type: uuid
primaryKey: true
firstName:
type: string
required: true
maxLength: 100
lastName:
type: string
required: true
maxLength: 100
email:
type: email
required: true
unique: true
phone:
type: phone
$merge:
- { $ref: '#/objects/Timestamp' }
computed:
fullName:
type: string
formula: "concat(firstName, ' ', lastName)"
stored: false
description: "Virtual field — calculated on read, not stored in DB"
relationships:
orders:
type: hasMany
target: Order
foreignKey: customerId
indexes:
- fields: [email]
description: "Unique email lookup"
- fields: [lastName, firstName]
description: "Sort customers by name"
features:
search: true
permissions:
list: [customer, admin, staff]
read: [customer, admin, staff]
create: [authenticated]
update: [customer, admin, staff]
delete: [admin]
# ╔══════════════════════════════════════════════════════════════╗
# ║ Product ║
# ╚══════════════════════════════════════════════════════════════╝
Product:
description: >
Catalog item with pricing. Demonstrates caching (read-heavy
reference data with TTL), bulk import, and export features.
object:
id:
type: uuid
primaryKey: true
sku:
type: string
required: true
unique: true
maxLength: 50
name:
type: string
required: true
maxLength: 200
description:
type: text
unitPrice:
type: decimal
precision: 19
scale: 4
required: true
min: 0
stockQty:
type: integer
default: 0
isActive:
type: boolean
default: true
$merge:
- { $ref: '#/objects/Timestamp' }
indexes:
- fields: [sku]
description: "Unique SKU lookup"
- fields: [isActive]
description: "Filter active/inactive products"
- fields: [unitPrice]
description: "Sort and range-query by price"
features:
search: true
caching: true
cacheTtlSeconds: 300
import: true
export: true
permissions:
list: ["*"]
read: ["*"]
create: [admin, staff]
update: [admin, staff]
delete: [admin]
# ╔══════════════════════════════════════════════════════════════╗
# ║ Order ║
# ╚══════════════════════════════════════════════════════════════╝
Order:
description: >
The primary resource. Demonstrates component (shippingAddress),
repeater (lineItems), computed aggregation (orderTotal), versioning,
audit, export, and custom operations.
object:
id:
type: uuid
primaryKey: true
customerId:
type: uuid
required: true
immutable: true
customerName:
type: string
maxLength: 200
description: "Denormalized customer name for display"
status:
$ref: '#/enums/OrderStatus'
default: pending
notes:
type: text
# Component — stored inline as JSON column, no separate table
shippingAddress:
type: component
object: { $ref: '#/objects/Address' }
# Repeater — ordered array stored as JSON column
lineItems:
type: repeater
sortable: false
object:
productId: { type: uuid, required: true }
productName: { type: string, required: true }
quantity: { type: integer, required: true, min: 1 }
unitPrice: { type: decimal, precision: 19, scale: 4, required: true }
discountCode:
type: string
maxLength: 50
discountAmount:
type: decimal
precision: 19
scale: 4
default: "0"
$merge:
- { $ref: '#/objects/Timestamp' }
computed:
orderTotal:
type: decimal
formula: "sum(orderItems.subtotal)"
stored: true
updateOn: [orderItems.create, orderItems.update, orderItems.delete]
description: "Aggregation — sum of all order item subtotals"
relationships:
customer:
type: belongsTo
target: Customer
foreignKey: customerId
orderItems:
type: hasMany
target: OrderItem
foreignKey: orderId
onDelete: cascade
indexes:
- fields: [customerId]
description: "List orders by customer"
- fields: [status]
description: "Filter orders by status"
- fields: [createdAt]
description: "Sort orders by date"
- fields: [customerId, status]
description: "Composite: customer orders by status"
features:
versioning: true
audit: true
export: true
audit:
track: [status, discountCode, discountAmount, notes, shippingAddress]
exclude: [updatedAt]
# validation:
# discountNotExceedTotal:
# rule: "discountAmount <= (orderTotal ?? 0)"
# message: "Discount cannot exceed order total"
# ─── Custom operations ──────────────────────────────────────
operations:
duplicate:
method: POST
path: "/:id/duplicate"
guards: [customer, admin, staff]
description: >
Creates a new Order copying all fields from the source order.
New ID generated, status reset to pending, timestamps reset.
applyDiscount:
method: POST
path: "/:id/apply-discount"
guards: [customer, admin, staff]
payload:
code: { type: string, required: true }
description: >
Validates the discount code exists, is active, not expired,
not exceeded max uses. Applies discountAmount to the order
and increments discount.usedCount.
permissions:
list: [customer, admin, staff]
read: [customer, admin, staff]
create: [authenticated]
update: [customer, admin, staff]
delete: [admin]
# ╔══════════════════════════════════════════════════════════════╗
# ║ OrderItem ║
# ╚══════════════════════════════════════════════════════════════╝
OrderItem:
description: >
A line item in an order. Demonstrates composite primary key
(orderId + productId) and materialized computed field (subtotal
is recalculated and stored whenever quantity or unitPrice changes).
object:
orderId:
type: uuid
compositePkOrder: 1
immutable: true
productId:
type: uuid
compositePkOrder: 2
immutable: true
quantity:
type: integer
required: true
min: 1
unitPrice:
type: decimal
precision: 19
scale: 4
required: true
$merge:
- { $ref: '#/objects/Timestamp' }
compositePrimaryKey: [orderId, productId]
computed:
subtotal:
type: decimal
formula: "quantity * unitPrice"
stored: true
updateOn: [quantity, unitPrice]
description: "Materialized — recalculated on write when quantity or unitPrice changes"
relationships:
order:
type: belongsTo
target: Order
foreignKey: orderId
onDelete: cascade
product:
type: belongsTo
target: Product
foreignKey: productId
indexes:
- fields: [orderId]
description: "List all items for an order"
- fields: [productId]
description: "Find all orders containing a product"
permissions:
list: [customer, admin, staff]
read: [customer, admin, staff]
create: [customer, admin, staff]
update: [customer, admin, staff]
delete: [customer, admin, staff]
# ╔══════════════════════════════════════════════════════════════╗
# ║ Discount ║
# ╚══════════════════════════════════════════════════════════════╝
Discount:
description: >
Coupon or discount code that can be applied to orders via the
apply-discount custom operation.
object:
id:
type: uuid
primaryKey: true
code:
type: string
required: true
unique: true
uppercase: true
maxLength: 50
type:
$ref: '#/enums/DiscountType'
required: true
value:
type: decimal
precision: 19
scale: 4
required: true
min: 0
maxUses:
type: integer
description: "Null means unlimited uses"
usedCount:
type: integer
default: 0
immutable: true
description: "Incremented by the apply-discount custom operation"
expiresAt:
type: datetime
isActive:
type: boolean
default: true
$merge:
- { $ref: '#/objects/Timestamp' }
indexes:
- fields: [code]
description: "Unique code lookup"
- fields: [isActive]
description: "Filter active/inactive discounts"
permissions:
list: [admin, staff]
read: [admin, staff]
create: [admin]
update: [admin]
delete: [admin]