# Master data

> Products, warehouses, counterparties, price lists - the entities everything else refers to, stored once as real tables with the attributes your business actually needs

Source: https://aipril.dev/docs/master-data

## The entities everything else points at

A purchase request names a supplier. A stock movement names an item and a warehouse. A price list
names both. A report groups by product category. A process routes by counterparty type.

None of those systems owns the supplier, the item or the warehouse. They **refer** to them - and
what they refer to has to live somewhere that is correct, shared and stable. That somewhere is
master data.

## What usually happens without one

Every platform has three things that look like they could hold a catalogue, and none of them is one.

| What gets used | Why it breaks |
|---|---|
| A spreadsheet | An editing surface, not a store. Fine for two hundred rows; a hundred thousand SKUs with a lookup on every checkout is a different job |
| An analytics dataset | Built for aggregation over many rows, not for answering "what is the price of this one SKU" on a hot path |
| A dictionary inside some other subsystem | Right shape, wrong owner - it belongs to that subsystem's lifecycle, lives behind its API, and takes your catalogue down with it |

The last one is the common ending: the product catalogue lives inside whichever subsystem needed it
first, and every other part of the platform fetches it over the network, unindexed, on paths that
cannot afford it. It works until it is the thing everything depends on.

## What is different here

**The attributes are yours.** What a product has - a category, a unit, a shelf life, a supplier
code, three fields nobody else would have thought of - is declared by the application that needs
them. Adding one is not a platform migration somebody has to write and deploy for you.

**It is stored as real tables, beside your other data.** Which means the catalogue can be joined to
anything: a report joins products to sales, a process reads a counterparty in the same query it
reads the request. Master data behind another service's HTTP API is the failure this exists to end.

**Codes are immutable, and entries deactivate rather than vanish.** Everything else - a balance in
the [ledger](https://aipril.dev/docs/ledger.md), a field on a task, a row in a report - refers to an entry by its code.
A code that can be renamed is a way to orphan all of it quietly.

**A catalogue ships with an application, and your edits survive its updates.** The application
declares the entity and can seed it with the values it needs to work. Seeding never overwrites a row
that already exists, so what your operators corrected stays corrected - and a new value added in a
later version still arrives.

## Where to go next

- [What you can do](https://aipril.dev/docs/master-data/what-you-can-do.md) - what belongs here, who maintains it, and
  how it reaches processes, reports, pages and the ledger.
- [Under the hood](https://aipril.dev/docs/master-data/under-the-hood.md) - how declared attributes get native speed
  without giving up free evolution, and the rules that keep a shared catalogue from drifting.
