All case studies
Case study 02 · Nurun · 2023–present

Modernizing a 10-year-old platform without stopping delivery

As frontend tech lead on a multi-brand automotive account, I modernize a 10-year-old content-driven Java platform while three squads keep shipping. Instead of a rewrite, client work becomes the vehicle for improving the stack, one module and one block at a time.


Role
Frontend tech lead, supporting 3 squads (~15 people)
Client
Large multi-brand automotive client, through Nurun
Stack
Java with FreeMarker, AngularJS, Vue.js, Vite, Playwright
Scope
Feature architecture, platform modernization, build and CI, testing, team coaching

2×faster CI on every pull request

3squads kept shipping

10+years of legacy, modernized in place

01Context

The client platform is a content-driven Java application with more than 10 years of history. Pages are built entirely from content: authors place blocks into page zones, and everything is stored in Sling. It renders on the server with FreeMarker, with legacy AngularJS on the frontend. Before I joined, Vue.js had been chosen to gradually replace AngularJS.

The hardest part isn’t any single technology. It’s the mix of legacy and newer stacks, along with architecture decisions that made sense at the time but didn’t scale.

As frontend tech lead, I define the technical approach for every new feature, support three squads of about 15 people, and am responsible for improving the project’s frontend stack.

02Challenges

The platform had to keep shipping for the client while it changed.

  • 01

    No time or budget of its own

    Modernization has no dedicated resources. Client priorities always come first, and there’s no long-term vision for where the platform should go.

  • 02

    No full rewrite

    A complete AngularJS migration wasn’t an option, so modernization has to happen inside client work.

  • 03

    Code all over the place

    Frontend code is scattered, and there’s no full inventory of existing blocks, so any cleanup is hard to scope.

  • 04

    Three squads, one platform

    All three squads had to stay aligned, and knowledge had to spread across them instead of staying in one squad.

03Approach

Rather than a big-bang migration, I modernize the platform piece by piece, inside normal client work.

  1. Turn client requests into refactoring opportunities

    Refactoring happens when a client request touches legacy code. If the deadline isn’t critical, we bake the needed refactoring into the work and move that module from AngularJS to Vue.js. Most of the complex blocks have been migrated this way.

  2. Load only what each block needs

    The platform used to load one global CSS file and one JS file on every page, even for blocks that weren’t there. I led a refactoring that splits each block’s CSS and JS, and loads them only when the block is on the page.

    Loading strategy. A loading layer on top applies a preload, defer or async strategy to each file.

    Where it stands. New blocks use this system, but the legacy global files are still loaded alongside them, so page weight hasn’t dropped yet. The gains will show as legacy code is removed, block by block.

  3. Propose a BFF API

    The existing APIs were so generic that the frontend had to parse and reshape almost everything. Every API change also risked breaking another part of the application.

    I proposed and championed a backend-for-frontend (BFF) layer shaped around what the frontend actually needs, and the backend team built it. Frontend code got simpler, and API changes stopped rippling across the app.

  4. Modernize the build and delivery pipeline

    Vite for the new block system. The new per-block system builds with Vite, while legacy code stays on Gulp until it’s migrated.

    A CI pipeline twice as fast. I restructured the pipelines to run processes in parallel, cutting build and test time on every pull request in half.

    Quality gates. CI/CD gates with linting and Stylelint enforce standards automatically.

  5. From Ghost Inspector to Playwright

    The QA team wanted to move away from Ghost Inspector. I drove the initiative and set up a full Playwright architecture where developers and QA write end-to-end tests together.

    Adoption. One squad now runs it on a regular cadence, and a second squad is ramping up.

  6. Spread knowledge across squads

    Documentation portal. Documentation had been missing since day one, and the team kept flagging it. Confluence existed, but people struggled to find what they needed. I introduced a Docusaurus portal where I document every frontend architecture decision, and I keep improving it over time.

    Coaching. I coach the squad leads and the team.

    Workshops. I facilitate workshops and collaboration across squads.

  7. Bring AI into the workflow

    The team mainly uses GitHub Copilot, and I’m still exploring how to work with it well. I write shared prompts and skills, and connect MCP servers such as Figma’s.

    An AI refactoring workflow. I’m building an AI workflow to bring the component library back in sync with the design system, and to help migrate the main app. It uses the documentation portal as the single source of truth for rules and guidelines. Early results are promising.

04What I’d do differently

Most of these lessons are about what incremental modernization needs to stay on track.

  • Set a long-term vision, even an informal one.

    Without a shared direction for the platform, modernization depends on which client requests happen to come in.

  • Treat documentation as infrastructure.

    Audits like a full inventory of existing blocks, and documented decisions, make cleanup possible to scope. With AI in the workflow, they matter even more: the tools are only as good as the context they’re given.