Selected Work — 01

FlowX.AI

A low-code platform that lets financial institutions build digital processes (mortgages, loans, onboarding) in weeks instead of years, without writing them by hand.

Role
Product Designer — Research, UX, UI
Team
Core → Rendering
Platform
Web, low-code
Timeframe
Sept 2024 – present (~2 yrs)

FlowX is built around BPMN (Business Process Model and Notation), a flowchart-style way of modeling a business process precisely enough for software to run it directly, with no separate build step in between. A bank configures a mortgage application, a loan approval, a KYC check, or an onboarding flow, each with its own steps, roles and business rules, as a visual process instead of custom code. That process is also the platform’s main artifact: the thing a configurator opens, edits, and hands off between teams.

I started in the Core team, which owns that process engine and how it’s configured, then moved into Rendering, the team that turns a configured process into the interface an end customer actually uses. The move was deliberate: exploring across the platform rather than staying in one lane, working closely with the AI team (the chat agent and its workflows) and the MVP team throughout. Across both, the throughline was the same: make a genuinely technical, high-stakes platform legible to the people configuring it directly, covered chapter by chapter below (merge conflicts and versioning, library-to-library dependencies, UI Flows and its chat agent, and the config panels).

Separately, I rolled out Dovetail as the shared research tool across the organization, before any AI tooling entered the picture, and later helped build a Claude Skill to synthesize interviews and extract insights. The human research practice came first; the AI accelerator came after.


Chapter 01

Merge conflicts & versioning

Processes in financial institutions used to take weeks to build, because two teams changing the same process at the same time had a very difficult time understanding what had changed between versions. There was no way to compare changes, no list of what had moved. And because it’s a low-code platform, most of the people actually configuring it for the client couldn’t read raw JSON or JavaScript to begin with.As a workaround, when merging two versions, they’d copy the code into VS Code just to read it, then come back and try to resolve the conflict on the platform itself.

The solution: translate a block of code into bite-sized, plain-language change descriptions, each tied to a clear location in the process, so the configurator could see what changed and where, with a clear path to the part in question, without reading the underlying code at all.

Finding the conflict

  • A conflicts overview lists every affected resource up front, so configurators can work through them one at a time instead of guessing where the conflicts even are.
  • Search across the process to jump straight to the part in conflict.
  • The tree is split by BPMN structure (process settings, swimlanes, tasks, actions), so a code block always comes with the context of where it lives.
  • A breadcrumb keeps the exact conflict path visible, e.g. User Task 1 › UI Elements › Container › Card › Onboarding Form.
  • Collapsed tree branches show a count, so nothing conflicting is hidden without a trace.

Resolving it

  • A clear default: unless a branch is chosen explicitly, its changes are what get prioritized when a conflict is left unresolved.
  • Raw JSON is translated into readable, formatted content per resource, with the actual diff highlighted.
  • Conflicts can be marked resolved one at a time, or for an entire process at once.
  • A deleted resource shows a clear “deleted in your version” state instead of a blank, missing code block.
  • Color coding distinguishes items still in conflict from items already marked resolved.
  • Progress can be saved as an intermediate state, rather than needing to resolve everything in one sitting.

The same conflict, before and after: a raw three-way JSON diff becomes a navigable, resolvable view, organized by where each change lives in the process.

The redesigned merge-conflict view: a conflicts tree organized by process structure, a breadcrumb path, and per-resource diffs that can be marked resolved
The same conflict, before and after. Toggle to compare; it opens on the redesign.

Before jumping into code, users get an overview of where the conflicts are and can take them one by one for each resource.

There is also a clear indication of what happens if no conflicts are resolved (what changes are prioritized by default).

The Merge Conflicts Detected modal, listing every affected resource up front before diving into any of them

Split view by BPMN process parts, for easier context around code snippets.

Counter for collapsed categories.

Color coding for items with conflicts vs. items marked as resolved.

Search for specific parts of the process.

Possibility to open the specific code block translated into content, for easier recognition of conflicts and changes.

Clear indication when something doesn't exist or was deleted, instead of showing a missing code block.

Clear conflict path.

The Mortgage Simulator conflict view: a BPMN-structured tree on the left, a breadcrumb conflict path, and a per-resource diff with a deleted-in-your-version state
The redesign, annotated: an overview up front, structure-aware navigation, and readable per-resource diffs.

Merge resolution that used to take days, sometimes weeks, came down to days. Teams could now collaborate on the same process directly instead of working around each other, and the feedback from the client was strong.

We have expected this for quite some time now. Now the merge doesn’t fail anymore, and we can continue delivering at a fast pace.

— Configurator, at a top Romanian bank

Roughly five months, alongside other design work.

Comparing versions

Before even reaching a merge, configurators working on a project needed to know what had changed between two branches, to better anticipate any conflicts ahead of time. It also helped them understand more about the progress their teammates had made, with a bigger overview of the project as a whole.

Clicking into a branch surfaces the resources that changed and their type, color-coded by the kind of change: green for added, yellow for edited, red for removed, all relative to the previous version. Toggling compare mode lets configurators pick any two versions directly, not just adjacent ones, to see the progress of the project at any point in time.

When clicking on each branch, users would see on the left side the resources that have been changed, and their type, as well as the type of change indicated by color (green for add, yellow for edited, red for removed).

Those changes are relative to the previous version.

Clicking into a branch surfaces the resources that changed and their type, color-coded green for added, yellow for edited, red for removed
Clicking a branch: changed resources, color-coded by the kind of change.

Overview of versions being compared, including last edited date, user, name, and whether it's committed or not.

Clear visual indication of what versions are selected.

Compare mode: picking any two versions directly to see an overview of what changed between them
Compare mode: pick any two versions directly, not just adjacent ones.

Chapter 02

Library-to-library dependencies

Large customers don’t build one app; they build a portfolio of them, and organize the shared parts (business processes, enums, templates, models, common logic) into reusable libraries. The catch: a library could only be consumed by a project, never by another library. So every domain team that needed the same KYC flow or the same customer model kept its own copy.

At the scale these organizations work, that copying compounds: the same logic duplicated across libraries, versions drifting apart, maintenance that means editing the same thing in five places, and a coordination tax between teams that grows with every new library. The design challenge was a dependency system that scales to hundreds of reusable resources while staying understandable and predictable: powerful underneath, calm on the surface.

Before · every library keeps its own copy
Mortgage Library
  • Customer Models
  • Enums
  • KYC
Lending Library
  • Customer Models
  • Enums
  • KYC

The same resources, copied into each library: duplicated logic, drifting versions, high coordination cost.

After · one shared foundation
Mortgage Project
Mortgage Library
Lending Library
Core Banking Library
Customer ModelsEnumsKYC

Shared resources live once, in a foundation both domains build on: defined in a single place, inherited everywhere.

Building on top, not copying across

The model I designed lets a library reference another library as a dependency instead of duplicating its assets. Shared resources are defined once and inherited everywhere downstream.

Making that safe meant deciding things before they could go wrong. A dependency is locked to a specific build when it’s added, so a foundation can move forward without silently shifting under everyone.

When two builds meet

Across hundreds of resources, two builds of the same library will eventually meet in one tree. Rather than asking a user to work that out from scratch each time, precedence follows a simple rule they can predict: the project’s own resource wins, then the closest library in the tree, with the newest build only as a tie-breaker. The same inputs always resolve the same way.

Project resourcealways wins
↑ takes precedence over
Closest librarynearest in the tree
↑ takes precedence over
Newest buildtie-breaker only
The Dependencies page for a project, listing subprocesses and libraries as a nested tree with current and new build versions; a conflicting Enums Library is flagged in red with a tooltip explaining that it already exists as a dependency
The Dependencies page: a project's tree of subprocesses and libraries, current and new builds side by side, conflicts flagged in red.

The payoff is architectural: enterprise teams can build modular, layered solutions, keep business definitions consistent, own their domains independently, and manage versions without fear. One update to a foundation propagates through everything built on it, instead of being re-typed into each library by hand.

Before that: copying resources

This wasn’t the first attempt at reuse. Before libraries could depend on libraries, we explored a more direct move: letting teams copy a resource (a process, a screen, an asset) from one project into another, together with everything it depends on.

It solved the immediate need and created a harder one. A copied resource could reference a library that already existed in the destination, but on a different build. As projects grew interconnected, the questions stacked up: keep the copy’s version, or the destination’s? What happens when several resources each need a different build of the same library? And, above all, how does someone see the consequences before they commit to them?

The design job wasn’t to expose the dependency machinery. It was to explain a genuinely complex situation in the simplest honest way, so a configurator could decide with confidence.

Copying from · Mortgage
kyc_process
└ error handling
  build 1.5.0
Into · Onboarding
error handling
build 1.6.0 (already here)

One library, two builds: 1.5.0 arrives with the copy, 1.6.0 already lives in the destination. Which one should win, and what breaks either way?

Three states, three moods. A plain copy shows New Dependencies: a calm preview of what’s about to be added. A version clash escalates to Dependency Conflicts Detected, with only the conflicting versions in red and a plain note that some usages may need fixing afterward. A copy that would create a loop is simply refused, in plain language: a circular reference, not a cryptic error.

The hardest case, several conflicts at once, gets its own view: Dependency Changes. New dependencies and version conflicts fold into one tree, so a single decision covers the whole impact. Depth by indentation, versions aligned on the right, red reserved for what actually conflicts: the hierarchy alone keeps a dense situation readable.

Four states of the copy-resources dialog: New Dependencies previews what will be added; Dependency Conflicts Detected flags libraries that already exist on a different build in red; a circular-reference case is refused in plain language; and a combined Dependency Changes view folds new dependencies and conflicts into a single tree
The copy-resources dialog across four states: a calm preview, a version conflict, a refused circular reference, and the combined view that carries the hardest case.

This exploration is what pointed to the library-to-library work. Once the real unit wasn’t a copied resource but a shared dependency, the problem changed shape: from reconciling one copy at a time to managing whole dependency trees on purpose. The same underlying question, asked better: how do you make a complex system legible enough that people trust their own decisions inside it?


Chapter 03

UI Flows

BPMN was, and still is, the platform’s core. UI Flows didn’t replace it; it sat alongside it. The heavier processes stayed in BPMN, while UI Flows handled the simpler things that never needed a full process behind them: standalone pages, dashboards, client-360 views (a single all-round view of a client). It grew out of two practical needs. The platform was moving toward SaaS (software as a service), where standalone pages were suddenly in demand, and clients were asking for configurable chat agents.

The first version of its navigator shipped fast, because speed was genuinely needed. It showed:

  • Switching the page felt disconnected from the rest of the navigator.
  • Adding a new page while viewing another momentarily read as “my first page got deleted.”
  • The collapse/expand icon on the tree didn’t communicate its function; there was a lot of hesitation around it.
  • No process-like diagram existed for UI Flows. Joining a project meant real effort to figure out “which button leads where,” since navigation was buried inside each element’s event handlers, with no overview.
Navigating a UI Flow: pages and the sitemap view. Click, or tap, to play.
Adding components to a page, with the Components Tree updating as you build. Click, or tap, to play.

In hindsight: push earlier for a more considered first pass, by making a stronger case for it up front rather than optimizing purely for speed.

The navigation that shipped: a single vertical panel in the UI Designer’s left sidebar, split into two stacked sections. Navigationis a flat list of the flow’s root-level items (Pages, Tab Bars, Global Components). Components Tree is the full nested tree of whatever root or global component is currently selected. The two sections share one resizable vertical split, with the Components Tree taking two-thirds of the panel by default.

A newly created or reopened UI Flow opens directly on the Navigation tab, not the components list. Structure gets defined first (pages, header, footer), so that’s the natural starting point rather than an empty tree.

A newly created UI Flow open on the Navigation tab, with the pages list and an empty canvas
A new flow opens on Navigation: structure first.
A populated UI Flow with the Components Tree expanded under the selected page, and the page laid out on the canvas
A populated flow: the Components Tree under the selected page.

Chat & the AI agent

The chat component was the largest and most complex piece added for UI Flows. It meant designing both the chat UI itself and the agent-type workflows behind it. Over roughly six months, features arrived gradually: suggested prompts, notifications, the ability to upload and read documents, actions, and feedback.

  • Message actions: copy message content, see the exact timestamp.
  • Search across every past conversation by keyword.
  • Chat sessions can be disabled once the linked business case reaches a status that no longer allows further interaction.
  • Notifications surface new information in the chat with a visual cue.

The main challenge was understanding the needs of different clients’ chat use cases and prioritizing which to support. Some needed a floating chat; others a fixed interface where the content changed based on chat input; others a large, dedicated page with chat alone. That meant staying flexible while working within real technical constraints. A lot of small features folded into one component, needing fast delivery, attention to detail, and clear prioritization.

The shipped chat interface across five screens: a new chat with suggested prompts, a reply in progress, conversation history, and document-aware responses
The shipped chat interface: suggested prompts, conversation history, and document-aware replies.
The chat in use. Click, or tap, to play.
Configuring the agent behind it: the conversational workflow builder. Click, or tap, to play.

Chapter 04

Config panels

The UI Designer’s config panel had aged out of step with the rest of the platform, full of form elements and interaction patterns that no longer matched. Feedback came directly from configurators on what they actually needed from it, and what they didn’t.

At the same time, a colleague on the MVP team was independently redesigning the Process Designer’s config panel, moving it from a bottom console to a side panel, the same pattern the UI Designer already used. Good for consistency, but it broke something. Referencing a Node Action from inside the UI Designer panel used to open the Process console on top, so a user could see the action’s context (business rules and so on) without losing their place. Once Process’s panel became a side panel too, that overlay no longer worked: two side panels wanted the same space at the same time.

Explorations ran in parallel with my colleague on both panels. A PR (pull request) built with Claude Code then stood up both panels quickly enough to test them against each other, rather than mocking them separately and guessing how they’d interact.

SolutionChallenge
Cascading side panelsDouble save is unclear. It’s hard to tell which one is being saved first.
Replace content in place, with a way to navigate backThe same double-save problem resurfaces, and users lose context navigating back and forth.
A “go to” button opening full config in a separate browser tabIntroduces tabs into the configuration flow, which the team didn’t want.
Open the referenced context in a modal, reusing the testing-modal patternInconsistent with the node config side panel: the same information ends up presented two different ways.

The panel that shipped: replacing content in place, with a way to navigate back. The referenced context takes over the panel rather than stacking a second one, with a path back to where you started.

The UI Designer config panel replacing content in place, with a way to navigate back to where you started
The UI Designer panel replacing content in place, with a path back to where you started.

Stronger overall visual consistency, and a more mature product perception, meaningfully so given the platform’s positioning as SaaS, where that kind of polish reads as credibility. Practically: less time spent configuring, and fewer panic clicks: the back-and-forth save clicks and the parallel tabs people opened out of uncertainty about what they were about to lose.

Across merge conflicts, versioning, library dependencies, UI Flows and config panels, the throughline held: make a low-code platform legible to the people who actually configure it, so they can move fast without fear of breaking what came before.

Photography during nature hikes in the Azores, 2026.