What matters in business software is not what it does when everything goes right, but what it protects when something goes wrong. What happens when the connection drops, when two cashiers sell the same item at the same moment, when someone wants a past record “corrected”? The rules below were settled before we wrote code — and we have never reopened them for negotiation.
Our Principles
Six rules, six reasons
Next to every rule we wrote why it is that way and what it means for your business. These are not marketing headlines; they are rules the code obeys and the tests enforce.
Process
How does a feature get shipped?
Every new feature goes through the same four steps. The order never changes: the screen comes last.
Technology
A modern and proven foundation
We do not pick what is exciting; we pick what will still be maintainable in ten years. Our choices are industry-standard, open and widely used technologies.
- A .NET + PostgreSQL core — a separate, individually restorable database for every company.
- A React web console and a Flutter mobile app — Android and iOS from one codebase.
- Modules never call each other directly; they communicate through events. The event is stored in the same transaction as the business data, so "saved it but failed to trigger the side effect" cannot happen.
- Deployment on Docker + Dokploy (Traefik); encrypted connections and security headers are enforced at the infrastructure layer.
- Authorisation, tenant resolution, transaction integrity and audit writing all run on a shared pipeline — never left to individual features to remember.
What we did not add is on the record too
Adding a library makes you faster today and leaves debt tomorrow: security updates, version conflicts, abandonment risk. So we also write down the decisions not to add something, with the reasoning.
- For background jobs, a popular scheduling library was not added; the platform’s own mechanism was chosen and the reasoning was recorded in a decision record.
- For inter-module communication, a separate message queue was not added; it was judged unnecessary complexity at this scale, and designed so it can be moved onto one later.
- No new dependency is added before its decision is written down.
A dependency is debt to be repaid later. A few well-chosen dependencies are safer than many convenient ones.
Evidence
We measure what we claim
None of the above is a statement of intent; they are rules checked on every change.
800+
Automated Tests
Business rules, end-to-end flows and tenant isolation included.
14 written
Architecture Decision Records
The reasoning, alternatives and consequences of every major decision.
3 platforms
Web + Android + iOS
All passing through the same build and test pipeline.
Every change
Build + Test Gate
Never merged into the main branch until the build and all tests are green.
A fake database lies
Our integration tests do not run against an in-memory imitation but against areal PostgreSQL instance. Behaviour such as stock locking under concurrent sales, transaction rollback and uniqueness constraints can only be tested truthfully on a real database — the imitation usually just says "passed".
Tests enforce the rule, not people
We do not leave it to code review to confirm that modules stay out of each other’s internals and that no delete or update code creeps into movement records: separatearchitecture tests check exactly that. Code that breaks the rule turns the pipeline red before it ever reaches review.
Let's talk about your operation
Tell us what you use today and where things get stuck; we will look together at whether Business Suite, our product today, fits your business.