TL;DR
- Context: Lead UX at a B2B packaging e-commerce scaleup.
- Problem: Reports (lost package, refund, invoice correction) got messaged to people one by one — it didn’t scale.
- What I did: Designed a workflow layer inside the platform that routes tasks to the right team by problem type.
- Result: ~10+ workflows live, ~300 tasks a month.
Diagnosis
The inherited concept already had “tasks”. What it lacked was the part that mattered: routing. The person reporting a lost package doesn’t know — and shouldn’t have to know — which team or person handles it; they just need to say what’s wrong. Direct messaging scales badly: you ping people in sequence until someone picks it up, and the time it eats grows exponentially. So the win wasn’t a fancier task list — it was a workflow layer that let you route a problem by type and let the right team pick it up. And it lived inside the platform where the order already was, so nobody had to switch tools.
flowchart TD
subgraph Before["Before"]
A1["Reporter messages person 1"] --> A2{"Reply?"}
A2 -->|"no"| A3["Messages person 2, 3..."]
A3 --> A2
A2 -->|"yes"| A4["Someone finally picks it up"]
end
subgraph After["After"]
B1["Report: problem type"] --> B2["Automatic routing to team"]
B2 --> B3["Right team picks up the task"]
end
classDef good fill:#e6f2ea,stroke:none,color:#1f4d33,rx:14,ry:14
classDef bad fill:#faeaea,stroke:none,color:#5f2626,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class A1,A2,A3,A4 bad
class B1,B2 good
class B3 accent
style Before fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
style After fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
What I did
- Extended an inherited task concept (left by a designer who’d departed) with a workflow-routing layer — the part I identified as the real value.
- Designed contextual task creation: tasks spawned from the order or line-item view, not from a blank form.
- Built filtered dashboards per role — a manager splits by assignee plus an “unassigned” bucket for distribution; a worker filters to their own tasks and groups by workflow (inspired by Notion databases and Jira/Asana boards).
- Kept the whole thing inside the existing platform — no external ticketing tool, no context switching.
Results
- ~10+ workflows live (lost package, invoice correction, refund, and the like).
| # | Workflow | Status |
|---|---|---|
| 1 | Lost package | live |
| 2 | Invoice correction | live |
| 3 | Refund | live |
| 4 | Shipping status | live |
| 5–10+ | other request types | live |
- ~300 tasks/month handled in the first three months.
- Handling-time monitoring per process enabled — something direct messaging never gave.
- Feedback highlighted easy monitoring of open cases and easy delegation during unplanned absences (sick leave), because a task routed by type isn’t tied to one person’s inbox.
The problem
Why were internal requests so slow?
A custom-order business runs as a chain — spec, quote, production, shipping, invoicing — and any link can break. When something went wrong (a lost package, a wrong invoice), the person who spotted it, often customer service, had to message colleagues one by one until someone picked it up. They didn’t know who would handle it; there was no system. That kind of direct communication doesn’t scale — the time it eats grows exponentially, and there’s zero visibility into what’s open or who’s on it.
Why not just buy a ticketing tool?
Because the work already lives in the order-management platform. Sending people to a separate tool means context switching — another login, another place to look, another thing that drifts out of sync. The system had to be minimal and live where the order was.
My role / scope
- Lead UX. I owned the design of the task system and its workflow layer.
- Honest provenance: the base task concept was sketched by another designer before they left — without workflows. I added the workflow-routing layer, because I could see that routing to the right team was where the value actually lived.
- I left the company before the planned next phase (a command palette and auto-assignment).
Process
- Started from the assumption that mattered: the reporter doesn’t care who handles it — only what’s wrong. That shaped the whole workflow abstraction.
- Mapped the recurring request types (lost package, invoice correction, refund, shipping status) — each became a workflow with its own required info.
- Designed contextual creation (from the order or line-item), role-based dashboards, and notifications, iterating with the teams who’d use them.
Key decisions & trade-offs
- Route by problem type, not by person. The reporter picks “lost package”, not “message someone in logistics”. That decouples reporting from knowing-who, and it’s what scales. The inherited concept had tasks; this was the unlock.
- Build inside the platform, not a separate tool. No external ticketing system. Trade-off: you build and maintain it yourself — but it lives where the order lives, so no context switching and no drift.
flowchart LR
O["Order view<br/>existing platform"] --> T["Task system + routing<br/>built in"]
Alt["Separate ticketing system"] -->|"another login, context switching"| O
classDef good fill:#e6f2ea,stroke:none,color:#1f4d33,rx:14,ry:14
classDef bad fill:#faeaea,stroke:none,color:#5f2626,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class O good
class T accent
class Alt bad
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
- Contextual creation from the order. Tasks spawn where the problem is, carrying the order’s context with them — not from a blank form that makes you restate everything.
- Role-based dashboards (manager vs worker). A manager distributes work (by assignee, with “unassigned” on top); a worker self-filters and groups by workflow. Filters and density for power users — inspired by Notion databases and Jira/Asana boards.
- Honest MVP: required fields as pasted text. To limit early cost, each workflow’s required info (amount, account number, and so on) was templated into the description field as text — not structured form fields. Pragmatic for v1; structure it once adoption tells you what’s actually needed.
How it turned out
The system shipped and got adopted fast — ~10+ workflows and ~300 tasks a month within the first three months — and it unlocked handling-time monitoring per process, which direct messaging never could. The clearest signal from the teams: open cases were easy to monitor, and delegation during unplanned absences (sick leave) became trivial, because a task routed by type was no longer hostage to one person’s inbox. I left before the planned command palette and auto-assignment — so I’ll claim the shipped core and its adoption, not the features that came after.
What I took away
- The value is often in the routing, not the list. A task list someone else sketched became useful only once problems could find their team without a human switchboard.
- Decouple reporting from knowing-who. “What’s wrong” scales; “who do I ping” doesn’t.
- Build where the work lives. An internal tool that forces context switching slowly dies. In-platform beats a separate tool when the work is already there.
- Ship the rough shape, then let adoption decide structure. Pasted-text fields were enough to learn from; the case for structured fields shows up in how people actually use the thing.