Design a product-event rule engine

Build a trigger framework that matches product events to versioned conditions and executes reliable, idempotent actions.

Rule engine and trigger framework

An order arrives, and the product wants some orders reviewed before fulfillment. The condition can change while old events remain available for replay. A rule engine must preserve why an action was selected, or the same recorded order can quietly acquire a different history each time a worker sees it.

The same pattern can issue a rider incentive after delivery, a coupon after cart abandonment or a workflow after document approval. We'll define the event-to-action path, resolve overlapping rules, then replay an order under a changed policy.

A decision before an effect

wiki/dag-workflow-orchestration The workflow lesson started with an agreed set of steps. Here the first decision is whether that workflow should exist at all. An incoming event supplies facts; a versioned rule tests those facts and chooses an action obligation, such as creating a review task.

Keep evaluating the rule separate from carrying out the action. Evaluation should produce the same decision from the same recorded input and rule version. That is a pure evaluation: it does not charge a card, send a message or ask a changing external database what the order looks like now. Effect workers use the identity and recovery agreements already established in Module 08.

If the rule needs additional facts, record those facts as inputs with their source versions or timestamps before evaluating. Otherwise a historical order can match differently because its customer's profile changed, even though the rule stayed fixed. Sometimes “use the current profile” is the intended product policy, but that evaluation must record which profile it actually used.

Normalize the incoming event into a validated, typed input before matching. The rule store supplies an immutable policy version; matching produces a decision and an action obligation. In this proposed architecture, a dispatcher carries out the obligation later and records the outcome.

The decision explains why work was requested; the execution outcome explains what happened. Preserve both. An audit log written after an external effect cannot repair a lost decision by itself.

Our chosen event is order-A , with type order.submitted , schema version one and a quantity of 150 units. The units describe a synthetic order size, not a measured production threshold. Rule review-large matches at or above 100 units in rule set version one; review-all matches at or above zero.

Both rules can therefore match the same event. We choose a policy where the lower priority number wins, with rule identifier as a deterministic tie-breaker. They select the same action category, review, so matching both must still create only one review obligation. Another product could permit several independent actions, but it would need an identity for each action and a defined conflict policy.

Read the table as the chosen rule data. The two version columns make the change visible without changing the recorded order.

Rule Priority Version one minimum Version two minimum --- --- --- --- review-large 10 100 units 200 units review-all 20 0 units 0 units

Changing the threshold changes the selected rule; the retained order stays the same.

Rule-set version and event-schema version answer different questions. The schema version says how to interpret the event fields, as wiki/event-contracts the event contract lesson established. The rule-set version says which policy evaluates those fields. Store both with the evaluation, together with the matched rules and selected action, so an explanation does not depend on today's configuration.

The workflow replay stores evaluations and action obligations in a private temporary database; it creates no real review tasks or customer messages.