The business context
Blaze generates marketing content on autopilot. A client sets their goals, brand style, and assets, and the platform produces organic social posts, paid ads, paid search, and SEO content automatically. In 2026, the company moved upmarket, targeting businesses that wanted an agency experience where humans handle everything. Blaze hired Account Managers to revise and quality-check the auto-generated content before it reached clients.
The Account Manager team came to us with a request: they needed a real review step. There was no structured moment between "the AI generated this" and "the client sees this." I was asked to design the approval workflow that would make the managed service promise credible.
Where it started
The existing approval surface had almost no states. Content sat in "Review," and once approved, the card simply disappeared. Nothing could be tracked afterward. When a client rejected content, the state silently reverted to draft: no feedback was captured, so Account Managers had no idea what the client actually wanted changed. Every rejection was a guessing game.
One surface, two business models
The complication was that approvals could not be designed for one audience. The same surface had to serve both of Blaze's business models. Self-serve customers review their own generated content: generated, approve, autopublish. Managed clients sit inside an agency pipeline, where content passes through internal review before it ever reaches them.
The self-serve flow stays deliberately simple because the customer is the approver. The managed pipeline is where the full state machine unfolds: Account Managers need revision history, internal notes, and the state of every item across every client account, while clients need a clean decision surface. That meant designing two views of one system and deciding, state by state, what each side sees and what stays hidden.

Defining every state, including the ugly ones
We mapped every state a piece of content could occupy and every transition between them, including the edge cases the old system pretended did not exist. The most important addition was the feedback loop: requesting changes now required capturing what the client expected, so a rejection became a brief instead of a dead end.
Three key decisions
One system, two views: not two products
Building separate approval experiences for staff and clients would have doubled the surface area and let the two views drift apart. Instead, I designed a single state machine and made visibility the design decision: Account Managers see everything, including internal revision churn; clients see only the states that require something from them. The tradeoff was discipline. Every new state had to be defined twice, once per audience, before it could ship.
A rejection is not one thing
The old system had a single undifferentiated reject that dumped content back to draft. But clients mean two different things when they say no. "Fix this" became Changes Requested: feedback is captured and the content loops back through revision. "Kill this" became Disapproved: a terminal state where the content does not proceed. Separating intent is what turned rejection from a guessing game into a working feedback loop.
Approval granularity per content type
Approval was a global action covering very different content types, from organic social to paid ads to SEO blogs. A client might want to personally approve every paid ad while letting blog posts flow through automatically. I designed a master approvals switch with per-content-type settings underneath, so each client chooses manual or auto-approval per channel. The settings modal became the single source of truth: other surfaces read from it and link back rather than duplicating the toggle.
The settings model raised a question bigger than the UI: what should the defaults be? I flagged this as a product decision rather than a design one and brought it to the team with the tradeoffs framed around the cost of a mistake. Content types that carry spend or public risk got a human gate by default; high-volume organic content flowed.

Process: where the prototype hit its limit
My default process at Blaze was working prototypes. I built the flow in our QA environment with Claude Code and ran real content through it to gather feedback. For this project, the prototype hit a real limitation: a working demo shows the happy path and whatever you stumble into, but this system's entire value lived in its full state coverage, and no demo walks through every state.
So I made two moves. First, I extended the team's development state panel with the switches this project needed, so reviewers could jump directly to any audience and any approval state instead of clicking their way there. Second, I paired the prototype with a complete spec: a Linear ticket documenting the full state logic and every transition in the flow. The prototype made the experience tangible. The spec made the system buildable. Neither alone was enough.
Iteration and launch
Account Managers, the daily users of this workflow, reviewed each round. Their feedback was applied directly to the second and third prototype iterations.
For launch, we scoped iOS to the client view only: clients approve on the go, while Account Managers work at a desk. Because the state logic was already fully defined, the iOS build was fast. The work was pattern adaptation, not re-invention, built on the iOS component library I had established earlier.
Outcomes
The workflow was validated round by round with the people who use it every day: Account Manager feedback shaped the second and third prototypes directly, and the final flow was received enthusiastically by the team. It launched on Web and iOS.
What the system delivers: a review process where nothing disappears, every rejection carries a reason, and approval flexes per content type for every client.
What I took from this
Ambiguity is not a lack of information. It is information without structure. On this project, structure meant states: once every state and transition had a name, the open questions stopped being debates and became decisions. And I learned where my own favorite method ends. A working prototype is the fastest way to feel a system, but it is not a spec, and knowing which one a moment calls for is the job.
Skills & Methods