Skip to content
Faldaro
All guides

Workflows

A submission is a record with a state. A workflow declares the states, the moves between them, and what happens when a move is made — drawn as a picture in the builder, and shown on every record as where it is and what can happen next.

Building one

The Workflow tab in the form builder is a diagram. States are boxes, laid out left to right by how many moves it takes to reach them from the start; moves are arrows with their button text on them. Select a state or a move and the rail beside the picture edits it; click the paper to deselect. Moves available from any state (a Cancel, say) are listed beneath the picture rather than drawn from every box.

An empty form offers four quick startsReview and approve, Ticket, Application and To do — each a complete workflow you rename rather than a blank page. Or type a state's name into Add a state: its id is derived from the name (In review becomes in-review), never typed, so there is no id to misspell. Picking a quick start on a form that already has states asks first, and Undo brings the old workflow back.

The picture carries a few marks worth knowing:

MarkMeans
Play triangle on a boxThe start state — where every new submission begins.
Flag on a boxA final state. Nothing moves out of it.
Clock on a boxThe state has a deadline.
Lock on an arrowThe move names a required privilege.
Funnel on an arrowThe move has a condition.
Checklist on an arrowThe move requires fields to be filled in first.
Warning triangleSomething to look at, listed under the picture.

States

A state has a name, a colour, and two switches. Start state is where new submissions begin — the first state you add takes it until you say otherwise. Final state means the record is finished: the engine refuses every move out of one, so mark a state final only when reopening truly must be impossible. A final state cannot carry a deadline, because a finished record has no clock to run out.

The colour is one of six — gray, blue, green, amber, red, teal — and it is how a state looks everywhere it appears: the box in the diagram, the chip beside a record's title, the status column of the submissions table. The engine ignores it; it exists so Rejected reads as red at a glance without anyone reading the word. Anything outside the six shows as gray.

A state's rail also lists the moves out of it and into it (each a chip that opens the move), and the actions that run when a submission enters or leaves it. Removing a state takes everything that named it — its moves, its actions, and any deadline that fired one of those moves — so the document never keeps a reference to a state that no longer exists.

Moves

A move — the API and the audit log call it a transition — is a button on the record. It has the text on that button, a from state (or any state) and a to state. Publishing validates the whole graph: every move must connect declared states, and one out of a final state can never be taken, which the builder warns about before the server refuses it.

Three guards decide whether the button shows on a given record:

GuardWhat it does
Who may take itA privilege the person must hold, chosen from the catalog. Leave it on the default and the move needs submission:transition — never nothing. Moving a record and editing its data are separate powers held by separate privileges.
Only whenA condition on the record's values, built with the same pickers as a logic rule — field, operator, value — or written as a formula. The button appears only while it holds.
Must be filled in firstFields that must have a value before the move is allowed. The record names the missing ones.

The engine re-checks every guard when the button is pressed, whatever the page showed. That is what makes it safe for the page to also explain a move it could not offer — see on the record.

Effects: what a move does

Actions belong to states, not moves: each state has a When entering list and a When leaving list, edited in its rail. The menu that adds one is split in two, because the two halves behave differently.

ActionDoes
With the move
Set a fieldWrites a value or a formula's result onto the submission — a decision, a date, a flag a later move can require. Pick one of the form's fields, or something else to write a key no field displays.
Assign to someoneRoutes the record to a person picked by name, or to whoever a formula names. Their membership is checked, so a rule cannot hand work to somebody outside your organisation.
After the move
Send a notificationQueues an email template, chosen by name, to the recipients you tick: the assignee, the owner, the creator, any email field on the form — or a list field of addresses, each email-shaped entry reached (capped at twenty).
Generate a documentRenders a PDF template and attaches it to the submission.
Request a paymentPrices the form's payment rule now and emails the payer a checkout link — the deposit asked for on approval, not at submission.
Request a signatureEmails each named signer their own signing link for a frozen, fingerprinted document — with an evidence trail and a certificate on the signed copy.
Deliver a fileAdds one of your deliverable files to the submitter's download link.
Create a linked submissionOpens a record on another form, chosen by name — a claim from a policy — as a draft, since a rule rather than a person is filling it in. The link between the two is kept.
Call a webhookPosts to an https address of your own that an operator has allow-listed.
Send to an integrationQueues a delivery to a named connection — never a URL.

Set a field and assign happen inside the move itself. Everything that leaves the platform happens after the move commits, from a queue with retries: an unreachable mail server delays a notification, it never un-moves the record. Each queued effect is a visible row you can inspect on the submission's Activity tab, not a hope.

A value a move set is remembered rather than recomputed, so a later move can be gated on a flag an earlier one raised — including `payment_status` = "succeeded", which is how work waits for money to clear, and `signature_status` = "signed", which is how it waits for everyone asked to sign.

Deadlines

A state can carry a clock: after 2 days without a move, Escalate. You set the wait in hours or days and choose one move that leaves the state; the platform takes that move itself when time runs out, with every check except the caller's privilege, because there is no caller — the authorisation happened when someone with form:write published it. The move's own rail says when a deadline also fires it.

A deadline fires once per stay in the state, and only for submissions created after the version that declared it was published — publishing one never retroactively arms existing records. A move that loops back into the same state cannot be a deadline's, since re-entry would reset the clock and it would fire forever; a recurring reminder is an agent's job.

What the builder checks

Under the picture, the builder lists what is wrong in plain words, and clicking a line selects the state or move it is about. Two levels:

  • Things to fix are what publishing would refuse: a move to a state that no longer exists, two moves sharing an id, a required field the form does not have, a condition the engine cannot parse, a deadline with no move or the wrong one, an action with no template, no form, no file or a webhook that is not https.
  • Worth a look is what publishes but almost never means what you meant: a state nothing moves out of that is not marked final (a dead end), a state no move leads to, a move out of a final state, two moves out of one state with the same button text, a button with no text, an action that sets nothing or assigns nobody.

The server runs its own validation at publish regardless; the builder's list is the same rules said earlier, where they can be fixed with one click.

On the record

A submission's page shows its state as a chip in the state's colour beside the title, and under the header a strip of every state in the order the workflow flows, with the current one lit. The strip is the map and the pin, not a history: a rejected claim never passed through Approved, and the page does not pretend it did.

The moves the person may take right now are the buttons in the header, the first one accented; hovering says where it leads. A move into a final state asks before it is taken, because nothing moves out of one afterwards. Moves that exist from this state but were not offered are listed under the strip with the reason: the privilege it needs, the fields to complete first, or that its condition does not hold — never the condition's text, so the page is not an oracle for the rule behind it.

The submissions table shows the same coloured chips, and above it the workflow's states are a row of counted filters in flow order — how many records sit in each, and one click to see only those. My work groups everything assigned to you by state across every form.

Everything is audited

Every move lands in the audit log with who, when and what — a deadline's move says the deadline did it — and the log is append-only at the database-permission level. What happened is what the log says happened.