← All scenarios

Worked example — Procurement

Purchase approvals that live in an inbox

A request goes out by email, gathers approvals in whatever order people answer, and nobody can say where it is or whether the right people signed.

The situation

Someone raises a request. Depending on the amount it needs a manager, then finance, then — above a threshold — a director. Vendor checks happen somewhere in the middle, a purchase order has to reach the finance system, and the whole thing currently runs on forwarded email. The thresholds change at budget time, and an auditor asks later who approved what.

These are illustrative scenarios showing how the products are used, not customer case studies.

Build-versus-buy lens

What this helps you decide

Use the example to find where product configuration ends and custom code begins — and whether the boundary leaves your team with less infrastructure to own.

Model fit
Can the record shape evolve without coordinating a migration, API and UI release?
Workflow fit
Can approvals, exceptions and deadlines move out of application code without losing control?
Integration fit
Can your existing APIs become reusable steps with retries, throttling and visible run history?
Control fit
Can your team reconstruct model changes, workflow runs and human decisions later?

What gets modeled

The structure as it would actually be defined — sections that repeat are marked.

  • Purchase requestrecord type
    • Requestersection
    • Vendorchoice

      Options read live from Vendors

    • Linesrepeating section

      The count is not known when the request starts

      • Descriptiontext
      • Quantitywhole number
      • Unit pricedecimal
      • Cost centrechoice

        Read from your finance system

    • Approvalssection

      Written by the process, not the requester

  • Vendorsrecord type

    Status and checks live here

  • Approval thresholdsrecord type

    Reference data finance owns

How it gets built

In the order somebody would actually do it. Each step names the capability it rests on, so it can be checked against the product pages.

  1. Model the request, lines and all

    A request is a header plus a variable number of lines, so lines are a repeating section rather than a fixed set of columns. Vendor and cost centre are choice fields reading live from the systems that own them, so a new cost centre is available without anyone editing a form.

    What it uses: Repeating sections, and choice options sourced from a live system

  2. Give requesters a form and finance a table

    Publishing produces the form and a table with server-side paging, typed filters and column selection, and each person keeps their own saved layout. Nobody builds a request screen or a queue view.

    What it uses: Forms and tables rendered from the schema

  3. Start the approval when the request is submitted

    A trigger on the record starts a run, filtered so that trivial requests take a shorter path. The conditions sit on the links and read the request total, so the amount picks the route. Nobody decides by eye which approver a request belongs to, and nobody forwards it.

    What it uses: Record triggers with filters, conditional links with an explicit default

  4. Read the threshold rather than hardcoding it

    Before routing, a step reads the current thresholds from the record type finance owns. Changing what needs a director is a data change made by the people accountable for it, not a workflow edit and a release.

    What it uses: A step that reads the record mid-run

  5. Ask the right approver for this amount

    Each approval is a human decision step, and who has to sign is configuration on that step: a named person for the manager, a two-of-three quorum for the finance panel. Both are settings on the same step type, so nobody maintains a separate implementation for the panel.

    What it uses: Approval rules from a named person through to a weighted vote

  6. Chase it before it stalls

    Deadline warnings fire while a decision is outstanding, and escalation moves it on when it takes too long. Claims on a task are leased, so an approver who opens one and goes on leave does not hold the request indefinitely.

    What it uses: Deadline warnings, escalation, and leased claims

  7. Check the vendor without leaving the run

    A step calls the vendor-checking service, registered by importing its API description. If that service degrades it is throttled live — paused, stopped or rate-limited on its own — rather than in a release, and a step blocked by a rate limit waits without spending a retry attempt.

    What it uses: Any API becomes a step, with per-action live throttling

  8. Raise the order in the finance system

    The final step posts the purchase order to the finance system and writes the reference back onto the request. Failures retry on a widening backoff, and a failure that persists raises a notification rather than sitting in a queue nobody watches.

    What it uses: Mapped step inputs, retry with backoff, and configured alerting

Numbers used above, and where they come from

Every figure on this site is counted from the product itself. Nothing here is a performance or customer claim, because there is no measurement to cite for one.

ways to decide who approves
7ways to decide who approvesCounted from egav-automation/backend/app/api/v1/automation/schemas/hitl_config_schemas.py — HitlAssignmentPolicy
field types
9field typesCounted from egav/backend/app/api/v1/egav/schemas/entity_type_attribute.py — DataType

What changes

Where a request has got to is a question with an answer, the thresholds are owned by finance rather than buried in a workflow, and who approved what is recorded rather than reconstructed from a mailbox.

Written for Operations teams that own a process.

Evaluate it with your real model

Bring the awkward record, the exception-heavy workflow and the integration you do not want to own. We will make the configuration-versus-code boundary explicit.