← All seeds
Orders ADL v0.3.1

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.

FieldTypeNotes
iduuidPrimary key
firstNamestringRequired, max 100
lastNamestringRequired, max 100
emailemailRequired, unique
phonephone
createdAtdatetimeAuto-set on create
updatedAtdatetimeAuto-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.

FieldTypeNotes
iduuidPrimary key
skustringRequired, unique, max 50
namestringRequired, max 200
descriptiontext
unitPricedecimalRequired, precision 19 / scale 4, min 0
stockQtyintegerDefault 0
isActivebooleanDefault true
createdAtdatetimeAuto-set on create
updatedAtdatetimeAuto-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).

FieldTypeNotes
iduuidPrimary key
customerIduuidRequired, immutable (FK)
customerNamestringDenormalized display name
statusenumOrderStatus, default “pending”
notestext
shippingAddresscomponentInline Address object
lineItemsrepeaterArray of product line items
discountCodestringMax 50
discountAmountdecimalDefault 0
createdAtdatetimeAuto-set on create
updatedAtdatetimeAuto-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).

FieldTypeNotes
orderIduuidComposite PK part 1, immutable
productIduuidComposite PK part 2, immutable
quantityintegerRequired, min 1
unitPricedecimalRequired, precision 19 / scale 4
createdAtdatetimeAuto-set on create
updatedAtdatetimeAuto-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.

FieldTypeNotes
iduuidPrimary key
codestringRequired, unique, uppercase
typeenumDiscountType (percentage/fixed)
valuedecimalRequired, min 0
maxUsesintegerNull means unlimited
usedCountintegerDefault 0, immutable (engine-managed)
expiresAtdatetime
isActivebooleanDefault true
createdAtdatetimeAuto-set on create
updatedAtdatetimeAuto-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:

ValueLabelColor
pendingPending#f59e0b
confirmedConfirmed#3b82f6
processingProcessing#8b5cf6
shippedShipped#10b981
deliveredDelivered#22c55e
cancelledCancelled#ef4444
refundedRefunded#6b7280

DiscountType

ValueLabel
percentagePercentage
fixedFixed

Shared Objects

  • TimestampcreatedAt (auto on create) and updatedAt (auto on update), merged into all resources.
  • Address — street, city, state, postalCode, country; used as a component in Order.shippingAddress.

Roles and Permissions

RoleDescription
adminFull system access, can manage all resources and delete orders
customerEnd user, can place orders and view own records
staffInternal staff, can view all orders and manage products

Permission matrix (summary):

Resourcelistreadcreateupdatedelete
Customercustomer,admin,staffcustomer,admin,staffauthenticatedcustomer,admin,staffadmin
Product**admin,staffadmin,staffadmin
Ordercustomer,admin,staffcustomer,admin,staffauthenticatedcustomer,admin,staffadmin
OrderItemcustomer,admin,staffcustomer,admin,staffcustomer,admin,staffcustomer,admin,staffcustomer,admin,staff
Discountadmin,staffadmin,staffadminadminadmin

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]

Download bundle