The project page describes what the flow is and what it asks of a customer, with the public regulatory sources cited. This case study is about the decisions: what we chose, what we rejected, and what each choice cost. No source code, internal documentation, or customer data appears in either.
The problem, stated precisely
A Mexican bank account is not a single product. It sits at one of four levels, and the level is a function of how complete the bank's identity file on you is. At N2, with name, date of birth, official ID and address details, the account may receive 3,000 UDIs a month, around MXN $24,000. At N4, with a fully verified file, there is no ceiling at all.
Payroll customers are concentrated at the bottom of that ladder for a structural reason: the account was opened for them, by an employer, with the minimum file that would satisfy the regulator. Nobody chose N2. They inherited it. And they discover the ceiling the way you discover any invisible constraint: when a deposit bounces.
The bank's answer, before this project, was a branch: bring a physical ID, a utility bill no older than three months, your CURP and your RFC, and a morning of your time. For a customer base that is overwhelmingly mobile, that answer is a filter, not a service.
So the question was not "can we build a form". It was: can the same evidentiary standard a branch officer applies in person be reproduced by someone alone with a phone, and can it be made survivable enough that people actually finish it?
The constraints we did not choose
Four of them, and they shaped everything downstream:
- The framework was decided. The bank builds on its own in-house Web Components framework, layered over Lit and TypeScript. No npm packages, no external component library, no escape hatch. You build with the catalogue the bank maintains or you do not build.
- The APIs predated us. We were consumers, not designers. Data shapes, validation semantics and error codes arrived fixed.
- The team was two people. There was no larger frontend group to absorb complexity: my colleague and me, working directly with design, business analysts, compliance and the API owners.
- Every change carries a review chain. In a bank, shipping is not the bottleneck; getting a change reviewed, tested and approved is. Anything that widened the blast radius of a change was expensive in a way that had nothing to do with the code.
Constraint 4 is the one that did most of the architectural work, and it is worth being explicit about, because it is the piece that does not transfer from consumer software. In a startup, coupling costs you a bug. Here, coupling costs you a review cycle across four modules to change one.
Decision 1: Five modules, not one wizard
The obvious shape for "collect five documents" is a linear wizard: step 1 of 5, next, next, done. It is simpler to build, simpler to reason about, and simpler to instrument.
We built five self-contained modules behind an orchestration layer instead, each with its own state, its own API contracts and its own error handling, and let the customer complete them in any order, across any number of sessions.
Why. Three reasons, in ascending order of weight:
- The regulation does not require one sitting. It requires a complete file. Nothing about the legal obligation implied a linear path, so imposing one would have been a constraint we invented ourselves.
- The documents are genuinely independent. An ID photograph, an address proof, a tax self-declaration, a KYC questionnaire and a beneficiary record share no data and no validation. The seam was already there in the domain; we were choosing whether to honour it.
- It matches how the change chain actually works. A fix to the beneficiary module that cannot possibly affect the ID module is a fix that gets reviewed as one module, not five.
What it cost. A wizard has one state machine; five modules plus an orchestrator have six, and the orchestrator has the hardest job in the system: knowing what is done, what is pending, and what a partially complete file means. It also means five places to get analytics tagging right instead of one, and a test surface that grows with the number of entry points rather than the number of steps.
Was it right? The evidence arrived a year later, and it is in Decision 4.
Decision 2: Failing on the device rather than at the API
The ID and proof-of-address modules are the only ones that leave the world of forms. They need the camera, and a photograph is the one input in the whole flow that can be accepted by every validation layer and still be wrong: out of focus, glare across the hologram, a corner cropped off.
If that judgment is made server-side, or worse, downstream by whatever verifies the document, the customer finds out they failed long after they have stopped paying attention. So the UI takes on work it would be easier to delegate: framing guidance, feedback before capture, an explicit review step where the customer confirms the image is legible before it is uploaded.
This is more code, in the least well-supported part of the stack, to prevent a failure the system could technically survive. It was still the right trade, because the cost of a late rejection is not one retake; it is a customer who has already given up.
Decision 3: Treating analytics tagging as behaviour, not as a side effect
Every module entry and exit, every user action, and every API outcome had to be instrumented against a tagging specification owned by a separate business team.
The tempting way to do this is to sprinkle tag calls into event handlers as the last step before a release. We treated tag emission as behaviour the tests assert, for a reason that is easy to state and easy to underrate: in a flow whose only purpose is completion, the tagging is the sole instrument that can tell anyone which of the five modules is losing people. A missing tag is not a missing analytics row. It is a blind spot in the one feedback loop the product has.
The tagging spec also arrived from outside the team, which made it a genuine interface, the same category of thing as the API contract, and deserving the same treatment.
Decision 4: Rebuilding one module instead of restyling five
In 2024, BBVA introduced a new UX design language and updated internal tooling. The proof of address module, shipped in 2023 on the older UI pattern, was the piece most visibly out of step.
There were three options. Leave it, and accept a seam in the experience. Restyle it in place, cheapest in the short term and the option that quietly accumulates two design systems inside one component. Or rebuild it from scratch in the new system, keeping the existing API contracts so nothing outside the module needed to know.
We rebuilt. Scoping the second MVP to exactly one module out of five meant the regression surface was the module's own contract with the orchestrator, and nothing else; the other four were not touched, not rebuilt, and not re-reviewed.
This is the payoff of Decision 1, and it is worth being honest about the direction of the argument: modularity is usually justified in the abstract and validated never. Here the bet was placed in 2023 and settled in 2024. One fifth of a production banking flow was replaced in isolation, and the customer moving between modules saw a continuous journey.
What made this harder than it looks
The failure states have legal weight. In consumer software an error message is a UX problem. In a compliance flow, what you tell a customer about why their document was rejected is a statement the bank is making about their identity file. The copy is reviewed by people who are not designers, and "something went wrong, try again" is not always an acceptable answer.
Accessibility is not a checklist item here. In 2023 the CNBV, with GIZ, assessed Mexican banks' web and mobile channels against WCAG 2.1 and published recommendations grounded in disability as a protected category. The stakes are concrete rather than procedural: a compliance flow a screen-reader user cannot finish leaves that person permanently capped at MXN $24,000 a month. The camera step is the hard case, and it is the hard case for everyone.
You cannot show the work. No repository, no screenshots of the real thing, no numbers you did not earn the right to publish. That constraint turned out to be clarifying: if the only thing you can carry out of a project is the reasoning, you find out quickly whether the reasoning was any good.
Outcome
The flow shipped to production and serves BBVA México's payroll base, a base the bank publicly reports in the tens of millions, three quarters of it operating through mobile. Its value is structural rather than impressive: it converts a morning in a branch into a task you can finish on the bus, for the specific population least likely to be able to spare the morning.
The architecture held. That is the claim I am most willing to defend, because it was tested rather than asserted; the 2024 rebuild is the experiment, and it came back clean.
Personally, this was the project where I stopped executing tickets and started owning a surface: in the room for the design and business sessions, arguing tradeoffs against compliance and API constraints I could not change, and accountable for the whole delivery rather than a slice of it.
Sources
Regulatory and market figures on this page are public. See the project page for the full source list: Banco de México's Circular 14/2011 and the CNBV provisions under article 115 of the LIC for the account-level scheme, BBVA México's own financial-education site for the N1–N4 ceilings, BBVA's 2024 results for the customer and mobile figures, INEGI and CNBV's ENIF 2024 for payroll account prevalence, and the CNBV/GIZ 2023 accessibility study.
