Skip to content
All case studies
Payments / Fintech·Senior Full-Stack Developer·2026

Documenting a system nobody fully understood

A legacy platform with no documentation and business logic split across four codebases. I reverse-engineered it into a 138-page reference that mapped roughly 820 legacy actions to their replacements, so the migration ran against a map instead of guesswork.

138
pages, sole author, from scattered wiki notes
~820
legacy actions mapped to their replacements
4 → 1
source codebases reconciled into one reference

Stack

Nuxt ContentDocusMarkdownMermaidInformation Architecture

In one line

I turned a legacy platform that lived only in the heads of whoever had touched it last into a 138-page reference that mapped every legacy action to its replacement, so the migration was archaeology done once and written down, not re-discovered by every developer who touched a module.

The problem

The legacy platform had effectively no documentation. What existed was a handful of stale wiki pages, scattered and contradictory, plus tribal knowledge that left the building whenever someone did. The business logic for a single feature was routinely spread across four codebases: a first-generation SOAP webservice, a second-generation JSON-RPC service, an aging frontend, and a separate UI app.

That is a bad place to start a migration from. Every module a developer picked up began the same way: hours of grep-driven archaeology across four repositories to answer one question - what does this actually do today, and where? The same excavation happened again the next time someone touched an adjacent feature, because the answer was never written down.

The migration could not be estimated, sequenced, or parallelised while the ground truth lived only in code nobody wanted to read.

What I built

A documentation portal (Nuxt Content / Docus, Mermaid diagrams), sole author, that grew to 138 pages across five sections: general reference and glossary, backend, middleware, frontend, and the migration itself. It was not a wiki of prose. It was structured to answer the questions the migration actually asked.

1. A gap analysis that mapped the whole legacy surface

The centrepiece. A domain-by-domain comparison of legacy versus new, covering all 14 feature domains, that quantified the entire legacy surface: roughly 820 legacy actions, against which the new stack's endpoints were tracked. For every feature it recorded the exact legacy source and its new-stack replacement:

FeatureLegacy sourceNew stack
Login / logoutV2 Auth/AclAuth module, 11 endpoints
MFA (TOTP, email OTP)V2 Acl.activateMultiFactorAuthenticationdedicated endpoints
Password resetV2 Acl.forgotPassword / resetPassword3 endpoints

Multiply that across 14 domains and hundreds of actions. The result answered, on one page, the question every developer had been re-deriving by hand: this is what exists, this is where it lives, this is what replaces it, and this is how much is left.

2. A live migration tracker

Every feature across API, middleware and frontend, with a status legend (complete / in progress / documented / not started / partial / skipped) so anyone could see the true state of the migration without asking. Phases were planned against it; ownership was assigned against it.

3. A migration document per module

Each module got its own document written before implementation began: what was being extracted, from which legacy sources, into which new module boundary, with the file-by-file breakdown of the new structure. The document was the plan and, afterwards, the record.

4. The reference layer

A 70-entry glossary that pinned down the domain vocabulary (the same term meant different things in different legacy apps), plus architecture, tooling and convention pages, so a decision made once did not get relitigated in every review.

Why it mattered

It changed the unit of migration work from "excavate, then build" to just "build." The most expensive part of each migration - reconstructing what the legacy system did and where - was done once, by me, and written down. Every subsequent developer, and every AI-assisted session, started from the map instead of the grep.

It made the migration estimable and parallelisable. You cannot sequence work you cannot see. The gap analysis turned "the legacy system is a black box" into "627 of 820 actions remain, here are the hard ones, here is the order" - which is the difference between a plan and a hope.

It survived its author. The whole point of writing down where every piece of legacy logic lives is that the knowledge stops walking out of the door. The platform went from "ask the person who last touched it" to "read the docs" for every future hire.

What I would tell someone starting this

Document the questions, not the code. Nobody reads a wiki that mirrors the source. They read the one page that answers "where does this live and what replaces it," so build the reference around the decisions people actually make.

The map is worth more than the territory when the territory is four codebases. The single highest-leverage artefact was not any module's documentation; it was the one table that reconciled four legacy sources into one view. Build that first.

Write the migration doc before the migration. A plan written down is a plan that can be reviewed, estimated, and handed off. Written afterwards, it is just a changelog.

Let’s build something that lasts

Hiring a senior engineer or architect for a remote team? I work across EU and US time zones - tell me what you're building.

Newsletter

I write about software architecture, PHP, Vue, TypeScript, and developer experience. No spam, unsubscribe anytime.

Copyright © 2026. All rights reserved.