A faster way to create software
The business had developed an unusual advantage: operational knowledge could become working software quickly through AI-assisted development. Ideas no longer had to wait for a conventional delivery cycle before they could be tried inside the business.
Useful applications emerged around customer quoting, administration, pricing, and transport operations. Each one reflected real workflows and could evolve around the people using it.
Software creation was getting easier. Keeping the resulting systems coherent was becoming the harder job.
When coherence became the constraint
As the application estate grew, each product also began developing its own backend routes, data access, integrations, and interpretation of shared rules. That was manageable while the workflows remained isolated. It became risky when the same transaction crossed several products.
A single freight transaction can involve identity, organisation pricing, shipment details, carrier selection, insurance, payments, booking state, communication, and downstream operations. Those decisions must agree even when users enter the workflow through different applications.
Duplicated decisions
Pricing, permissions, and customer context could be interpreted differently depending on the application handling them.
Unclear authority
Values moving between interfaces risked becoming trusted facts without one system owning the consequential decision.
The problem was not that multiple applications existed. It was that the platform lacked an explicit answer to a basic question: which system owns each business decision?
A shared platform boundary
I shaped the architectural response around a shared API that acts as the business backbone for the application estate. Rather than centralising every screen or workflow, it centralises the capabilities that need one authoritative implementation.
Platform boundary
The API follows a feature-driven modular-monolith structure. Transactional domains have explicit boundaries between routes, services, domain models, persistence, and provider adapters. Smaller capabilities remain pragmatic rather than inheriting ceremony they do not need.
A modular monolith was deliberate. The business needed clearer ownership and stable contracts—not the operational cost of premature microservices.
Evolving without a rewrite
The platform could not pause while its architecture changed. Existing customer journeys, operational tools, and provider integrations still needed to behave consistently.
I used a capability-by-capability migration pattern:
- Map the current owners and callers of a business capability.
- Define its authoritative boundary and contract.
- Implement that capability behind the shared API.
- Use compatibility adapters where an existing interface cannot move immediately.
- Compare behavior and protect critical invariants before retiring old ownership.
This keeps migration grounded in product and operational continuity rather than treating it as a route-for-route code move.
What changed in the engineering work
AI-assisted development did not make architecture less relevant. It changed where the difficult work sat.
When implementation becomes easier, more of the value moves into deciding where authority belongs, which rules must remain consistent, how retries and partial failures behave, and how independently useful applications continue operating as one platform.
The goal was never to slow down business-led software creation. It was to give that capability boundaries it could keep building against.