Implementation worksheet · 5 min read
An Approval Workflow Spec for an Agency Client Portal
Specify approvals as a state machine on deliverables: draft → submitted → in_review → approved | changes_requested, with changes_requested looping to draft. Only client users with the approver role can approve; approvals bind to a specific version; resubmission after changes creates a new version and a new review cycle; reminders fire on days 3 and 7 of in_review. Write the spec before building — approval ambiguity is where agency-client trust actually erodes.
'They approved it' versus 'we never saw the final version' is the oldest fight in agency work. The workflow spec exists to make that fight impossible: every approval names its version, and every state change names its actor.
Put it into practice
1. Define the states and the loop
Five states, one loop. Resist extra states (blocked, on_hold) until real usage demands them — every state doubles the edge cases.
2. Bind approval to version
Approving deliverable #12 means approving version 3 of deliverable #12. If a new version uploads, prior approval doesn't transfer — it can't, or the word means nothing.
3. Name who can act
Approver is a role on the client's users, not 'anyone with the link'. Multiple approvers? Decide now: any-one-of or all-of. Write it down; this is the spec's most-litigated line.
4. Specify the reminders
Day 3 nudge, day 7 escalation to your PM. Approval latency is the real portal metric; unreminded reviews are where timelines quietly die.
5. Log every transition
actor, timestamp, from-state, to-state, version. The log is the deliverable's biography and your receipts.
State transition table
Copy this structure into your review document and record your observed result for each row.
| From | To | Who | Side effects |
|---|---|---|---|
| draft | submitted | agency | notify approvers |
| submitted | in_review | system | start reminder clock |
| in_review | approved | client approver | bind version, log, notify |
| in_review | changes_requested | client approver | comment required, loop to draft |
| draft (resubmit) | submitted | agency | new version, fresh cycle |
A failure worth checking
Version drift: the client approves v2 on Tuesday, the designer uploads a 'tiny fix' v3 on Wednesday, and the approved flag silently rides along. Ship v3 and the client is right to be furious — the system said approved and meant something else. Approval binds to version or the workflow is decorative.
Common questions
Should approvals expire?
For time-sensitive work, an optional valid-until on approval is honest — a v2 approved in March shouldn't authorize an August print run unexamined. Most portals skip this; agencies with production deadlines shouldn't.
What about partial approvals ('approve the copy, not the layout')?
That's changes_requested with a comment — resist modeling sub-approvals until a real client workflow demands it. The comment loop covers 95% of it with one-fifth the machinery.
Basis and scope
This is a proposed implementation method using illustrative examples, not a measured benchmark or a customer case study. Prepared with AI assistance. Validate product-specific behavior against current documentation and your own test environment.