A framework that outgrew one factory
Coordinator began years ago as a PHP framework and application running on a single on-premises virtual machine. That setup was appropriate for a local intranet: one codebase, one MySQL database, one operational environment, and one factory to serve. Its constraints were also easy to understand because every change landed in the same application boundary.
The context changed when the platform needed to support more divisions around the world. A shared global product has different requirements: capabilities must be easier to evolve independently, integrations must not depend on a particular screen or code path, and a delivery model built for one machine must become repeatable. The question was not whether PHP had stopped working. It was whether the existing shape could responsibly carry the next stage of the product.
I chose to modernize Coordinator as an architectural transformation rather than a language rewrite. The target platform uses TypeScript across the stack: Node.js and NestJS for services, Angular for the frontend, PostgreSQL for the new platform data, and Redis where fast shared state is useful.
A platform, not a collection of replacements
The important change is the boundary around a capability. Each service is organised around a focused domain capability rather than a technical layer, making its responsibility easier to understand and evolve. Instead of treating the intranet UI as the only way to reach functionality, the new platform makes capabilities available through APIs. The Angular application is one consumer; approved vendors and other internal tools can become consumers too, without taking a dependency on the implementation behind the boundary.
Single-factory monolith
PHP, MySQL, and an on-premises VM concentrated product, data, and release concerns in one application.
Global cloud platform
TypeScript services and Angular clients expose reusable capabilities on a containerized platform.
That runtime change matters, but it is not the subject of this article. Moving from a VM to Docker workloads on Kubernetes and AWS EKS provides the operating model the platform needs; the detailed infrastructure story is covered in Multi-Cluster Infrastructure with zero downtime GitOps.
A staged migration that kept people working
A full cutover would have made the migration harder to validate and harder for users to absorb. Instead, the platform is being moved capability by capability. The legacy PHP application continues to serve the areas that have not moved, while new services and Angular views take responsibility for the areas that are ready.
The coexistence phase is deliberate. During a partially migrated capability, the existing PHP login still uses the established Active Directory credentials and also authenticates against the new APIs. The JWT returned by that step is retained in the PHP session, allowing legacy pages to call the new REST capability without asking people to sign in twice. Once a capability is fully migrated, the legacy application directs users to its new Angular experience instead.
One module, end to end: user administration
To keep this story concrete without exposing business-specific workflows, this article focuses on one capability: user administration. It is a useful example because it crosses authentication, authorization, data management, frontend usability, and an API surface that other consumers can understand.
The sign-in screen keeps the first interaction familiar while the underlying architecture changes. It is the entry point from which users can continue into legacy areas, partially migrated capabilities, or the new Angular experience without having to understand where each function is currently implemented.
The Coordinator dashboard establishes a clear operational shell. It groups capabilities into recognisable areas, gives users an obvious starting point after sign-in, and keeps the administrative experience consistent as functionality moves out of the monolith. The article stays focused on the account-management path, but the dashboard shows that the frontend is designed as a coherent product rather than a set of isolated screens.
The account list is designed for repeated operational work: the user can scan records, identify the relevant account, and move to the next step without losing the surrounding administrative context. This is a small interface decision with an architectural consequence. The new frontend makes a shared capability practical to use, not merely available through an API.
The detail view brings together the information needed to understand one account: personal data, login handlers for terminal access or mobile access with a badge, roles whose permissions are inherited, and permissions assigned directly to the user. This makes it possible to inspect the full access model before deciding whether a change is required.
The edit screen lets administrators update every detail associated with the selected user, from personal information to access configuration and assigned permissions.
APIs turn an internal application into a platform
The Angular screens are deliberately not the only way to use the capability. The same user-administration boundary is exposed through a REST API, which means a new interface, an approved vendor, or another internal tool can integrate with the capability without coupling itself to the Angular application or the old PHP codebase.
This is the central reason for the migration. Microservices are not the goal on their own; they provide a way to give a focused capability a clear contract, evolve it without entangling every consumer, and make the platform useful beyond a single factory or a single interface.
Leading the path, then enabling the team
I defined the direction for this modernization: the service boundaries, the TypeScript stack, the API-first model, and the migration sequence that keeps the legacy application useful while new capabilities are introduced. That direction matters because a large migration needs more than a list of technologies. It needs a path that people can follow without having to rediscover the architecture at every step.
We are now building that path as a dedicated three-person effort. My role combines technical ownership with the work that makes it sustainable: translating architectural intent into focused work, reviewing decisions and implementations, sharing context, and delegating ownership so the other team members can move the platform forward with confidence. The outcome I want is not only a better system, but also a team that can keep improving it.
What comes next
The direction is clear, but the migration is still in progress. The next steps are to continue improving the platform while keeping the transition safe for its users:
- Migrate capabilities incrementally. Continue moving focused areas from the PHP monolith into the new platform, keeping each step small enough to validate with users and the team.
- Strengthen API reuse. Keep refining capability boundaries and documentation so new frontend features, approved vendors, and internal tools can integrate without coupling themselves to a specific interface.
- Grow shared ownership. Turn architectural direction into repeatable practices, reviews, and decisions that the whole team can apply as the number of services and migrated capabilities grows.
- Retire legacy paths deliberately. Replace coexistence links and PHP entry points only when a capability is complete, understood, and ready to be owned entirely by the new platform.
Conclusion
This is not a story about replacing PHP with TypeScript for its own sake. It is about giving a product that began in one factory the boundaries, interfaces, and operating model it needs to serve a wider organisation.
Coordinator's modernization brings frontend experience, reusable APIs, gradual migration, and technical leadership into the same effort. The platform will keep evolving, but the foundation is now in place: capabilities can be developed independently, users can continue working through the transition, and the team has a clear path to carry the work forward.