Confidentiality notice: Because this is an internal enterprise system, this case study is described in generalized terms and omits internal system names, screenshots, infrastructure addresses, confidential metrics and third-party names.
Problem
The enterprise industrial maintenance system tracks daily work orders, staff allocation and operating costs. Originally built on ASP Classic and VBScript, it still supported day-to-day operations, but had reached an inflection point: adding new modules, maintaining business rules tightly coupled to legacy pages and ensuring reliable management reporting had become increasingly expensive and risky.
Upon taking over coordination of the unit, the challenge was not purely technical — it was keeping daily operations running without interruption while building a sustainable software foundation with an ultra-lean team (myself + 1 contracted developer).
Constraints
- Continuous operations: the legacy system is used every day by operational teams and could not be frozen for months for a big-bang rewrite.
- Shared database: the existing SQL Server database serves as the integration point between the legacy app and other operational workflows, requiring strict schema and data compatibility.
- Lean team and enterprise governance: only two people directly building software, operating within the governance rules of an enterprise Microsoft 365 environment.
- Data parity: migrated reports and entries had to match the legacy system outputs line by line before replacing any screen in production.
Decision
Chosen
Incremental coexistence (.NET 10 + React 19 sharing the legacy SQL Server)
Discarded alternative
Full rewrite on a greenfield database with a single cutover
Coexistence requires respecting historical database conventions during transition, but eliminates downtime risk and delivers business value from the very first modules.
- Legacy ASP Classic (live)
- Shared SQL Server
- .NET 10 API + OpenAPI
- React 19 + TypeScript SPA
- Parity & E2E before release
Every migrated module ships only after line-by-line parity validation against legacy reports.
- Parallel modular architecture: a .NET 10 API (ASP.NET Core, EF Core + Dapper) powering a React 19 + TypeScript SPA, while ASP Classic continues serving unmigrated workflows.
- End-to-end typed contracts: TypeScript types generated directly from the backend OpenAPI/Swagger specification, preventing silent client-server mismatches.
- Strict acceptance and parity gates: migrated features and reports reach production only after line-by-line parity checks against legacy results and automated functional tests.
- Governed AI-assisted delivery: structured AI workflows (specs, architecture reviews and deterministic checks) to multiply the output of a two-person team without sacrificing human review or risk control.
Outcome
- Coexistence enabled continuous production delivery of new modules in .NET 10 + React 19 without disrupting daily legacy usage.
- The new codebase established clear separation between business rules, data access and UI, backed by typed contracts and automated functional test suites before each release.
- The unit gained predictability to prioritize business demands and sustain gradual migration with controlled risk.
What I learned
- Coordinating modernization is risk management, not framework picking: the pivotal call was avoiding a big-bang rewrite and defining clear coexistence boundaries around the database.
- Data parity is non-negotiable in business systems: users trust consistent numbers; proving equivalence with the legacy output protects confidence in the new platform.
- Lean teams rely on engineering discipline: typed contracts, documented conventions and automated verification gates replace long status meetings and prevent rework.