01 / 03 — Case Study
AI SaaS Logistics Dispatch co-pilot Dev Handoff
AI SaaS Logistics Dispatch co-pilot Dev Handoff

NebloAI — Freight, brokered.

Making AI assistance useful inside real freight operations — not beside them.

Product flows and dashboard experiences for an AI freight platform — helping brokers, carriers, and admins manage search, offers, negotiation, and visibility without losing the thread between them. Screens from my Figma files, shown with dummy data.

RoleProduct Designer
PlatformWeb app + AI in email and chats
ScopeUX flows, dashboard UI, portal redesign, Figma handoff
TimelineMar 2025 – Oct 2026
Statusv1–v3 shipped
(01)Project snapshot

NebloAI at a glance.

Product type AI logistics SaaS

An AI freight platform that started as a tool for brokers and became a dispatch co-pilot for trucking carriers.

Users Brokers, carriers, admins

Three roles working the same freight data, each needing a very different slice of it.

Main challenge Turning dense freight operations into clear workflows

Search, offers, negotiation, and tracking had to read as one continuous flow.

My contribution UX flows, dashboard UI, AI interaction patterns, handoff

End-to-end design ownership from first structure to dev-ready Figma files.

Primary outcome Clearer operational structure and dev-ready flows

A shared model for how AI, operations, and roles fit together — and screens that hold up in development.

(02)The context

Three roles, two surfaces, one moving feature set

Product environment

NebloAI started as an AI tool for freight brokers and became a dispatch co-pilot for trucking carriers. It combines AI that works inside email and the chats brokers and carriers already use with dashboards for teams running freight operations end to end. Brokers search loads and negotiate offers, carriers respond and track assignments, and admins need operational visibility across everything.

All of it happened under fast-moving startup constraints: priorities shifted week to week, engineering capacity was limited, and design had to keep the product coherent while the feature set was still being discovered. That meant favoring clear, reusable patterns over one-off screens from the start.

Why this was complex
  • 01Output trust — brokers must tell system fact from model suggestion before money moves.
  • 02Human review — every AI proposal needs a clear approve, edit, or dismiss path.
  • 03Uncertainty states — matches and rate suggestions carry confidence the UI has to show honestly.
  • 04Input design — vague broker asks need structure before the model can match loads well.
  • 05Workflow integration — assistance has to land inside search, offers, and tracking, not in a side chat.
  • 06Automation boundaries — what AI may draft versus what only a broker may commit had to be explicit.
(03)The problem

The real problem was workflow clarity.

A broker's day is a constant loop of searching loads, comparing offers, messaging carriers, monitoring statuses, and making quick pricing decisions. Every step carries money and time pressure — a missed update means a lost load. NebloAI's premise is that AI can absorb a large share of that operational load: matching, drafting offers, flagging risks.

But without a clear product structure, AI features drift into becoming a disconnected chatbot bolted onto the side of the real work. Brokers will not switch tools to talk to a bot; they switch tools when the whole workflow gets faster. Every AI suggestion had to land next to the decision it supports.

P-01

Orientation speed

A broker scanning the board is asking what changed and what needs me now. The early structure made that a row-by-row read.

P-02

Information density

Lanes, rates, statuses, carrier history, and AI output all competed at equal weight, with nothing leading the eye to the next action.

P-03

Handoff clarity

Engineering was building from loose screens without state definitions, so every new feature reopened structural debates.

ai dispatcher / inbox — before the revampDummy data
The earlier broker inbox: a flat list where every thread carries identical visual weight, rate and lane detail is buried in preview text, and nothing indicates which message has to be answered first.
01 — Before: every thread the same weight, urgency nowhere1631×1104
(04)My role

The design surface was mine, end to end

As the only designer on a team with a PM and frontend, backend, AI/ML and QA engineers, I owned the flows and screens from first structure to Figma handoff, working in short loops while the feature set was still moving.

  • 01Designed dashboard and workflow concepts
  • 02Structured broker and carrier-facing experiences
  • 03Worked on admin and operational visibility patterns
  • 04Designed the chat-based workflows that run alongside the web app
  • 05Designed flows for search, offers, negotiation, and operational management
  • 06Defined AI interaction patterns — suggestion, review, and dismissal
  • 07Prepared Figma designs for product and development discussions
  • 08Every screen here comes from my Figma files, with dummy data in place of customer records
(05)The workflow

Mapping the broker loop before redesigning

Before any screens, I mapped the broker loop end to end. Two stretches stood out as the friction core: comparing offers and holding negotiation state — exactly where the AI layer had to earn its place.

1
Broker defines searchLane, equipment, dates, and rate expectations
Input
2
AI surfaces matching loadsRanked matches with lane and carrier context
AI draft
3
Broker compares offersRates, carriers, and histories — scattered across tabs and chats
Friction
4
Negotiation opensCounters move fast; state lives in message text, not the UI
Friction
5
Terms agreedRate confirmed, load assigned to the carrier
Committed
6
Operations tracks loadStatus updates through pickup and delivery
Live
7
Admin reviews outcomeMargins, fill rate, and escalations across teams
Review
(06)Key UX challenges

Six ways freight resists clean UI

01

Making AI useful inside operational workflows

AI suggestions had to appear at the moment of decision (inside search, offers, and tracking), not in a separate chat tab brokers would ignore.

02

Supporting multiple user roles

Brokers, carriers, and admins share the same freight data but need different views, permissions, and default actions from every screen.

03

Broker search and carrier interaction as one flow

Search results, carrier outreach, and offer threads had to feel like one continuous flow instead of three separate tools.

04

Making offer and negotiation states clear

Sent, countered, accepted, expired — every offer state had to be readable at a glance, because a stale state costs real money.

05

Handling dashboard density without overwhelm

Freight data is inherently dense. The dashboard had to surface what needs action now and let everything else recede.

06

Scalable patterns for future broker integrations

New load boards and broker integrations were on the roadmap, so core modules had to work as templates, not bespoke screens.

(07)Key design decisions

Five decisions that shaped the product.

Each decision came out of a concrete workflow problem, not a visual preference, and each one changed how the screens are structured.

Decision 01

Separate operational visibility from AI assistance

Problem

Early concepts mixed AI messages into the same surface as live load data, so brokers could not tell system fact from model suggestion.

Solution

A two-layer model: the operations layer is always the source of truth (loads, offers, statuses), while AI assistance lives in a clearly framed copilot layer that reads from it and proposes actions back. Suggestions are always labeled, always dismissible, and never overwrite an operational state on their own.

Why it mattered

A wrong read on a load status is expensive. Trust in the AI layer starts with never letting it be confused with the record.

co-pilot panel beside the threadDummy data
The Ask Co-Pilot panel docked beside a load thread, keeping the operational record and the AI conversation in separate, permanently visible columns.
02 — The record on the left, the assistance on the rightSplit model
Decision 02

Keep load and offer status highly visible

Problem

Statuses were buried in detail views and free text, forcing brokers to open every row to answer the only question that matters: what changed, and what needs me now?

Solution

Every load row carries a status pill in a fixed column, states follow one consistent taxonomy across broker, carrier, and admin views, and rows that need action sort to the top.

Why it mattered

The board became scannable in seconds instead of a row-by-row read — and a stale state stopped hiding among live ones.

trucks — status at a glanceDummy data
The trucks list showing status as plain-language movement — parked 3 h, not moving; no signal for 6 h — beside location, current load and owning dispatcher.
03 — Status written as movement, not telematics codes5 states
Decision 03

Make negotiation flows action-oriented

Problem

Counter-offers arrived as plain messages. The broker had to read, decide, switch context, and type — four steps where competitors need one.

Solution

Every negotiation event ships with its next actions attached: accept, counter with a suggested number, or decline — right on the thread. The AI drafts the counter from lane data, but the broker always makes the call with one click.

Why it mattered

Negotiation is where brokers live or die on speed. Reading and acting became the same moment.

broker thread — load context pinnedDummy data
A long broker thread with a persistent load context rail pinned beside it — load, lane, truck, status, pickup and delivery — so replying never means leaving to look something up.
04 — The negotiation and the load facts on one screenOne-click
Decision 04

Use dashboard cards for quick scanning

Problem

Admins and team leads check the health of the whole operation between other tasks. A wall of tables answers detailed questions but fails the ten-second check-in that happens twenty times a day.

Solution

The admin dashboard leads with a card layer — a small set of KPI cards and a volume chart that answer "is today normal?" before any table appears. Cards drill into the dense views underneath.

Why it mattered

Density stayed available on demand rather than by default, so the frequent check-in got fast without losing depth.

reviews — urgent queueDummy data
The urgent review queue, where each card opens with what happens if it is ignored and by when, rather than with a record identifier.
05 — Cards lead with the consequence and its deadline10-sec read
Decision 05

Create reusable patterns for broker integrations

Problem

The roadmap pointed at more load sources and broker integrations. Per-integration screen designs would fragment the product within months and cost a full design cycle each time.

Solution

One module anatomy (header, lane, rate, status pill, action row) that every load source renders into, no matter where the data comes from.

Why it mattered

New integrations became a data-mapping task instead of a design project, and brokers learn the pattern once.

"We separated seeing the operation from asking about it."

Design principle — NebloAI
(08)Before and after

The carrier portal, restructured.

The carrier-facing portal is where the difference is easiest to see: the early state put everything on one screen with equal weight, while the redesign leads with status and a single clear action per load.

Before — the earlier build
inbox — beforeDummy data
The earlier inbox: one undifferentiated list of broker threads, each row carrying the same weight, with no priority, no category and no sense of what is at stake.
06 — Flat list, no triage, urgency invisible1631×1104

Every thread looked equally important, so triage happened in the dispatcher's head. Rate, lane and deadline were all buried in the same grey preview line.

After — the redesign
mailbox — afterDummy data
The redesigned mailbox: the same familiar mail list, now with a freight-native priority chip on every row, category tabs across the top, and freight labels in the rail.
07 — Priority, category and labels carry the triage2000×1024

The list keeps its familiar shape, but urgency is now a property of the row (Urgent, Reply in 6h), and categories and labels let a whole class of mail be dealt with at once.

(09)Core screens

Core screens, shown with dummy data

(10)The system

What the screens are built from.

I owned NebloAI's design system from v1 to v3. The screens use a shadcn base kit plus Neblo's own tokens and components, and every value in this section is read from the Figma file.

Colour does a job. Purple is the brand: table headers, links and the active filter. In the loads table, one warning colour marks every load that needs a person (a delivery at risk, no truck, an unsigned rate con, a missing POD), green marks delivered and grey marks cancelled.

foundations — figma variablesFrom Figma
Colour 25 variables
1. Primitives Shadcn Library
  • Colors/Primary-Purple/50#f7f5ff
  • Colors/Primary-Purple/100#d8d0fb
  • Colors/Primary-Purple/200#b1a2f6
  • Colors/Primary-Purple/300#8c75f0
  • Colors/Primary-Purple/500#4a27e2
  • Colors/Primary-Purple/800#1f1254
  • Colors/Emerald/50#ecfdf5
  • Colors/Emerald/600#059669
  • Colors/Emerald/800#065f46
  • Colors/Blue/50#eff6ff
  • Colors/Blue/600#2563eb
  • Colors/Gray/50#f9fafb
  • Colors/Gray/800#1f2937
  • Colors/Base/White#ffffff
semantic-color Styling & Components
  • background/medium/warning#e0601f
  • stroke/warning#e0601f
  • content/on-bold/default#ffffffe3
3. shadcn/ui colors Shadcn Library
  • Base/foregroundvar(--foreground)#080614
  • Base/backgroundvar(--background)#ffffff
  • Base/border/bordervar(--border)#d4d4d8
  • Base/inputvar(--input)#a1a1aa
  • Base/muted/muted-foregroundvar(--muted-foreground)#27272a
  • Sidebar/backgroundvar(--sidebar-background)#f7f5ff
  • Sidebar/foregroundvar(--sidebar-foreground)#27272a
  • Sidebar/foreground-70%var(--sidebar-foreground)/70#27272ab2
Type 7 variables · 6 text styles
  • font-family/heading Inter
  • text-xs 12
  • text-sm 14
  • text-base 16
  • font-weight/font-normal 400
  • font-weight/font-medium 500
  • font-weight/font-semibold 600
  • text-base/font-semiBold16 / 24 · 600
  • text-sm/font-semiBold14 / 20 · 600
  • text-sm/font-medium14 / 20 · 500
  • text-sm/font-regular14 / 20 · 400
  • text-xs/font-medium12 / 16 · 500
  • text-xs/font-regular12 / 16 · 400
Radius 5 variables
  • Radius/TailwindCSS/rounded-sm4
  • Radius/Component/radius-button6
  • Radius/Component/radius-input6
  • Radius/Component/radius-iconButton6
  • Radius/TailwindCSS/rounded-lg8
Spacing 9 variables
  • Gap/gap-14
  • Spacing/spacing-2xs4
  • Gap/gap-28
  • Padding/p-28
  • Spacing/spacing-sm8
  • Spacing/spacing-md12
  • Padding/p-416
  • Spacing/spacing-lg16
  • Spacing/input-size-container-md40
Size, dimension, opacity 6 variables
  • Size/size-button-sm36
  • Size/size-button-md40
  • Size/size-input-md40
  • Dimensions/00
  • Dimensions/416
  • Opacity/disabled50
13 — Tokens the screens use, read from the Figma variables52 tokens
components in their statesDummy data
Loads table · STATUS 8 states The STATUS column of the booked-loads table. Delivery at risk, Needs a truck, Rate con unsigned and POD missing share one orange-red; Picking up today and In transit are dark text; Delivered is green; Cancelled is grey.
Trucks table · status cell 3 states Dispatch-sheet status above, live line below
A truck status cell: a TRANSIT badge above the live line “62 mph, moving”. TRANSIT, moving: the two agree
A truck status cell: a TRANSIT badge above an orange-red live line, “parked 3 h — not moving”. TRANSIT, not moving: they disagree
A truck status cell: a DISPATCHED badge above an orange-red live line, “no signal for 6 h”. DISPATCHED, no signal
Mailbox rows · priority and category tags 5 states The right-hand end of six mailbox rows: priority tags Urgent and Reply in 6h beside category tags Opportunity, Update and Claims, then each row’s time.
Settings · Phone, changed 1 state
The Phone field in its changed state: the new number in a highlighted input, with “Changed from +1 555 010 1122” and an Undo link beneath it.
14 — Components in their states, cropped from the product screens17 states
status taxonomy — one languageDummy data
Settings, Groups tab: seven connected groups across four statuses (Working, Nothing to post, Needs trucks, Needs admin), dummy data
15 — One status vocabulary, every row in the fleet4 states
empty state — written as consequenceDummy data
A load with no truck assigned, where every empty module states the specific consequence — nothing to track, pickup in 14 hours — instead of rendering a dash.
16 — Nothing renders without a designed fallbackEmpty state
(11)Dev-ready handoff

Frames named for the state they show.

On a small team, handoff couldn't be a ceremony. Each area of the product has its own section in the Figma file, with frames numbered and named for the state they show, so an engineer can open one section and see every state before building it.

figma file — frames in canvas order, left to rightFrom Figma
Loads 5 frames
  1. L1 · Loads — booked
  2. L5 · Load detail — documents by stop
  3. L6 · Load detail — no truck assigned
  4. L5a · Load detail — documents as a list
  5. L7 · Find a truck — drawer
Alerts 15 frames
  1. AL1 · Alerts — all
  2. AL2 · Alerts — Geofences tab
  3. AL2b · Alerts — Departures tab
  4. AL2c · Alerts — Red Zone tab
  5. AL3 · Alerts — New alert chooser
  6. AL4 · Alerts — Red Zone editor
  7. AL5 · Alerts — Geofence editor (wide, with map)
  8. AL6 · Alerts — Departure editor
  9. AL7 · Alerts — a reminder that couldn’t post (list)
  10. AL7a · Alerts — a reminder that couldn’t post (opened)
  11. AL8 · New geofence — nothing placed yet
  12. AL8a · New geofence — circle placed
  13. AL8b · New geofence — states or cities
  14. AL9 · New departure reminder
  15. AL10 · Red Zone tab — not set up yet
17 — How the Figma file is organised for engineers20 frames
(12)Outcome

Where the work landed.

Customer figures stay private, so this section covers what changed in the product: the team has a shared structure for how AI, operations, and roles fit together, and screens that hold up in development conversations.

Product impact — 01

Clearer product structure

The team now works from a shared model of how AI assistance, operational truth, and three user roles fit together.

Product impact — 02

Workflow direction for core loops

Broker and carrier interactions follow one continuous flow from search through negotiation to delivery.

Design impact — 03

Dashboard clarity for decisions

Operational views lead with status and next actions; density is available on demand rather than by default.

Design impact — 04

Faster product discussions

Dev-ready Figma flows keep product and engineering conversations concrete instead of hypothetical.

(13)Reflection

What I would improve next.

These are the threads I would have pulled on next.

  • 01Usability testing sessions with working brokers, on their own loads
  • 02More edge states for negotiation — expiry mid-counter, simultaneous counters, withdrawn offers
  • 03Mobile responsiveness, starting with the carrier portal
  • 04Deeper analytics review once real usage data accumulates
  • 05Design system expansion as the integration module set grows
(+) More work in complex product design
Next case study — 02 / 03 Driver ops Logistics · Mobile + Web