← Back

FINTECH · DESIGN SYSTEM · 0→1, THEN SCALE

A design system you can run,
not just read

I built the token architecture, component contracts and governance for a B2B fintech platform's design system — then rebuilt the parts I got wrong, on the record.

  • Design system
  • Token architecture
  • Figma to code
  • Governance
Role
Lead Product Designer · design system owner
Product
B2B fintech platform for operations teams
Scope
Tokens, component contracts, documentation, governance

Reconstructed catalog shown for public-safe storytelling. Client name, brand marks, counterparties and amounts are adapted or invented. No proprietary metrics appear here.

Semantic colour ramps in the live catalog, every step resolved for light and dark
Live catalog · Semantic colour ramps

The decisions are the system, so I made them the artifact.

Component count is the usual measure. The one that predicted whether this system survived a team change was whether a decision could be found, questioned and reversed.

01

25 decisions of record

One decision per file, numbered and never reassigned. Two superseded, one deliberately left open.

DECISION REGISTER
02

3 layers, one owner each

Tokens in Figma variables, components built twice, mapping in Code Connect. No layer has two owners.

ARCHITECTURE
03

2 kinds of contract

Form drift for every component; value correctness for anything that renders money or a number.

VERIFICATION

Delivery outran its own documentation.

The platform grew from its first flows into a complex fintech product, and the system grew with it — unevenly. We were not short of components. Nobody could tell which version of a decision was current, so teams re-litigated settled questions and quietly diverged.

  1. 01
    Decisions had no homeOne file, three logs

    Durable decisions lived as dated callouts across four places.

    NOT FINDABLE
  2. 02
    Docs contradicted themselvesMeasurable drift

    A retired tool stayed named as source of truth for five weeks.

    OBSERVABLE COST
  3. 03
    Two token systemsDivergent primitives

    Parallel sets defined different greys, radii and font stacks.

    FRAGMENTATION
  4. 04
    Catalog disagreed with productOne button, two specs

    The documented button and the shipped button were not the same.

    DRIFT

One source of truth per layer — and no sync between them.

The tempting fix is bidirectional sync between design and code. I ruled it out. Components are built twice, deliberately, and alignment is enforced by a contract and an automated check rather than by a pipeline that pretends two representations are one.

  1. 01
    TokensFigma variables, one-way

    One source, one direction, so there is no merge to arbitrate.

    SOURCE
  2. 02
    Semantics alias primitivesNo chaining

    A semantic token points at a primitive and nothing else.

    CONSTRAINT
  3. 03
    Figma is a ceilingMerged token layer

    Figma variables plus a hand-authored layer, merged in the build.

    PIPELINE
  4. 04
    Agnostic core, module UIInstantiate, don't copy

    A structure copied per module does not scale, it multiplies.

    LAYERING
  5. 05
    Third-party as dependencyNever a fork

    Consumed at a version. A fork is a liability, not a shortcut.

    BOUNDARY
Type scale, spacing and radius tokens rendered from the token layer
Live catalog · Type scale, spacing and radius

In a financial interface, a misleading number is a defect.

The platform's principles were already written. My job was the design-system reading of each: what a component must actually do to honor it, and how it fails. That turned three sentences into enforceable rules.

01

Numbers must not mislead

A negative sign is always visible and never carried by colour alone. Rounding never silently loses precision. The positive and negative pair passes AA independent of colour perception. These are correctness rules, so they are a contract — not a guideline.

VALUE CORRECTNESS
02

Meaning must survive the mode

Where colour carries financial meaning, a mode in which that meaning degrades is a correctness bug. That is why light and dark ship together: a component is not done until both modes are done.

ONE RELEASE
03

Generated values don't borrow confidence

AI state got its own semantic namespace inside the existing collections, so an accent meaning "the model is unsure" is never the accent meaning "payment pending".

AI TOKEN GROUP
A destructive confirmation pattern shown with its do and do-not guidance
Live catalog · Destructive confirmation, with Do / Don't

The system holds because changing it is deliberately hard.

Every rule here exists because its absence had already cost us something. Rules this specific are cheap to follow; vague ones get ignored.

01

Foundation changes are gated

No foundation token change without an eight-step gate that starts with a written proposal naming the rationale, the affected surfaces and the migration. Token changes are wide-impact by definition.

EIGHT-STEP GATE
02

Triage starts at gate zero

Before any new component: does the reference system already solve this well? The answer gets written down either way, so the same question isn't re-argued next quarter.

REUSE BEFORE CREATING
03

Ownership is split, not shared

Design never touches component code; engineering never invents design. The token package is the contract between them. Shared ownership of the same artifact is how drift starts.

DESIGN / CODE BOUNDARY
04

The check doesn't certify the work

A deterministic check with no AI in it sits between the build and human review. Red means something changed, not that it is wrong. A human still decides, but starts from a diff instead of a blank page.

VERIFICATION
Accessibility checks that block a release when they are violated
Live catalog · Accessibility violations block release

Six designers and four pods on the same primitives.

Most of the product surface now renders from the system, and two people keep it current. The change I valued most is harder to count: once the primitives were settled, design review moved off spacing and onto whether the flow was right.

01

80% of the product surface

Rendering from system components, not one-off styling. The rest is legacy, on a known path.

COVERAGE
02

6 designers across 4 pods

Every pod shipping from the same primitives, so a component decided once didn't get re-decided in parallel three more times.

CONSUMERS
03

Maintained by 2 people

Me and one developer. The register answers most questions without either of us.

LEVERAGE
04

~35 components

Deliberately small. Gate zero asks if the reference system already solves it.

LIBRARY
05

64 semantic tokens

Every one resolved in both light and dark, so theming is a token concern and never a component override.

FOUNDATION
06

25 decisions on record

Two superseded, one still open. New designers onboard by reading why, not by asking someone who remembers.

GOVERNANCE

Figures describe the system artifact — component, token and decision counts are countable in the repository. Coverage and team numbers are my own, stated without client-identifying detail.

Every component renders in isolation before it ships.

The catalog renders components in isolation so their API, states and behaviour are proven before they reach the product. It is the shared reference between design and engineering, and it is executable — you can open it, change a prop, and flip the theme.

The catalog opens in full screen. Colour ramps, type scale, components, patterns and the theme switch are all live.

An escrow account component rendered in isolation in the catalog
Live catalog · A component rendered in isolation

Two decisions were wrong. The register is how I found out.

An accepted decision is never edited to change its meaning — a new one supersedes it and the original stays as history. That rule is uncomfortable by design, and it is the reason these are visible at all.

01

I named the wrong documentation home

"The showcase app" was ambiguous and pointed at the wrong one. Superseded once the product's own component catalog became the home and the showcase became reference only.

SUPERSEDED
02

I was wrong about the runtime twice over

I recorded that the framework version inherited no headless behaviour. Both premises turned out to be wrong — the version and the behaviour source. The replacement names the real runtime and specifies accessibility behaviour per component.

SUPERSEDED
03

One decision is deliberately unmade

What supplies interaction behaviour going forward is still open. The evidence is gathered so it is not re-derived, and the record names the conditions that should trigger the decision. Proposed is not allowed to quietly become permanent.

OPEN
04

Open constraints are listed, not hidden

Unverified assumptions carry a verification date, so a stale constraint is visible as stale rather than mistaken for a fact.

IN PROGRESS

What I'd do earlier next time

The architecture held. The thing that nearly sank it was that decisions had nowhere to live for the first stretch, and recovering that history cost more than recording it would have.

  1. 01
    Start the register on day one

    Reconstructing six months of reasoning costs far more.

    Record
  2. 02
    Write the failure test

    A principle that cannot be failed cannot be applied.

    Apply
  3. 03
    Automate drift detection first

    A check that says this changed beats ten more components.

    Verify
  4. 04
    Close the catalog-to-product gap

    Nothing failed when they diverged. That check comes first.

    Enforce