Data modeling
Skill nimadorostkar/Claude-Skills-collection/skills/data/data-modeling
A curated library of 137 production-grade skills for Claude and other AI coding agents.
npx -y skills add nimadorostkar/Claude-Skills-collection --skill data-modelingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 25 days oldThe repository was created 25 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 23 stars23 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when designing a schema. Covers normalization and when to break it, choosing keys, modeling time and history, soft deletes, multi-tenancy, and schema decisions that are expensive to reverse.
SKILL.md
5.1 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Data Modeling
Purpose
Design a schema that supports the queries you need and the changes you will want. Schema mistakes are the most expensive category of technical debt because the data outlives every application that touched it.
When to Use
- Designing a new schema or a significant new table.
- Adding multi-tenancy to an existing model.
- Modeling history, versioning, or audit requirements.
- Reviewing a schema before it becomes hard to change.
Capabilities
- Normalization, and deliberate denormalization.
- Key selection: natural, surrogate, UUID, ULID.
- Temporal modeling: valid time, transaction time, event history.
- Multi-tenancy strategies and their isolation guarantees.
- Constraint design: the invariants the database should enforce.
Inputs
- The domain entities and the relationships between them.
- The queries the schema must serve, and their frequency.
- Retention, audit, and compliance requirements.
Outputs
- A schema with enforced constraints and appropriate keys.
- A documented tenancy and soft-delete strategy.
- A migration path from the current schema, if there is one.
Workflow
- Normalize first — Third normal form as the default. Denormalize only where a measured query cost justifies it, and record the decision.
- Choose keys deliberately — A surrogate key (UUID/ULID) is stable and safe to expose. A natural key is meaningful and changes when the business changes its mind. Prefer surrogates for identity, and enforce natural uniqueness with a constraint.
- Enforce invariants in the database — Foreign keys, unique constraints, check constraints, not-null. Application-level validation does not survive a concurrent request, a background job, or a psql session.
- Model time explicitly — If history matters, do not overwrite. Append versions or events.
updated_attells you when, not what it was before. - Decide tenancy up front — Shared table with a tenant column, schema per tenant, or database per tenant. Migrating between these later is a project, not a task.
- Plan the migration — Every schema change on a large table needs a plan that does not lock it.
Best Practices
- A soft delete (
deleted_at) makes every query wrong by default: any query that forgets the filter returns deleted rows. If you use it, enforce it with a view or a row-level policy, not with discipline. - Sequential integer IDs leak business information (your order count) and are enumerable. ULIDs are sortable, unique, and safe to expose.
- Storing money as a float is a defect. Use an integer of minor units, or
numeric— neverfloatordouble. - Store timestamps in UTC, in a timestamp-with-timezone column. Store the user's timezone separately if you need to render local time.
- A nullable foreign key with a nullable meaning ("null means unassigned, or means deleted, or means legacy") is three columns pretending to be one.
- The
EAVpattern (entity-attribute-value) makes every query hard and every constraint impossible. Use JSONB for genuinely dynamic attributes instead.
Examples
History as an append-only fact, rather than an overwritten field:
-- Overwriting loses the answer to "what was the price when they ordered?"
-- forever, and that question will be asked.
CREATE TABLE product_prices (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
product_id uuid NOT NULL REFERENCES products(id),
amount_cents bigint NOT NULL CHECK (amount_cents >= 0),
currency char(3) NOT NULL,
valid_from timestamptz NOT NULL,
valid_to timestamptz, -- NULL = currently in effect
-- No two price rows for the same product may overlap in time.
EXCLUDE USING gist (
product_id WITH =,
tstzrange(valid_from, valid_to) WITH &&
)
);
-- The price at any point in time is now a query, not an archaeology project.
SELECT amount_cents FROM product_prices
WHERE product_id = $1
AND tstzrange(valid_from, valid_to) @> $2::timestamptz;
Multi-tenancy that the database enforces, not the application:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::uuid);
A forgotten WHERE tenant_id = ... in application code is now not a data breach. Relying on every query in the codebase to remember the filter, forever, is not a strategy.
Notes
- The exclusion constraint above is enforced by the database, so overlapping price periods cannot exist even under concurrent writes. Application-level checks for this are subject to a race that will eventually happen.
- Row-level security has a real performance cost and must be tested. It is still cheaper than a cross-tenant data leak.
- Adding a column is easy; changing a column's type or removing it is not. Think hardest about the columns you are most confident about.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most data backend skills give in ~1.1k tokens
Counted across 229 of the 229 authors here whose files we hold, read 2026-08-07
- Separate business logic into service layersin 22 of 229, across 15 files
- Retry failures with exponential backoffin 21 of 229, across 14 files
- Select only needed database columnsin 20 of 229, across 13 files
- Abstract data access into repository classesin 19 of 229, across 12 files
- Use centralized error handlersin 17 of 229, across 10 files
- Use AsNoTracking for read-only queriesin 16 of 229, across 4 files
- Use async/await for all I/O operationsin 16 of 229, across 5 files
- Implement structured loggingin 15 of 229, across 4 files
- Use dependency injection for all servicesin 14 of 229, across 2 files
- Use resource-based URLs for REST APIsin 13 of 229, across 7 files
- Invalidate cache after data changesin 13 of 229, across 9 files
- Use a dependency injection containerin 12 of 229, across 4 files
Said here and by no other author read
- normalize to third normal form by default
- denormalize only when query cost justifies it
- model time explicitly without overwriting
- append versions or events for history
- decide tenancy strategy up front
- enforce soft deletes with views or row-level policies
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.