Unifying transaction lifecycles across fragmented system states
Unifying transaction lifecycles across fragmented system states

A system-level abstraction that makes complex financial states interpretable, consistent, and scalable across the product.

IMPACT

Established a canonical transaction lifecycle across 100+ backend status variations

Redefined how financial activity is interpreted by introducing a transaction abstraction layer that maps 100+ backend status variations across transaction families into 5 canonical lifecycle states.

By shifting complexity out of the UI and into system rules, this created a predictable and scalable model adopted across Design, Engineering, Product, Compliance, and CX.

This abstraction governs every financial event surfaced in the product, across fiat, crypto, trading, staking, and compliance workflows.

CONTEXT

Financial activity lacked a shared system for interpreting what happened to user money

Newton is a regulated financial platform where users rely on transaction records to understand what happened to their money and why.

During a feature freeze tied to CIRO (Canadian Investment Regulatory Organization) registration, I used the window to investigate something no one had formally scoped: how transactions were being represented across the product.

Transactions originate from multiple domains:

  • Fiat transfers (eTransfer, wires)

  • Crypto deposits and withdrawals

  • Trades

  • Staking and rewards

  • Compliance workflows (e.g. Travel Rule, LVCT, KYC)

These systems evolved independently over time.

  • Backend states were shaped by provider and regulatory requirements

  • Frontend representations were built per feature

There was no shared abstraction governing how financial events should be interpreted.

PRODUCT TENSION

Transactions needed to be standardized without breaking backend and compliance complexity

We needed to standardize how transactions are interpreted across the product while preserving backend complexity required for compliance and provider integrations.

The system was already fragmented across transaction types, exposing inconsistent states and lacking a shared model across teams.

This created a tension between:

  • maintaining system correctness

  • providing a clear, consistent user understanding

This resulted in users experiencing:

  • confusion when similar transactions behaved differently

  • difficulty understanding transaction status

  • reduced trust in the system’s accuracy

SYSTEM CONSTRAINTS

Transaction design was fragmented because each flow evolved independently with its own logic

I initially approached this as a UI consistency problem.

There had already been attempts to design transaction sheets, primarily for transfers, but these were:

  • siloed per transaction type

  • triggered reactively by support issues

  • tightly coupled to backend-specific states

This worked because:

  • each flow was treated independently

  • complexity was contained locally

But as the system expanded:

  • instant transactions (e.g. trades) had no detail views

  • transfer flows each introduced their own status logic

  • backend states became increasingly specific and inconsistent

  • assumptions that previously worked no longer held at a system level

This caused:

  • frontend representations to diverge

  • users to interpret similar financial events differently

  • teams to lose a shared understanding of transaction meaning

Audit of transaction states across systems.

I mapped 100+ backend status variations across transaction families, revealing duplicated meanings, legacy states, and inconsistent lifecycle logic.

PROBLEM EVOLUTION

UI standardization failed because there was no shared definition of lifecycle across transactions

I reframed what initially appeared as a UI standardization problem into a system-level modelling problem.

When I placed all transaction flows and their corresponding designs side by side, it became clear:

  • each transaction type followed a different system model

  • statuses were inconsistent in meaning and level of detail

  • similar lifecycle stages were expressed differently across flows

Examples included:

  • “delay/issue” vs “pending” vs “completed”

  • transfer-specific states that didn’t translate across other transactions

The moment the previous approach broke was:

when we attempted to standardize transaction sheets and realized there was no shared definition of lifecycle across the system

Without a unified model, standardization at the UI level was not possible.

Fragmented transaction models across the product.

Each flow represented lifecycle differently, making it impossible to standardize the UI without first defining a shared system model.

WHY OBVIOUS SOLUTIONS FAILED

Neither backend standardization nor UI-level fixes could solve the problem at scale

Neither backend standardization nor UI-level fixes could solve the problem at scale

One approach was to standardize backend states. However, this was not feasible due to:

  • provider-specific requirements

  • regulatory constraints

  • existing system dependencies

Another approach was to normalize inconsistencies at the UI layer per feature. This led to:

  • duplicated logic

  • inconsistent interpretations

  • increasing divergence over time

Neither approach created a scalable or maintainable solution.

CORE INSIGHT & GOVERNING PRINCIPLE

The solution was to define a system that translates backend complexity into consistent user meaning

The key insight was: The problem was not backend complexity, it was the absence of a shared model translating that complexity into user meaning.

I reframed the problem from simplifying backend complexity to defining a stable system for interpreting it.

Governing Rule

All financial events must be interpreted through a stable lifecycle abstraction:

  • Every backend state maps to a canonical lifecycle state

  • Lifecycle communicates progress and outcome, independent of transaction type

  • Conditional requirements are expressed as flags, not new states

Defining a stable interpretation layer

Backend complexity translated into a canonical lifecycle model.

The lifecycle abstraction became the interpretation layer between backend states and product behaviour, allowing complexity to remain intact while presenting consistent user meaning.

To operationalize this, I introduced a lifecycle abstraction by:

  • Separated lifecycle, type, and conditional logic

  • Defined a fixed set of lifecycle states

  • Mapped backend complexity into a consistent interpretation layer

This allowed backend systems to evolve independently while maintaining a predictable user-facing model.

Want to see how it came together?
Want to see how it came together?

The implementation and outcomes involve sensitive system architecture from a regulated financial platform. Use the request button on the next page to get in touch.

KEY DECISIONS AND TRADEOFFS

Prioritized consistency over specificity and scannability over density

Tradeoff #1: Specificity vs Clarity

  • Reduced highly specific backend states into broader lifecycle categories

  • Example: “delay with this transaction” → “Action Required”

This reduced cognitive load at the cost of losing granular, system-specific detail that could be useful in edge cases

Tradeoff#2: Density vs Scannability

Introduced a standardized transaction sheet instead of exposing all data inline, which required users to tap open a detail view to access full information.

We accepted initial friction from users expecting inline detail, in exchange for:

  • faster information parsing

  • consistent layout across all transactions

  • a model that scales across all financial activity