Connection Trust

Connection Trust

A customer connected their directory to a security platform, saw a success message, and found out six weeks later that a whole category of data had never arrived. This is what I changed — told in the order I actually worked it out.

My Role
Lead Product Designer
Duration
2 Quarters
Connect — Directory Provider
Environment name
Production directory
Tenant ID
••••••••••••
Application secret
••••••••••••
You’ll collect
  • Users
  • Groups
  • Applications
You won’t collect
  • Sign-in logs
Not licensed
  • Risk events
14
Outcome states designed
Every way a connection can end, mapped before any layout
1,000+
Integrations to absorb
One pattern that works for every vendor in the catalogue
11
Design system components
Entity chips and result panels the team now reuses

Scope of the work — not performance claims

The Problem

Three different failures, one identical screen

A denied permission, a throttled API and a genuinely empty tenant all produced exactly the same thing in the product: nothing. No data appeared, and no screen was willing to say why.

Reviewing a quarter of production issues, setup and validation problems were the largest single theme — and almost none of them were visible at the moment of setup. That reframed the brief before I opened a design file: the failure wasn’t in the connection. It was in the reporting of it.

Production Issue Review

Read a quarter of reported issues to find where customers actually lose trust in the platform.

  • Setup and validation failures were the largest theme
  • Almost none were visible at the moment of setup
  • Most surfaced weeks later, via a missing finding

Customer Conversations

Sat in on calls where the missing data had already caused a problem, to hear how people described it.

  • “Connected” was read as “collecting everything”
  • Nobody re-checked an integration after setup day
  • Blame landed on the platform, not the permission

Engineering Walkthrough

Mapped what the backend can genuinely verify at connect time, and what it can only assume.

  • Permission checks resolve independently, not as one call
  • Throttling is indistinguishable from denial without retry
  • An unreachable tenant can’t return a count of any kind
Chapter 01
The question I started with

Am I designing one feature, or three projects wearing a trench coat?

The work arrived as three separate items on the roadmap — a test-connection flow, collection observability, and data quality. My first move wasn’t sketching; it was laying all three against the screens that already existed to see where they overlapped.

They overlapped almost completely. All three were asking the same question from different angles: can the customer tell what this integration is actually bringing in? Treating them as three designs would have produced three vocabularies for one idea. I scoped them as one pattern with three moments — at connect, after connect, and over time.

Chapter 02 — the turning point
The question that changed the project

Why are we building this? It’s already built.

The obvious path was a new screen: a connection health page, somewhere to put all this. I’d started specifying it when I went back through the production UI and found the panel where people already edit an integration — with a Test Connection button sitting right there in it.

The project wasn’t missing a home. It was missing a result.

Pressing that button returned pass or fail. Everything the roadmap was asking for — per-entity outcomes, what’s collected, what isn’t, why — could live inside a panel users already knew how to open. That deleted a screen from the plan, and it meant nobody had to learn a new place to go when something broke.

I hold onto this one because the instinct to add surface is strong and almost always wrong. The audit — what already exists that this belongs inside? — now runs before I design any new page.

Chapter 03
The question I kept asking engineering

What does the system actually know, and what is it only assuming?

Most of the early mistakes in this project were mine, and they were all the same kind: a label that claimed more than the backend could support. Correcting the domain model turned out to be most of the design work.

“Collecting logs” is consent, not health. It means the customer approved log collection — it says nothing about whether logs are arriving. I’d drawn it as a status indicator. Removed it from the health vocabulary entirely.

The scope noun is different for every vendor. Organisations, accounts, tenants, projects, directories, repositories, workspaces — sometimes a count, sometimes a name. A fixed three-column layout would break on the second integration. It became one composed meta line that absorbs whatever the vendor has.

Unreachable is not zero. If we can’t reach the integration, every entity has to read “unknown” — never a zero and never “permitted”. A zero is a claim about their environment we have no right to make.

That last one is the whole project in miniature. Almost every bug in the original flow came from the interface asserting something it hadn’t verified.

Chapter 04
The question before any layout

What are all the ways this ends?

I wrote the outcomes as a table before opening a design file. Fourteen of them, in four families. Two existed in no spec and no support ticket — they came from asking what happens when the connection works perfectly and there is still nothing there.

Test connection — outcome taxonomy 14 states · 4 families
Lifecycle
  • Untested — nothing run yet
  • Testing in progress
  • Config edited since last test
  • Stored result, six weeks old
Reachability
  • Couldn’t connect — credentials rejected
  • Couldn’t check — throttled or timed out
  • Connected, reads nothing back
Entity outcomes
  • Everything collects
  • Partial — a permission is missing
  • Optional source denied
  • Capability not licensed
Empty results
  • Connected, tenant returns zero objects
  • Log store readable but empty
  • Log destination blocked or missing

The grouping is the design decision. Reachability problems are ours or the network’s. Entity problems are the customer’s, and get a direct link to fix them. Empty results are nobody’s fault and must never be dressed as an error. Colour follows that logic rather than severity for its own sake.

One practical thing came out of drawing all fourteen at once: I stacked them in a single review frame so the team could compare them side by side — with a note in the file saying only one renders at runtime. Without that note, someone reads the frame cold and builds a panel that shows every outcome at the same time.

Chapter 05
The question the state map forced

Where does the answer actually land on screen?

Fourteen outcomes don’t fit under a button. The Test Connection button sat below every field in a single-column form, which meant its answer rendered below the fold — on the exact screen where it was the only thing the user cared about.

BeforeSingle column
Connect — Directory Provider
Environment name
Production directory
Tenant ID
••••••••••••
Application ID
••••••••••••
Application secret
••••••••••••
Test result renders here, below the fold

The answer to the only question the user has arrives where they can’t see it.

AfterTwo column, primed
Connect — Directory Provider
Environment name
Production directory
Tenant ID
••••••••••••
Application secret
••••••••••••
Will be checked — 4 of 10
  • Users
  • Groups
  • Applications
  • Sign-in logs
After testing
  • Will collect
  • Won’t collect
  • Not licensed

Results panel visible from the first second and primed with what’s about to be checked — never an empty box.

Two smaller calls followed from the same logic.

Connect is gated on a test

“Find out later” was the original defect, so Connect stays disabled until a test has run. The two buttons also do different jobs — one validates the vendor’s credentials, the other validates ours — which keeps it clear which side failed.

Re-testing never wipes the result

Rows resolve in place as each check returns, rather than the panel clearing and repopulating. A failed re-test doesn’t erase the record of what was working ten seconds earlier.

Chapter 06
The last question

How does this survive after I stop looking at it?

A screen decays. A component gets inherited. So the outcome wasn’t a mockup — it was a page in the shared design system: six entity chip states, five result panel tones, and the rules for when each applies.

  • Will collect
  • Won’t collect
  • Couldn’t check
  • Not licensed
  • Testing…
  • +3

One colour changed late and mattered more than its size suggests. Denied entities were originally pink, borrowed from the critical scale. I retoned them amber and reserved pink for things that genuinely don’t exist — because if the strongest colour in the system shows up on a routine missing permission, it means nothing by the time something is actually broken. A colour scale is a promise.

And when the components wouldn’t nest the way I wanted, I shipped the compromise rather than the ideal: the panel header published as a component, the bodies as editable templates. Live instances never broke, and the team could use the pattern that same week.

Problem → Solution

The whole project, on one screen

Problem
What I changed
Why it holds up
“Connected” was shown while half the expected data never arrived.
A test became a report, not a checkmark.
The user’s real question is what will be collected — a property of the whole credential set, which no single field can answer.
Denial, throttling and an empty tenant all looked identical.
Fourteen outcomes in four named families.
Grouping assigns ownership: ours to fix, theirs to fix, or nobody’s fault — so no state is dressed as an error it isn’t.
The result rendered below the fold, unseen.
Two-column modal with a primed results panel.
The panel is never empty and never off-screen; the user knows the scope before committing credentials.
Users could connect without ever testing.
Connect gated until a test has run.
“Find out later” was the original defect. Separating Test from Connect also keeps clear which side failed.
Every vendor seemed to need its own screen.
One composed meta line that absorbs any scope noun.
Accounts, tenants, projects and workspaces all fit one pattern, so integration number 200 costs no new design.
Each new connect flow reinvented its own vocabulary.
Chips and result panels in the design system.
The decision is inherited by the next designer instead of the pixels being copied.

Where It Landed

What shipped, and what it replaced

14 designed outcomes shipped

Across three milestones — test, edit and reconnect — including a stale stored result and a gated update.

One whole screen avoided

The result lives in a panel users already knew, instead of a new page nobody would find under pressure.

A success message that lied, replaced

“Connected” now names exactly what is and isn’t arriving, at the moment of setup.

What I’d do differently

I modelled one flagship vendor in full detail first, and it turned out to be the least representative integration in the catalogue — roughly two weeks of rework. The product lead’s instinct was right and mine was wrong: design the generic case first and treat the biggest, most-demanded integration as the special case it usually is.

All visuals rebuilt with synthetic data. Product and vendor names withheld under NDA.