There’s a feature in one of our internal applications at Improving that, from the outside, looks like a classic CRUD screen. Five fields: activity category, activity type (both dropdowns), a date, a quantity, and some notes. You fill it out and click a button. Simple.

Except it isn’t.
The Surface vs. the System
Behind that form is a process. Activities can be approved, rejected, or adjusted before approval. They can only be reported within open periods, and once a period is closed, no activity can be backdated into it. At the end of the period, after review, those activity points become coins that employees can redeem for bonuses, charity donations, and other rewards.
None of that is visible from the form. The form just looks like CRUD.
The periods themselves follow a similar pattern. They have a name, a start date, an end date, and a flag for open or closed. That part really is CRUD. But what happens around those periods, the lifecycle of activities flowing through them, is a workflow with meaningful state transitions and real business consequences.
This is a pattern not difficult to notice: systems that look like record management on the surface, but are actually orchestrating processes underneath.
The Experiment
A couple of months ago, I decided to run an experiment. I wanted to take this existing feature and build a proof of concept using event sourcing and CQRS, to see what it would look like if the architecture reflected the domain rather than the database.
The typical approach here would be to open the existing codebase and ask AI to analyze it, summarize what it does, and generate some documentation. That works, but it tends to produce documentation that mirrors the code rather than the domain.
Instead, I started from a different angle.
Improving already has documentation about this program. Not technical specs, but explanations written for employees: why this program exists, what value it creates for both the company and its people, how participation connects to growth and recognition. Human-facing writing.
I gave that documentation to my AI tool first, then had it analyze the codebase with a specific lens: run an event storming analysis, and slice what it finds into commands, events, aggregates, and read models.
What Came Out of It
The result was a document that looked nothing like the code. Even though the existing implementation doesn’t use CQRS terminology and doesn’t raise domain events, the AI identified what those events would be based on the business processes it found. It named the aggregates. It mapped the commands that trigger state changes. It described the read models needed to answer the queries that the system currently performs.
It also flagged an entity that is genuinely CRUD: no meaningful events, no workflows, just data. That distinction mattered. Not everything needs to be event-sourced, and the analysis was honest about that.
From the same session, I had an agent generate stories from the event storming artifacts. So I went from a codebase with no domain model documentation to a set of aggregates, commands, events, read models, and user stories in one sitting.
Building the Proof of Concept
Armed with that material, I created a new project and prompted AI to build a .NET backend using Marten and Postgres for event sourcing, with a React frontend. I was explicit that this was a proof of concept: I didn’t need a production-grade implementation. I needed to be able to run it, execute the main commands (create a period, log activities, approve or reject, close the period, generate payouts), and see the read models populate from the events.
It worked. Not perfectly, and not without iteration, but well enough to demonstrate the concept end to end. The experiment achieved what I was after.
What I’m Taking From This
The technique that made the difference wasn’t prompting AI to read code. It was giving the AI context from the outside, from the people and business that the software exists to serve, and then asking it to look at the code through that lens.
That shift in framing produced documentation that was useful for building something better, not just a reflection of what already existed.
What I’m learning is that AI is much more useful as a translator between human intent and technical implementation when you start with the human intent. Code alone doesn’t tell you why a system exists. But when you give the AI the “why” first, it reads the “how” very differently.





Leave a Reply