NDA periods are strange. You do some of the most interesting work of your career and then spend several years saying nothing about it. Mine just expired on a project I've been wanting to write about since we delivered it.

The project

The client was one of the largest banks in Europe. Thousands of branches across the continent. Not a regional player — a systemic institution with millions of active customers. The goal was straightforward and slightly aggressive: close the majority of physical branches and move customers to the app.

The way they approached it was smart. Instead of handing the entire project to one vendor, they divided the work into independent modules and distributed them across several contractors. Each team delivered a scoped piece; a central integration team stitched it together. 3S Coding was one of the contractors. Our scope: digitize what the teller does.

Context I can speak to our piece of the project, not the full system. What we built, what we learned, and what surprised us — within the scope we owned.

What we moved to the app

This sounds simpler than it was. Bank tellers handle dozens of transaction types, each with its own validation rules, compliance requirements, and exception paths. We covered three main areas.

Fund transfers and recurring payments

Domestic and international wire transfers, bill payments, standing orders, and scheduled future payments. All of these required a branch visit — either because the customer didn't trust online banking, or because the bank hadn't built a reliable digital path for them yet.

The scope wasn't just building the UI. It was mapping every validation rule the teller applied manually — beneficiary verification, daily limits, sanction screening, currency conversion logic — and encoding it into the application so it ran consistently, without human judgment filling in the gaps.

Document-heavy account services

KYC updates, address changes, beneficiary additions, account upgrades, and new account applications for existing customers. These are the workflows that required physical paperwork and a counter because the bank needed verified identity and wet signatures.

Replacing that required integrating with identity verification services, building document upload flows with backend validation, and handling the cases where verification fails or returns a partial result. The regulatory requirements on this part were non-trivial — each country the bank operated in had slightly different rules.

Financial product applications

Loan applications, credit facility requests, foreign exchange orders, and term deposit openings. These workflows are longer — multiple steps, conditional logic depending on customer profile, document requirements that vary by product and jurisdiction.

The teller used to guide customers through these in person. The app had to do the same without the human. That means clear state management (where are you in the process?), robust save-and-resume logic, and explicit handling for the cases where the application gets stuck mid-flow.

Three things I didn't expect

The technical scope was demanding but predictable. What I didn't fully anticipate were the things the bank treated as baseline requirements that I'd never dealt with at this scale before.

Banks watch the dark web

This one genuinely surprised me. The bank ran continuous automated monitoring of dark web forums and marketplaces — not reactively, but proactively. Scanning for leaked credential sets, compromised card numbers, and exposure from third-party breaches. When a match appeared, the account got flagged or suspended before the attacker could act on the data.

The implication for us: we had to build against externally-triggered account suspensions that could happen at any point — including mid-session, mid-transaction. Most developers treat security as something that happens at login. In banking, an account can be suspended while the customer is in the middle of approving a payment because a credential dump appeared on a forum twenty minutes ago.

Security reality check Authentication is the beginning of the security story, not the end. Design every screen assuming the session state can be invalidated at any point — by the user, by the system, or by an external security event.

Scalability is a design problem, not a hardware problem

A bank with thousands of branches has millions of active users. And those users are not uniformly distributed across the day. Salary day, end of quarter, tax deadlines, national holidays — traffic spikes are predictable in timing but brutal in intensity.

The naive approach to scalability is "add more servers." That solves maybe 40% of the problem. The rest is design: database locking strategies, transaction queues, idempotency keys, read replicas for high-read operations, cache invalidation logic that doesn't create race conditions. If your transaction logic holds a database lock for 400ms under normal load, it will cause cascading failures at 10x traffic — regardless of how many servers you've provisioned.

The lesson isn't that you need to over-engineer every project. It's that scalability decisions made during design are cheap. The same decisions made after launch are expensive and often require rebuilding core logic under pressure.

You don't scale a financial system by adding servers. You scale it by designing it so that servers can be added without everything breaking.

Error handling is the product

This is the lesson I carry into every financial project now. In most software, an error is a bug to fix. In banking, an error mid-transaction is a legal and financial liability.

If money leaves Account A and doesn't arrive at Account B — and the system cannot explain exactly what happened and prove that nothing was lost — that's not a software issue. That's a regulatory incident. It triggers audit procedures, customer compensation requirements, and potentially reporting obligations depending on the jurisdiction.

We built every transaction flow by answering three questions before writing a line of logic: what happens if this fails halfway through? Can this operation be safely retried without double-executing? What is the exact rollback path?

Idempotency keys on every state-changing operation. Dead letter queues for failed transactions with enough context to reconstruct what was attempted. Transaction logs granular enough to answer "at what exact point did this fail and what was the system state at that moment?" These aren't features. They're the minimum.

💡
First step: Before automating any financial or high-stakes workflow, map the failure paths first — not the happy path. The happy path is easy. The question is: what does your system do when step 3 of 5 fails at 2am with no one watching?

The bank got what it was after. Branches closed. Customers moved to the app. The volume that used to require a teller and a counter got absorbed by software we helped build — running reliably, at scale, without anyone standing behind a desk.

That's what automation at this level looks like when it works. Not magic. Just a very long list of edge cases, handled correctly, every time.