Data & APIs

Data Model Auditor

Check a schema/data model for normalization issues, missing constraints, and the specific place invalid data will slip through if the database doesn't enforce it.

When to use this

  • Designing or reviewing a new schema/data model before it's built.
  • Data quality issues in production point at a schema that doesn't enforce what the application assumes.
  • Not for a single query's correctness -- use sql-review for that; this is about the underlying structure.

The skill file

Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.

SKILL.md
---
name: data-model-auditor
description: Review a data model/schema design for normalization issues, missing constraints (foreign keys, uniqueness, not-null), and gaps between what the application assumes is always true and what the database actually enforces. Use when designing or reviewing a schema.
---

# Data Model Auditor

The core question: for every invariant the application code assumes
("a user has exactly one active subscription," "an order's total equals
the sum of its line items"), does the database actually enforce it, or
does it just happen to be true as long as every code path stays correct
forever?

## Checklist

- **Constraints match assumptions**: foreign keys for every relationship
  the application treats as required, `NOT NULL` on every column the
  application assumes is always present, `UNIQUE` on every field treated
  as unique (including compound uniqueness -- "one active row per user,"
  not just "no two rows fully identical").
- **Normalization**: is data duplicated in a way that can go inconsistent
  (the same fact stored in two places with no single source of truth)?
  Denormalization for performance is a valid choice, but should be
  deliberate and paired with a plan for keeping copies in sync, not an
  accident of schema growth.
- **Nullable columns**: for each nullable column, does null have a clear,
  intentional meaning distinct from "we forgot to backfill this," and does
  application code handle the null case everywhere it reads the column?
- **Enum-like columns**: is a status/type column constrained (database
  enum, check constraint, or foreign key to a lookup table) or just a
  free-text field the application hopes only ever contains expected
  values?
- **Timestamps**: created/updated timestamps present and consistently
  populated where audit/debugging needs them.

## Output

Each gap: the assumption the application makes, whether the database
enforces it, and the concrete scenario where a bug or a race condition
could produce data that violates the assumption if it isn't enforced.

Installing it elsewhere

The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:

Claude Code
.claude/skills/data-model-auditor/SKILL.md

Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /data-model-auditor.

Cursor
.cursor/rules/data-model-auditor.mdc

Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.

Codex CLI / Copilot
AGENTS.md

Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.

Windsurf
.windsurfrules

Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.

Where this goes wrong
  • Treating "the application always sets this correctly" as equivalent to a database constraint -- application bugs and future code paths won't respect an assumption the database doesn't enforce.
  • Missing compound uniqueness requirements (e.g. one active row per user) that a single-column UNIQUE constraint doesn't capture.
  • Flagging denormalization as automatically wrong without checking whether it's a deliberate, synced-correctly performance choice.