relational-data-modeling

v2026.09.24

Corrects the wrong defaults a model has when designing a relational schema — the DDL decisions an experienced engineer makes differently. Use when creating or reviewing tables, migrations, ER models, or ORM schema definitions. Covers identity and keys (surrogate vs natural, identity vs serial, uuidv7, composite keys that make cross-tenant references impossible), relationships (polymorphic foreign keys the database cannot enforce, referential actions, unindexed FK columns, disjoint subtypes), invariants the engine can prove instead of application code (EXCLUDE, partial unique indexes, CHECK limits, deferrable cycles, NOT VALID), types (timestamptz, exact money, range types, enum vs lookup table), derived and encoded data (generated columns, JSONB as an escape hatch), and time (events vs in-place updates, soft-delete flags that silently disable constraints, temporal keys). NOT for query tuning, index selection for read paths, or connection pooling.

GitHub
Install command
npx skhub add pproenca/relational-data-modeling
Markdown
SKILL.md

Relational Data Modeling

The decisions a relational schema forces, and how to settle them so the database enforces what it can and the application is left with only what it must. Every rule names the wrong default it corrects; there is no rule for what a capable model already gets right.

Examples are PostgreSQL 18, and every DDL statement in this skill was executed against 18.4 — including the failure cases, to confirm the constraints reject what they claim to reject. Roughly a third of the rules depend on mechanisms MySQL and SQLite do not have (EXCLUDE, partial unique indexes, range types, WITHOUT OVERLAPS, deferrable constraints, NOT VALID); those rules say so. The judgment rules transfer to any relational engine.

When to Apply

Use this skill when:

  • Writing or reviewing CREATE TABLE / ALTER TABLE, a migration, or an ORM schema definition (Prisma, Drizzle, Django models, ActiveRecord, Ecto, SQLAlchemy)
  • Designing an entity-relationship model, or naming what a row is — the point where key choices become expensive to reverse
  • The user says "should this be one table or two", "how do I model many-to-many", "the schema allows bad data", "we need history", "we're adding multi-tenancy", or "can the database enforce this"
  • A bug turns out to be a schema that permitted the bad state — duplicates that a unique constraint should have caught, orphans a foreign key should have blocked, overlapping bookings, two rows flagged as default
  • Adding constraints to a table that already has rows and traffic
  • Reviewing a schema generated by an ORM or a scaffolding tool, which is where polymorphic associations, reflexive surrogate keys, and blanket soft-delete flags arrive from

This skill is NOT for:

  • Query tuning, execution plans, or choosing indexes for a read path — this covers only the indexes that constraints and foreign keys require
  • Connection pooling, replication, or operational tuning
  • Non-relational stores, where the trade-offs it argues from do not hold

Rule Categories

#CategoryPrefixCovers
1Identity and Keyskey-What a row is; the choice every foreign key depends on
2Relationships and Cardinalityrel-Keeping references declarable to the database, not just intended
3Constraints as the Modelcons-Which mechanism can actually hold which invariant
4Types and Domainstype-The cheapest constraint available, chosen for meaning not habit
5Derived and Encoded Datanorm-What every deliberate copy costs, and what the database can't see inside
6Time, History and Lifecycletime-What happens to a row when the world changes

Quick Reference

1. Identity and Keys

2. Relationships and Cardinality

3. Constraints as the Model

4. Types and Domains

5. Derived and Encoded Data

6. Time, History and Lifecycle

How to Use

Read a reference file when its decision comes up — the quick reference above is enough to route. Each rule states the wrong default it corrects and why, then gives a canonical example.

Two rules of thumb tie the categories together and are worth applying even outside a specific rule:

  1. Before adding a column, name what makes two rows the same row. That sentence is a constraint you owe the table.
  2. Before writing a validation in application code, ask which constraint could hold it instead. If the answer is "none", that is worth knowing explicitly — see cons-check-is-single-row for the map of invariant shapes to mechanisms.

Reference Files

FileDescription
references/_sections.mdCategory definitions and ordering
assets/templates/_template.mdTemplate for new rules
metadata.jsonVersion and source references
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

skills/.experimental/relational-data-modeling

Default branch

master

Latest commit

cf93c57

Tree SHA

afbb575