Nobody buys an ERP for its schema, which is why most ERP schemas are an afterthought assembled feature by feature. I build Agaro ERP the other way around. The features are queries against the data model. The data model is the product. Everything the customer will ever ask for is either a query or a migration, and which one it is was decided the day the schema was written.
One concept, one definition
The first test I apply before any feature work: is there exactly one place in the system that defines what a unit, a customer, a payment, or an order is? If two subsystems each carry their own definition and reconcile nightly, you have not built two systems, you have built a disagreement with a scheduler attached.
The classic version is inventory across channels. Point of sale and online storefront both decrement stock, and if they disagree about what a sellable unit is, a bundle sold in the store and the same bundle sold online consume inventory differently. Reporting survives the disagreement. Automation does not. You cannot generate reorder suggestions from sell through data that was recorded at two different grains, and you certainly cannot let an AI agent act on it, because ambiguous data is a reporting headache for humans and a safety problem the moment a nonhuman actor starts pressing buttons against it.
In Agaro, one canonical definition per concept, and channels and pricing modeled as attributes of that canonical core rather than as parallel universes that sync. When a customer later asked for cross channel margin per product, it was a query, not a project. That is the whole thesis in one anecdote.
The right grain, because you can always roll up
Pre aggregation is irreversible information loss. You can always roll up from fine grain to summary. You can never roll down. So facts get stored at the finest grain the business might ever need, and summaries are derived, cached, and disposable. If a report needs a number the raw facts cannot produce, the report is wrong or the schema is wrong, and it is worth finding out which before the report becomes load bearing for someone’s quarter.
There is a cost, and it is honest to name it. Fine grain facts mean bigger tables and more careful indexing. But storage is the cheapest thing in the stack, and re-derivation beats retroactive migration every time it is offered.
Money is explicit
Every money field carries its currency and its scale, and arithmetic happens in integer minor units. The cents as dollars failure, where 340 dollars is read as 34,000, is not a formatting bug. It is a data model failure, and it is the kind that ends quarters and audits. In a multi tenant ERP the same field is written by many hands across many companies with different currencies and conventions, so the schema itself has to refuse ambiguity. Explicit currency, explicit scale, one rounding policy enforced in one place.
The uncomfortable timing problem
The honest difficulty is that you make the most consequential schema decisions when you understand the customer’s business the least. Week one, before you have seen the edge cases, you are committing to the structure that will enable or block year two. There is no way out of that, only through: spend the early weeks on the canonical entities instead of the screens, defend the slowness to the customer by telling them the truth, that every clever thing they will want later is either a query against this core or a migration against it, and let the second year prove you right.
It always has, so far. That is why the data model is the product.