Data Models
Data Dictionary Template and Model Traceability
Use a one-page data dictionary template for every entity and link it to its stories, rules and migrations, so any table can explain why it exists.
A Diagram Is Not Enough
Boxes and lines show structure. They do not show meaning. The word status on a diagram does not tell you who is allowed to change it, what returned means when a drill comes back broken, or which story asked for it in the first place.
The data dictionary is the written half of the model. It sits one layer above the schema. The migrations are the authority on structure, and the dictionary is the authority on meaning.
One Record per Entity
Keep one short record for each entity. A plain Markdown file in the repository, next to your specs, is enough. Each record answers the same questions:
- Name and meaning. One sentence, in the business's own words.
- Identifier. What people use to say "that one".
- Attributes. Each with its meaning, and a note on which ones are derived.
- Relationships. Written as sentences, in both directions.
- Rules. For example, "a member may hold at most three loans at once."
- Used by. The stories and requirements that need this entity.
- Built by. The migration or migrations that create or change it.
- Changes. Whether the entry is still current, and a dated note of each change.
The record and the migration it describes change together and are reviewed together. If a reviewer sees a migration with no matching dictionary change, they should ask why.
The Trace Chain
Once every entity has a record, you can trace in both directions.
Forwards, from a story, you can find every table that serves it. Backwards, from any table, you can find why it exists. A table that cannot answer "why do you exist?" is an orphan. The rule that prevents orphans is short: no table without an entry.
Drift: The Check That Keeps the Model True
A model is only worth something while it matches reality, so check it regularly:
- Read the live database, not a note that says it matches.
- Orphans. Tables with no dictionary entry.
- Ghosts. Entries with no table: either never built or quietly dropped.
- Mismatches. Attributes, relationships or rules that differ between the entry and the table.
Every finding ends one of two ways. Either fix the table to match the approved model, or change the model on purpose, with a recorded decision and a new approval. Never silently edit the model to match the database. That turns the specification back into a photograph.
Keep It Small Enough to Maintain
A dictionary nobody updates is worse than none, because people will trust it. Keep entries short, keep them in the repository, and review them with the migration. If an entry is too long to update alongside the migration, it is too long.
Key Takeaways
- The diagram shows structure. The dictionary records meaning. The migrations hold structure.
- One short record per entity, changed and reviewed together with its migration.
- Trace runs forwards (story to table) and backwards (table to reason).
- No table without an entry.
- Drift checks read the live database. Each finding is fixed in the table or changed in the model deliberately, never quietly.
Example
# LOAN
**Meaning:** One tool lent to one member, from the day it leaves the desk
until it comes back.
**Identifier:** loan number (printed on the receipt)
## Attributes
- borrowed on (date): the day the tool left the desk
- due on (date): must not be before borrowed on
- status (derived): the kind of the latest loan event; never stored
## Relationships
- Every loan belongs to exactly one member; a member has zero or more loans.
- Every loan is for exactly one tool; a tool has zero or more loans.
- Every loan has one or more loan events; each event belongs to one loan.
## Rules
- A member may hold at most three open loans. (STATED by the owner)
- A loan may be renewed once. (ASSUMED, ask at the next review)
## Used by
- Check out a tool to a member
- Record a return
- Renew a loan
## Built by
- 20260901120000_create_loans.sql
- 20260908090000_create_loan_events.sql
## Changes
- 2026-09-01: first written
- 2026-09-08: status now derived from loan events# LOAN **Meaning:** One tool lent to one member, from the day it leaves the desk until it comes back. **Identifier:** loan number (printed on the receipt) ## Attributes - borrowed on (date): the day the tool left the desk - due on (date): must not be before borrowed on - status (derived): the kind of the latest loan event; never stored ## Relationships - Every loan belongs to exactly one member; a member has zero or more loans. - Every loan is for exactly one tool; a tool has zero or more loans. - Every loan has one or more loan events; each event belongs to one loan. ## Rules - A member may hold at most three open loans. (STATED by the owner) - A loan may be renewed once. (ASSUMED, ask at the next review) ## Used by - Check out a tool to a member - Record a return - Renew a loan ## Built by - 20260901120000_create_loans.sql - 20260908090000_create_loan_events.sql ## Changes - 2026-09-01: first written - 2026-09-08: status now derived from loan events
Where You'll See This in the Real World
Regulated industries such as banking, healthcare and insurance require data dictionaries, because an auditor's first question about any field is what it means and who can change it. Teams outside those industries tend to discover the need during a handover. The new developer, or the new AI session, cannot tell what a column is for, and the only people who knew have moved on.