Skip to main content

3. Using the web app

The walkthrough below processes one invoice from start to finish. A clerk submits it, the clerk is refused when trying to approve it, and an approver corrects the PO number and approves it. A second invoice is then rejected.

3.1 First visit​

The web app before signing in

The page has three areas:

  • Top bar: the agent picker and the access-token field. The picker lists the workflows the backend compiled from YAML; nothing is hard-coded in the web app.
  • Left: the run, showing its status and every state key the workflow allows the browser to see (its state_whitelist).
  • Right: the approval card (when one is open) and the chat.

3.2 Sign in​

The clerk's token pasted into the token field

Paste a token from seed_demo into the token field. It is kept for the browser tab only and is sent to the backend with every request. There is no sign-in screen yet; an identity provider such as Keycloak is planned.

3.3 Submit an invoice​

An invoice typed into the chat

Type or paste the invoice into the chat and press Enter. The chat's text becomes the document the workflow reads. Uploading a file through the API works too (§10).

3.4 The run pauses for approval​

The run paused, with the approval card and step-by-step narration

Each step reports as it finishes. The chat narrates (Parsed the document, Extracted invoice, All checks passed, Matched vendor ACME Supplies Ltd (1.00), Awaiting human approval), and the state panel fills in:

State keyWhat it holds
invoiceThe fields the model extracted, checked against schemas/invoice.yaml
validation_issuesProblems the rules found; [] means every check passed
matchThe vendor and purchase order found, the score, every candidate, and bank_details_changed
awaiting_approvaltrue while a person must decide
approvalThe decision once made: approved, by, comment
postedThe accounting system's response once the bill is posted

The demo's narration says Extracted invoice with Qwen/Qwen3.8-27B-FP8: the fixture runs under the name of the model configured in models.yaml.

The approval card is built from the workflow's ui.approval_card block:

The approval card in detail

  • The title is a template over the run's state (Approve invoice {{ invoice.invoice_number }}).
  • The fields listed in the YAML are shown read-only.
  • The editable fields can be corrected by the approver; only those fields can be changed.
  • Comment is stored with the decision.

3.5 The clerk cannot approve​

The clerk's attempt is refused and the approval stays open

A clerk does not hold the approvals.resolve permission. The backend refuses the decision, says why (Not accepted: …), and offers the same approval again, so someone who may decide still can. The run is not changed.

The same happens if the person who started the run tries to approve it (four-eyes: the person who started a run cannot approve it), or if a decision edits a field the card does not mark editable.

3.6 The approver corrects and approves​

Paste the approver's token. The same run, still waiting, stays on screen. Correct the PO number, add a comment and press Approve:

The approver editing the PO number and adding a comment

The run continues. The bill is posted to accounting exactly once, and the status becomes posted:

The run completed and posted

Scroll the state panel to see the decision and the accounting response. The posted bill carries the corrected PO-7A:

The approval record and the posting result

3.7 Rejecting an invoice​

Reload the page to start a new conversation, submit another invoice as the clerk, then reject it as the approver with a comment. The run ends at the workflow's reject node, Closed as rejected, and nothing is posted:

A rejected run

(The fixture model extracts INV-1001 whatever you send, so the second invoice shows the same fields.)