The Great Refactor: Migrating a CRM from Spring Boot to Serverless
By Andrei Roman
Principal Architect, The Foundry
In my "Mission" manifesto, I outlined three capabilities I am developing at The Foundry. The second was System Integration and Refactoring - specifically, the move from heavy Java monoliths to agile serverless architectures.
Today, I am executing on that promise.
I am taking AmbienCRM - a production-grade application I built for a flooring company using Java Spring Boot, Hibernate, and PostgreSQL—and porting it entirely to the AMODX Serverless Stack (AWS Lambda, DynamoDB, CDK).
This is not a "rewrite." Rewrites are often vanity projects where developers trade old bugs for new bugs. This is a Migration. It is a calculated, architectural maneuver designed to eliminate idle costs and unlock infinite extensibility.
Here is the engineering logic behind the move, and the blueprint for how I am doing it without breaking production.
The "Expert's Dilemma"
I spent years mastering the Spring ecosystem. It is robust. It is typed. It is reliable. When I built AmbienCRM, I used Clean Architecture principles to ensure the business logic was decoupled from the framework.
But for a tool used by a specific team during business hours, a containerized Java application running 24/7 is financially inefficient. You are paying for CPU cycles while your users are sleeping.
More importantly, a monolith is a "walled garden." If I want to add a feature - say, an AI agent that drafts offers based on a voice memo - I have to open the monolith, wire up new services, and redeploy the entire beast.
I wanted to make it easier to work on it in the future. There will be integrations with online shops, accounting, invoicing, bank verifications, inventory management, all of which can be done easier with a serverless architecture.
In the Serverless paradigm, that feature is just a new Lambda function listening to an event bus.
The Architecture: From Monolith to Distributed System
We are moving from a Service-Based Monolith to a Service-Based Lambda Monolith.
We are preserving the domain integrity while changing the infrastructure.
The Controller becomes the Handler: The Spring @RestController is replaced by thin Lambda Handlers. Their only job is to parse the JSON event, validate inputs (using Zod), and call the Service.
The Service remains the King: The core business logic - calculating discounts, validating approval workflows, generating diffs - is ported from Java classes to pure TypeScript classes. This logic does not know it is running on AWS. It just calculates.
The Repository changes the Physics: We are moving from Relational (PostgreSQL) to Access-Pattern Driven (DynamoDB Single Table Design). We aren't using JOIN anymore. We are designing our data access patterns upfront (e.g., PK=CLIENT#123 and SK=OFFER#456).
The Methodology: The "Golden Master" Strategy
How do you rewrite a complex financial tool without breaking the math? You don't guess. You verify.
I am employing a Golden Master testing strategy, a technique often used in safety-critical legacy migrations:
Baseline Capture: Before shutting down the Java backend, I am running a series of complex scenarios (creating offers with specific VAT rates, discounts, and mixed currency calculations). I am saving the inputs and the resulting PDF outputs as binary artifacts.
Port & Execute: I write the TypeScript logic.
Bit-Level Verification: I run the same inputs through the new Serverless backend. The output must match the Golden Master artifacts bit-for-bit (or value-for-value).
If the math drifts by a cent, the build fails.
Unlocking Extensibility (The Real Goal)
The goal isn't just to save money on hosting. The goal is to make the system evolved.
By moving to this stack, AmbienCRM inherits the Event-Driven Architecture of AMODX.
Old Way: When an offer is approved, the Java service calls the EmailService directly. If the email server is down, the transaction might hang or fail.
New Way: When an offer is approved, the system puts an OfferApproved event onto EventBridge.
This decoupling is where the magic happens.
Right now, that event triggers an email. But tomorrow? I can add a new listener - an AI Agent - that subscribes to OfferApproved, reads the offer details, and automatically generates a "Thank You" video script for the salesperson, or adds a task to a separate project management tool.
I don't have to touch the core CRM code to add that. I just plug into the bus.
The Roadmap
We have defined the methodology. We have mapped the database access patterns. Now, the migration begins.
Phase 1: Infrastructure & Shared Types (Defining the contract).
Phase 2: Core Domain Logic (Porting the "Brain").
Phase 3: API Layer (The "Mouth").
Phase 4: The Golden Master Verification.
I am applying the rigor of avionics engineering to the flexibility of the cloud.
Oh and for now I'm keeping the same frontend so the goal is to switch the backend to serverless and the users should continue using the application in the same way as before.
Back to the code.
Discussion (0)
No comments yet. Be the first!