Architecting platforms for Cheap Change: Five decisions for building systems that are easier to evolve
A customer missed an appointment with an important client. The reason was not that he didn't care; he runs a solid, well-regarded practice. He simply lost a handwritten to-do list, the invite sat buried under a dozen other emails and he forgot. It cost him a real business opportunity.
This incident wasn't unusual but it was just usually invisible.
That's the story that got me thinking about how much our tools help with our daily work. It convinced me that this wasn't something another integration could fix and it's the main reason I started this project.
The cost of fragmentation compounds quietly
A lot of work gets lost to administration: copy-pasting information between tools, keeping multiple systems in sync, searching for documents, checking whether somebody responded and keeping track of what needs to happen next.
Individually these moments look trivial; it's just bad luck. Multiply them across a team and it adds up to serious time and money. Work is spread across a CRM, a file drive, an inbox, someone's memory, a written list or a text message thread. Each handoff is a place where information gets re-typed, forgotten or simply lost. It doesn't fail all at once but rather show up as missed follow-ups, organizational bottlenecks and duplicate manual work.
The main idea here is that fragmentation is not primarily a tooling problem. It's a consequence of how information, permissions, state and events are modeled across an organization. That makes it an architecture question and not a shopping list for "which tool should we buy next?".
5 Decisions and what I said no to
I've set out to build a solution called Breeze that frees my customers' hands so that they can spend time on their core business: the work that they're actually good at and want to do.
Before writing a line of code that meant setting a clear standard and sticking to it, even when the faster path pointed elsewhere. I aimed for a steady foundation that allows me to quickly and cheaply add new features.
Each decision below (no particular order) represents a real fork in the road with a tempting alternative that I deliberately turned down. I approached every decision with a simple question as an architectural test:
Does this make the next change cheaper, or does it create another special case?
1. Sequencing over scope
The temptation when building a new platform is to ship many features: a little bit of everything. I chose the opposite approach: build a small number of capabilities deeply enough that they establish a solid foundation for everything that comes next. One well-designed mechanism is more valuable than five half-built features sitting on top of an unstable foundation.
The goal wasn't simply to get something working quickly, but to make the next capability cheaper to build than the previous one. This became an important test throughout the project:
Does this decision make the next change cheaper or does it create another special case?
2. One system, not a constellation of integrations
The obvious alternative to keep the CRM, the file drive and task tracker separate and stitch them together with something like Zapier or n8n. That can work: I'm not arguing that every organization should replace its existing tools with one platform. Integrations are useful when the systems genuinely have different responsibilities.
The problem occurs when basic organizational concepts such as people, projects, permissions and work state are fragmented across systems and have to be reconstructed through integrations. These increase the surface area of the system. Every connector introduces another dependency, another potential failure mode and another place where data and permissions have to be translated.
More importantly: the underlying concepts remain fragmented. If a client record lives in one system while its files live in another and its tasks live somewhere else, answering a simple question like "What is the current state of this case?" still requires stitching information together.
I therefore chose a shared domain model. This way, projects, files, tasks, people, groups and other capabilities can operate on the same underlying concepts rather than maintaining separate versions of them. The trade-off is that building the platform is harder. The benefit is that complexity moves from integrating independent systems to designing one coherent system with a shared data model and permission model.
3. A reactive core
A system that helps people work should not require them to constantly check whether something has changed. The goal is to automate the predictable: when something meaningful happens, the right people and processes should be able to react without someone having to remember to check.
The easy approach would have been to bolt an email notification onto each feature as it was built. I rejected that in favor of a central event mechanism. Meaningful changes in the system emit events. Notifications, automation rules and activity history can subscribe to those events rather than implementing their own mechanisms.
The downside is that this approach costs more up front but it creates an important property. Adding a new reaction to an existing event doesn't require changing the feature that produced the event. The same event can therefore drive:
- notifications
- automated workflows
- activity history
- auditing
- future integrations
The architecture becomes a platform for behavior, rather than simply a place to store data.
4. Sovereignty as a starting constraint
The easy path is SaaS-first, with self-hosting added later if a sufficiently large customer asks for it. I've seen that retrofit fail more than once. By the time it's requested, the data model, infrastructure, deployment process and operational assumptions may already depend on a shared cloud environment.
For Breeze, sovereignty primarily means that an organization can control where the application and its data run, rather than requiring business data to pass through a vendor-controlled SaaS environment.
I chose to make this a constraint from the beginning. Breeze can be deployed in infrastructure controlled by the organization. That affects more than where the application runs, it influences the architecture, dependencies, authentication, storage and operating model.
It costs more to build this way but it means data sovereignty isn't an enterprise feature bolted onto an existing SaaS architecture. It is part of the foundation and this makes Breeze suitable for organizations that require control over where their application and data run.
5. Composable, not per-client configuration
Shipping could have been faster if I'd hard-coded logic per feature and added config flags whenever clients asked for a variation. It's a familiar shortcut that quietly turns the product into a collection of exceptions that are difficult to understand, test and change.
The goal was a system able to grow into further automation and smarter features later, without tearing up the foundation to get there. Therefore I built Breeze from a small set of shared primitives like groups, events, permissions.
Modules can build on those primitives without changing the underlying foundation. This means that a customer-specific requirement can become a reusable capability rather than another special case. It also leaves room for future modules an automations without requiring the platform to be redesigned every time the product grows.
The costs of these decisions
None of these decisions are free. A shared domain model means more responsibility sits inside the platform. An event-driven architecture introduces its own operational complexity and can make debugging more involved. Self-hosting gives organizations control, but it also means someone has to operate the software. And composability requires discipline to prevent the shared primitives from becoming a dumping ground for every new requirement.
I chose these trade-offs deliberately because they match the organizations Breeze is intended for.
What these decisions produced
The architectural decisions are only interesting if they result in something useful. Development started with a clear goal, clear constraints and the decisions above to guide the work. Here's what came out of them.

1. Real-time collaboration, with one shared source of the truth
One familiar failure mode is everyone keeping their own copy of a document, emailing revisions around and eventually having someone merge the different versions manually. Or worse: the only copy exists on someone's laptop that suddenly breaks.
Breeze provides a real-time, multi-user editing of Office documents directly in the browser, with recoverable version history and labels per version. In addition to simply collaborative editing, work happens inside the same system that knows about the people, projects, permissions and surrounding work.
The organization can keep collaboration infrastructure under its own control, rather than sending documents to an unrelated external service
2. Secure data sharing across organizations, without losing control.
Organizations often need to work together without giving everyone access to everything. Usually this get solved by the aforementioned mailing around of documents.
Breeze makes the group the central access boundary. A group can contain colleagues from one organization, people from another organization or a combination of both. Access to projects, files and other resources can then be managed through those groups.
This makes secure, cross-organizational collaboration part of the core model rather than something that has to be solved separately for every feature.
3. An architecture built to react.
The event-driven foundation changes what the platform can do. Instead of simply storing what users put into it, Breeze can react to changes in the system: real-time notifications, and rules an organization sets up itself (when X happens, do Y) that run automatically.
Because every action already emits events for meaningful changes, those same events provide the foundation for an audit trail rather than requiring a separate mechanism to reconstruct activity afterward.
4. Users who knows what needs their attention.
Ultimately, all of these architectural decisions lead to a much simpler user experience. You open the system and see what needs your attention. What is urgent? What is waiting for someone else? What changed while you were away and what happened to the project?
Instead of checking five different places, the system brings that context together. That is the real goal of solving fragmentation at the architecture level rather than simply adding another tool.
Built for adoption, not just architecture
Good architecture is not enough. An organization still needs to be able to adopt the system without replacing everything it already uses. This shaped the product as much as the technical architecture.
The base provides capabilities such as groups, projects, files and tasks. Additional modules, such as CRM, automation and shared knowledge, can build on that foundation rather than requiring a separate system for each capability. This is the same composability principle from the engineering side, applied from the buyer's perspective.
An organization can start with the capabilities it needs today and add others later. That reduces adoption risk without turning the architecture into a collection of disconnected products.
Built to grow, not bolted on
The current foundation covers the core workflow around people, project, files, tasks and collaboration. The more interesting question is what happens next.
AI becomes more useful once the underlying context already exists. Because Breeze already understands users, permissions, projects, documents and activity, AI features can operate within that context rather than relying on users to manually assemble it.
New modules should extend the existing model rather than replace it. And because the foundation is based on shared primitives, organization-specific capabilities can be built without having to redesign the platform underneath them.
That is one of the reasons why the architectural boundaries are so important to me. Good architecture isn't one that predicts every future requirement but rather one that makes changing your mind relatively cheap.
Learnings
The interesting finding is that the difficult part wasn't any individual technical component. It was deciding where the boundaries should be.
Every new feature creates pressure to add another exception, another integration or another configuration option. The discipline is resisting that pressure when it makes the underlying model weaker.
The guiding question mentioned before (Does this make the future change cheaper?) turned out to be very helpful. It guided decisions about the domain model, events, permissions, deployment and modularity. It also changed how I think about product architecture more broadly. The goal isn't to build the most sophisticated architecture possible but to create a foundation that makes the next useful change cheaper than the last.
What this took
Building Breeze crossed quite a few disciplines:
- Product judgement about what a user actually needs to see, and when.
- Architectural judgement about boundaries, composability, deployment and long-term change
- Backend engineering around shared domain concepts, permissions, events and data
- Frontend engineering to make collaboration and real-time behavior feel natural
- Security thinking around access across boundaries an cross-organizational collaboration
- Operational thinking around self-hosting and environments that organizations control
- AI judgement about where AI can genuinely reduce work instead of simply being added because it is fashionable.
None of these concerns exist in isolation and that is what makes this project so interesting to me. The architecture has to serve the product, the product has to serve the organization and the technology has to remain capable of changing as both evolve.
See Breeze in action
I've deliberately left many of the implementation details out of this article.
If you're interested in how the architecture works, want to see the system running or want to explore whether Breeze could fit your organization's way of working, I'd be happy to show you.
Breeze: https://breeze.dataedge.nl
I hope this article was as clear as I intended it to be but if this is not the case please let me know what I can do to clarify further. In the meantime, check out my other articles on all kinds of programming-related topics.
Happy coding!
— Mike
P.s: like what I'm doing? Follow me!




