Executive Summary: Refactoring legacy B2B systems in Laravel focused on halting data integrity violations and untangling spaghetti code. I implemented Postman-based contract testing, SOLID principles, and Repository Pattern abstractions to modernize core business logic without causing downtime on production servers.
"Greenfield" projects are what every developer dreams of—a blank slate, fresh repositories, and the latest tech stack. But the reality of senior engineering is that true value is often created by rescuing codebases that are already in production, generating revenue, and actively failing.
During my time at PT Labani Media Nusantara, I inherited three massive legacy B2B applications: a Laundry management system, a Cooperative network, and a Pawnshop platform. They were all built in Laravel, but they suffered from critical logical defects, "spaghetti" code, and severe data integrity violations.
Here is how I approached modernizing them without breaking the active business operations.
Step 1: The Triage Phase
When you open a massive, undocumented monolithic controller that is 3,000 lines long, your first instinct is to rewrite it. Don't.
A rewrite is a massive business risk. Instead, my first week was spent strictly observing. I monitored the database query logs and identified the endpoints causing memory exhaustion (usually due to the N+1 query problem). I mapped out the core business flows (e.g., how a pawn transaction was approved) by reading the actual execution path, because the documentation did not exist. This is especially critical when navigating Eloquent ORM.
Step 2: Securing the perimeter
Before refactoring business logic, I had to patch authentication vulnerabilities. The legacy code often checked authorization at the UI level (hiding buttons) but completely failed to protect the underlying POST routes. I immediately implemented strict Laravel Middleware and Form Requests to ensure that ID spoofing or privilege escalation was impossible.
Step 3: Extracting Fat Controllers to Service Classes
The core issue with the applications was that the Controllers were doing everything: validating requests, writing raw SQL, processing payments, and formatting views.
I slowly migrated the application to a Service-Repository pattern. I extracted the business logic out of the controllers and into dedicated Service classes (e.g., ProcessPawnTransactionService). This allowed me to:
- Isolate business rules away from the HTTP layer.
- Write unit tests (via Pest/PHPUnit) for the exact financial calculations, proving they worked before I touched anything else.
- Re-use logic easily across different parts of the application or new API endpoints.
Step 4: Fixing Data Integrity
The database lacked proper foreign key constraints, meaning "orphan" records were everywhere. I wrote migration scripts that safely re-linked orphaned data using heuristics, and then locked down the MySQL schema with strict foreign keys and cascading rules. From that point on, it became impossible for the application code to corrupt the database relationships.
The Takeaway
Refactoring legacy systems isn't glamorous, but it forces you to become a true software architect. It teaches you to respect the code that pays the bills, prioritize testing, and implement SOLID principles not because a textbook said so, but because you've seen the catastrophe that occurs without them.
Ultimately, restructuring a monolithic Laravel system in this manner vastly improves both developer satisfaction and business value. By isolating critical components into testable, modular services, we managed to reduce deployment times and drastically decrease production regressions. This is what outcome-driven software engineering looks like.