Eighteen thousand six hundred forty-four lines of Vue code lived in fourteen files that were each over a thousand lines long. Settings.vue alone was 2,322 lines — a god component that handled user preferences, team management, billing configuration, notification settings, and widget customization in a single file.
The decomposition extracted roughly forty child components and five composables. Settings.vue went from 2,322 lines to 293 — an 87% reduction. AffiliateDashboard dropped from 1,856 to 452. Quote and TryDemo each lost over half their weight. The total: 18,644 lines became 10,178. Forty-five percent gone, and every feature still works.
But the decomposition wasn't the hard part. The CI pipeline was.
Six checks were failing. ESLint 9 had stricter defaults than the version the codebase was written against — arrow-parens and vue/html-self-closing violations across thirty files. Autofix handled most of them. PHPUnit 11 no longer supports the memoryLimit attribute in its config. Integration tests referenced /api/admin/analytics/ and /api/admin/customer/ — routes that had been renamed months ago but the tests never updated. OrderServiceTest needed mocks for two services that had been added to the constructor since the test was written. The package-lock.json was out of sync with the ESLint 9 migration.
Every one of these failures predated the decomposition. They'd been invisible because nobody had run the full CI suite in a while. The decomposition didn't cause them — it revealed them. The lesson: run CI locally before pushing a large refactor, not after. The refactor will be blamed for every preexisting failure it surfaces.
Fourteen PRs merged. Issue #117 closed. Issue #101 fully resolved at twenty-two of twenty-two findings. The codebase is lighter, and the files that remain are each focused on one thing.