Skip to content

Flows and steps

A flow describes how one kind of record is approved. It is an ordered list of steps; a request goes through them one at a time, and each step must be approved before the next starts. A rejection in any step rejects the request.

const purchase = defineFlow({
key: "purchase",
steps: [
// One person: the requester's manager, found by a resolver you write.
{ id: "manager", approvers: { type: "resolver", name: "directManager" } },
// Any two of the committee must approve.
{ id: "committee", approvers: { type: "role", role: "committee" }, mode: { quorum: 2 } },
// Only for contracts.
{
id: "legal",
approvers: { type: "users", ids: ["u_legal"] },
when: { field: "category", op: "eq", value: "contract" },
},
// Every board member, only from 50,000.
{
id: "board",
approvers: { type: "role", role: "board" },
mode: "all",
when: { field: "amount", op: "gte", value: 50_000 },
},
],
});

Runs in CI:examples/docs-snippets/src/concepts/flows.ts

mode decides when a step is done:

Mode The step is approved when Rejected when
"any" (default) the first approver approves the first approver rejects
"all" everyone approves anyone rejects
{ quorum: n } n approvers approve approval can no longer reach n

In any mode the first decision closes the step and the other tasks are superseded (EC-12).

flows.register validates a flow and stores it as a new version when its content changed. A request is pinned to the version it was submitted with, so changing a flow never changes requests already in progress (EC-37). A tenant can register its own version of a flow, which its requests use instead of the global one (EC-56).

defineFlow checks a flow before anything runs, and reports every problem at once:

try {
defineFlow({
key: "broken",
steps: [{ id: "a", approvers: { type: "users", ids: [] }, deadline: "P1M" }],
});
} catch (error) {
if (error instanceof FlowDefinitionError) {
console.log(error.issues); // every problem, each with its path: steps[0].deadline, ...
issues = error.issues;
}
}

Runs in CI:examples/docs-snippets/src/concepts/flows.ts

Settings that would silently skip an approval default to the safe choice: a step that ends up with nobody to approve stops the submit instead of being skipped (EC-02).