Document Submission with Manager Approval¶
A step-by-step guide to a user-triggered workflow where a requester uploads a document through the request catalog and their manager must approve it before the run completes. This is the single-tier building block. For a request that escalates to a second approver when a numeric threshold is crossed, see Multi-Step Approval Chain Workflow.
Prerequisites¶
- Every requester who will submit documents must have a manager
configured in Floh (
manager_idset on their user record) — the step's sole approver is the requester's manager, and the workflow fails closed if that reference can't be resolved (see Security model). - The
workflow:create,workflow:update,workflow:publish, andworkflow:readpermissions on your admin account. Starting a verification run also requiresworkflow:start.
Security model — read this before publishing¶
- Approval is mandatory. The
document_submissionstep below declares anapproverslist — there is no path that skips straight to completion. If you copy this pattern, resist the temptation to removeapproversfor a "trusted requester" shortcut; that reintroduces an unreviewed upload. - Unresolved approvers fail the run, not the check. If a requester
has no manager on file, the step's only approver reference
(
{{requestor.manager.id}}) resolves to nothing, and the document upload handler fails the step withNo approvals could be created — unresolved approver(s)rather than silently completing without approval. This is why manager assignment is a hard prerequisite, not a nice-to-have. - Rejections loop back by default. This workflow leaves
allowResubmissionunset (defaulttrue), so a rejected upload resets the task towaiting_submissionand the requester can upload a corrected file. See Variations if you want a terminal rejection instead. - File uploads are constrained.
allowedMimeTypesrestricts uploads to PDF and image files;maxSizeBytescaps the file size. Don't widen these without a reason — an unconstrained upload accepts arbitrary file types.
Overview¶
flowchart TD
Submit[Portal Submit]
Start[Start]
Upload["Submit Document (document_submission)"]
Approved[Notify Submission Approved]
Rejected[Notify Submission Rejected]
Done[End]
Submit --> Start --> Upload
Upload -->|success| Approved
Upload -->|error| Rejected
Approved --> Done
Rejected --> Done
Step 1 — Create the workflow¶
Navigate to Design in the sidebar (opens /workflows) and use the
section tabs to open Workflows, then click New Workflow and fill
in:
| Field | Value |
|---|---|
| Name | Document Submission with Manager Approval |
| Description | Submit a document for manager approval |
| Category | user |
| Subject Variable | requestor |
| Error Strategy | stop |
| Trigger | manual |
Step 2 — Define variables¶
Open the Variables tab and add:
| Name | Type | Required | Secret | Default | Description |
|---|---|---|---|---|---|
requestor |
Requestor | yes | no | — | The submitting user (auto-filled from session, hidden in form) |
submissionDescription |
String |
no | no | — | What the document is for, shown to the approver (e.g. "W-9 update") |
The Requestor preset binds requestor to the authenticated caller
and hides the field on the catalog form — the server overrides any
caller-supplied value, so a requester cannot submit as someone else.
Step 3 — Add the workflow steps¶
3.1 — Start¶
Type: start. Entry point.
3.2 — Submit Document¶
Type: document_submission.
| Config Field | Value |
|---|---|
| Submitter ID | {{requestor.id}} |
| Submitter Email | {{requestor.email}} |
| Document Label | Supporting Document |
| Instructions | Upload the required document. Your manager will review it. |
| Allowed MIME Types | application/pdf, image/* |
| Max Size | 10485760 (10 MB) |
| Approvers | {{requestor.manager.id}} |
| Notify Submitter | true |
| Notify Approvers | true |
Transitions:
success→ Notify Submission Approvederror→ Notify Submission Rejected
document_submission's approver resolution does not support the
manager:{{id}} ref shorthand that the approval step type accepts —
it only resolves raw user IDs and group:<slug> refs. That's why the
config interpolates the manager's ID directly
({{requestor.manager.id}}, using the shallow manager snapshot on the
requestor variable) rather than writing manager:{{requestor.id}}.
3.3 — Notify Submission Approved¶
Type: notification.
| Config Field | Value |
|---|---|
| Recipient Type | internal |
| Recipient User | {{requestor.id}} |
| Subject Override | Your document submission was approved |
| Custom Body | Your submission ({{submissionDescription}}) has been approved. |
3.4 — Notify Submission Rejected¶
Type: notification.
| Config Field | Value |
|---|---|
| Recipient Type | internal |
| Recipient User | {{requestor.id}} |
| Subject Override | Your document submission was not approved |
| Custom Body | Your submission ({{submissionDescription}}) was not approved. See your task inbox for next steps. |
This step only fires when allowResubmission is false (or the
approver uses a final_rejected decision) — see
Variations. With the default resubmission loop, a plain
rejection just resets the task and this notification never fires.
3.5 — End¶
Type: end. Exit point.
Step 4 — Wire the graph¶
In the Graph tab, draw these transitions:
- Start → Submit Document
- Submit Document →
success→ Notify Submission Approved - Submit Document →
error→ Notify Submission Rejected - Notify Submission Approved → End
- Notify Submission Rejected → End
Step 5 — Save, test, publish¶
- Click Save. Fix any validation errors the designer reports — an
empty
approverslist on thedocument_submissionstep will block save. - Click Test Run and submit. Confirm the run pauses at Submit
Document with
waiting_submission. Upload a test file, then sign in as the requestor's manager and approve. Confirm the Notify Submission Approved email arrives. - Test the rejection path: submit, upload a file, then reject it as
the approver. Confirm the task resets to
waiting_submissionand the requester can upload a corrected file (the defaultallowResubmission: truebehavior). - Click Publish.
- On the Catalog tab, set Published, pick an icon, add a clear description, and restrict submission to the right groups if applicable.
Variations¶
Terminal rejection¶
Set allowResubmission to false on the Submit Document step. A
rejected upload then follows the error transition to Notify
Submission Rejected and End, instead of resetting to
waiting_submission. Approvers can also force that terminal path on a
resubmission-enabled step by choosing a final_rejected decision —
that still fires the rejection notification even when
allowResubmission is left at its default.