Soheil Yousefi Frontend · Design engineer
CASE / 01

Resolve

Making a support operations platform fast enough to live in for a whole shift.

Role
Frontend architecture · UI
Year
2026
Stack
React · TS · TanStack
Status
Self-directed showcase
FIG 00 · INBOX — ALL OPEN TICKETS PROTOTYPE · SEEDED DATA
Resolve inbox: 214 open tickets in a table with priority, account, channel, assignee and SLA countdown; three rows selected with a bulk action bar; queue rail on the left
The rail is queue state, the table is the virtualised list, and the bar above it appears the moment a selection exists. Breaching SLA is a column, not a badge you have to hunt for. All figures show seeded demo data.
01 — CONTEXT

The problem with support tooling

Support agents don’t browse an app; they inhabit one screen for an entire shift. Every extra click, every list that re-renders and loses scroll, every reply that waits on a round trip compounds hundreds of times a day. Most helpdesk front ends are built as if each interaction happens once.

Resolve is my attempt at the opposite: an interface tuned for the thousandth interaction rather than the first.

THE BRIEF
Design the surface a support agent lives in for a full shift — triage, reply, and escalate without ever leaving one screen.
CONSTRAINTS
A 10,000-row queue that must stay scroll-stable, replies that must feel instant on a 400ms connection, and a colour-blind-safe status language.
MY ROLE
Everything in the browser: information architecture, interaction model, the component layer, and the performance budget it is held to.
SCOPE
A self-directed showcase build: six screens, a component layer, and the interaction model written down. No client, no production deployment, no live users.
02 — APPROACH

Three rules I held to

Each one is a decision I could be wrong about, so each one is written down where a teammate can argue with it.

01

Never move the ground

Scroll position, selection, and focus survive every refetch. New tickets arrive as a count, not as a jump.

TRADE-OFF · more state to reconcile
02

Optimism with a receipt

Actions land immediately and carry their own undo. Failure restores the exact prior state and says so in words.

TRADE-OFF · harder error paths
03

Density over disclosure

If an agent needs it hourly it is on screen. Accordions are for things read once.

TRADE-OFF · a steeper first hour
03 — INTERACTION
FIG 01 · useOptimisticReply.ts
 // reply lands in the thread before the network confirms it  const mutation = useMutation({    mutationFn: sendReply,    onMutate: async (draft) => {      await qc.cancelQueries({ queryKey: thread(id) });      const prev = qc.getQueryData(thread(id));      qc.setQueryData(thread(id), append(draft, 'pending'));      return { prev };    },    onError: (_e, _v, ctx) => qc.setQueryData(thread(id), ctx.prev),  }); 

Pick a note to mark the lines it refers to.

FIG 02 · CONVERSATION · MACROS & ESCALATION
Resolve conversation view: customer messages, an internal note, an SLA panel counting down to breach, a linked engineering issue, and the macro palette open over the reply box
The thread carries three kinds of entry — public reply, internal note, system event — and they are typographically distinct rather than colour-coded. The right column is the account: SLA clock, requester, the engineering issue this ticket is waiting on.
04 — KEYBOARD

The mouse is the fallback

Every triage action has a single key. The palette exists for discovery, not for speed — an agent who has learned the queue never opens it.

J / K
Move down / up the queue Selection never leaves the viewport
E
Archive and advance Undo toast holds for 8 seconds
A
Assign Opens the palette pre-filtered to people
R
Reply inline Focus lands in the composer, draft autosaved
⇧S
Snooze until tomorrow 9:00 Custom times via the palette
⌘K
Command palette Only surface that is mouse-first
FIG 03 · COMMAND PALETTE

Results are ranked by recency of use, not alphabetically — the second week feels different from the first.

05 — SYSTEM

Status has to be readable at a glance

Colour alone never carries meaning: each state pairs a hue with a shape and a word, so the list stays legible for colour-blind agents and in a screenshot pasted into Slack.

BREACHING

Copper dot, round. SLA is inside one hour — the only state that also sorts to the top.

OPEN

Neutral dot. Waiting on us, but with time on the clock.

WAITING

Square, not round. Waiting on the customer; ages differently.

RESOLVED

Green dot plus a struck subject line — two signals, never one.

DENSITY LADDER
Row height, comfortable 44px
Row height, compact 32px
Pane gutter 16px
Text floor in list 12px
PERFORMANCE BUDGET
Keystroke to paint < 16ms
Reply appears immediate
Queue switch < 120ms
Bundle, route-split 96kb
06 — AUTOMATION

A rule you can read out loud

Routing is where support tools go opaque: a ticket lands somewhere and nobody can say why. Every rule here reads as one sentence — when a trigger fires, if these conditions match, then run these actions in order — and each clause is an editable chip rather than a nested form.

The list beside the editor shows runs in the last thirty days and the last time each rule fired, so a rule that has quietly stopped matching is visible without opening it.

Resolve automation screen: a list of seventeen routing rules with run counts and toggles, beside a rule editor built from when, if and then clauses
FIG 04 · ROUTING RULE EDITOR — the recent-runs strip under the editor is the only honest test of a rule.

The knowledge base is an output

Searches that returned nothing are ranked by the tickets created straight after them, and solved threads are offered back as article drafts. Coverage gaps are content, not a chart.

Resolve knowledge base: article table with deflection counts and status, beside a panel of coverage gaps and drafts generated from resolved tickets
FIG 05 · KNOWLEDGE BASE
07 — RESULT

Density is a feature. The job was to make more information legible, not to hide it behind progressive disclosure.

KEYBOARD COVERAGE
100%
Every triage action
LIST SIZE
10k
Virtualised, stable scroll
CONTRAST FLOOR
AA
Both themes, all states
Resolve reports screen: six headline metrics across the top, SLA compliance by policy, an agent workload heat map by hour, volume by channel and a CSAT breakdown
FIG 06 · SUPPORT OPERATIONS — every number on this screen is seeded prototype data. It is here to show what the reporting layer has to hold, not to claim a result.
WHAT I'D DO NEXT
A shared-draft indicator — two agents in one thread is the failure mode I have not solved.
Saved views with keyboard slots, so a senior agent can build their own queue order.
The density ladder is a deliberate design decision intended to balance scan speed with information depth; it is presented as a design rationale, not a validated user-research finding.
PROOF
Live prototype URL REQUIRED
Component source REPO REQUIRED
Interaction spec FILE REQUIRED

A proof link renders only once its destination exists.