Skip to content

Rules

Rules are event-driven automation components that react to system events in Hantera. They enable you to validate state changes, enforce business logic, and trigger automated workflows.

What are Rules?

A rule is a component that executes when specific events occur in the system. Rules can:

  • Validate operations before they complete (prevent invalid states)
  • Automate workflows when entities change
  • Enforce business logic across the platform
  • Integrate with external systems via effects

Unlike Jobs which are time-triggered, rules are event-triggered - they run automatically when specific system events occur.

INFO

Current Focus: Available hooks currently focus on actor lifecycle events (order created, payment captured, etc.). The rule system is extensible and may support additional event types in the future, such as file operations, registry changes, and other resource events.

How Rules Work

Rules follow a three-step pattern:

  1. Hook Triggers: A system event occurs (e.g., order created)
  2. Component Evaluates: Rule component receives event data and evaluates conditions
  3. Effects Execute: Component returns effects to execute (commands, validations, integrations)

INFO

Rules use components with the rule runtime, which has more capabilities than the discount runtime but less than the reactor runtime. See Runtime Reference for details on what's available.

Simple Example: Order Confirmation Email

Here's a complete example that sends an email when an order is created:

  1. Create the rule component:

    filtrera
    //order-confirmation.hrule
    import 'resources'
    
    // 'input' is a special parameter and the designated type determines when/if the rule will evaluate:
    param input: OnOrderCreated
    
    let customerEmail = input.order.invoiceAddress.email
    
    from customerEmail match
      /@/ |> 
        {
         effect = 'sendEmail'
          to = email
          subject = $'Order #{input.order.orderNumber} Confirmed'
          body = {
            html = $'<h1>Thank you for your order!</h1><p>Order number: {input.order.orderNumber}</p>'
          }
          category = 'order_confirmation'
          dynamic = {
            orderId = input.order.orderId
          }
        }
      ]
  2. Deploy via manifest:

    yaml
    uri: /resources/rules/order-confirmation
    spec:
      codeFile: order-confirmation.hrule
  3. Apply the manifest:

    bash
    h_ manage apply h_manifest.yaml

Now every time an order is created, the customer receives a confirmation email automatically.

Rule Hooks

Rules respond to actor lifecycle events called hooks. Hooks are categorized by timing and actor type:

Hook Timing

Before Hooks (OnXxxBeforeCreated, OnXxxBeforeDeleted):

  • Execute before the operation completes
  • Can prevent the operation with validation errors
  • Changes aren't yet persisted

After Hooks (OnXxxCreated, OnXxxDeleted):

  • Execute after the operation completes
  • Changes are persisted
  • Can trigger side effects and automation

Command Hooks (OnXxxCommands):

  • Execute when commands are applied
  • Can add additional commands
  • Useful for cascading logic

Available Hooks

Currently available hooks focus on actor lifecycle events:

  • Order: 6 hooks (BeforeCreated, Created, BeforeDeleted, Deleted, Commands, Journal)
  • Payment: 7 hooks (BeforeCreated, Created, BeforeDeleted, Deleted, Commands, Capture, Journal)
  • Ticket: 8 hooks (BeforeCreated, Created, BeforeDeleted, Deleted, Commands, Complete, Rejected)
  • Sku: 5 hooks (BeforeCreated, Created, BeforeDeleted, Deleted, Commands)
  • Asset: 5 hooks (BeforeCreated, Created, BeforeDeleted, Deleted, Commands)

Additional hooks for other resource types (files, registry, etc.) may be added in the future.

See all hooks →

Rule Effects

Rules return effects - instructions for what should happen.

WARNING

Effect Availability: Not all effects work in all hooks. Before hooks typically support validation and commands, while after hooks support broader effects like messageActor and scheduleJob. Check individual hook documentation in the Runtime Reference to see which effects are supported in each context.

Effects include:

Actor Commands

Apply commands to actors:

  • orderCommand - Modify orders
  • paymentCommand - Modify payments
  • ticketCommand - Modify tickets
  • skuCommand - Modify SKUs
  • assetCommand - Modify assets

System Operations

  • messageActor - Send messages to other actors
  • scheduleJob - Schedule background jobs

Validation

  • validationError - Prevent operation and return error

See all effects →

Common Use Cases

Validation Rules

Prevent invalid state changes:

filtrera
import 'iterators'

param input: OnOrderBeforeCreated

let hasItems =
  input.order.deliveries
  select d => d.orderLines
  flatten
  count > 0

from hasItems match
  false |> {
    effect = 'validationError'
    code = 'EMPTY_ORDER'
    message = 'Orders must have at least one item'
  }

Automation Rules

Trigger workflows automatically:

filtrera
param input: OnPaymentCapture

from input.paymentCapture.capturedAmount > 10000 match
  true |> {
    effect = 'messageActor'
    actorType = 'ticket'
    actorId = 'new'
    messages = [{
      type = 'create'
      commands = [{
        type = 'setDynamicFields',
        fields = {
          title = 'Large Payment Review'
          description = $'Payment {input.payment.paymentNumber} for {input.paymentCapture.capturedAmount} needs review'
          paymentId = input.payment.paymentId
        }
      }]
    }]
  }

Integration Rules

Sync with external systems:

filtrera
param input: OnOrderCreated

from [{
  effect = 'scheduleJob'
  definition = 'sync-to-erp'
  at = datetime.now addMinutes 5
  parameters = {
    orderId = order.id
  }
}]

Multiple Effects

Rules can return multiple effects as an array:

filtrera
param input: OnOrderCreated

from {
  effect = 'orderCommand'
  type = 'createComputedOrderDiscount'
  componentId = 'free-shipping'
  description = 'Free Shipping'
  parameters = { threshold = '500' }
}
from {
  effect = 'sendEmail'
  to = order.customer.email
  subject = 'Order Confirmed'
  body = { html = '<h1>Thank you!</h1>' }
  dynamic = {}
}

All effects execute in the order specified.

Access Control

Managing rule resources requires standard permissions:

rules:read   # View rule configurations
rules:write  # Create, update, and delete rules

Rules inherit the execution permissions of the system - they run with elevated privileges to enforce business logic across the platform.

Best Practices

1. Use Before Hooks for Validation

Prevent invalid operations with before hooks:

filtrera
hook OnOrderBeforeCreated
from validateOrder(order) match
  Error |> [{ effect = 'validationError', code = error.code, message = error.message }]
  |> []

2. Use After Hooks for Automation

Trigger workflows after successful operations:

filtrera
hook OnOrderCreated
from [
  { effect = 'sendEmail', ... },
  { effect = 'scheduleJob', ... }
]

3. Handle Missing Data Gracefully

Always handle optional data:

filtrera
from input.order.invoiceAddress.email match
  email |> { effect = 'sendEmail', to = email, ... }
  // Default case returns nothing

See Also

© 2024 Hantera AB. All rights reserved.