AddThisFeature

Data Integrity Constraints

Enforce your important rules in the database, not just in the form.

involved Security & Reliability

What it adds

Database-level uniqueness, foreign key, check, and not-null constraints backing the business rules the application currently only validates in code.

What your agent is told to do

6
  1. 1

    Inventory the rules the app relies on — required fields, uniqueness, valid enum values, positive amounts, referential links — and note which exist only in application code.

  2. 2

    Before adding each constraint, query for rows that already violate it and decide explicitly whether to fix, delete, or exclude them. Every mature database has violating legacy rows.

  3. 3

    Add constraints in a way that does not hold a long exclusive lock: create indexes concurrently, add checks as NOT VALID and validate them in a second step.

  4. 4

    Keep application validation in place alongside the constraint so users get a field-level message, and catch the database error as a backstop for races and imports.

  5. 5

    Translate constraint violations into human sentences naming the field. A raw unique-index error string must never reach the user.

  6. 6

    Do NOT add a plain unique index to a table with soft deletes or multiple tenants without scoping it. A global unique email on a table with deleted rows will block a user from ever signing up again.

Edge cases it handles

7
  • Uniqueness across nullable columns behaves differently than people expect — NULL is not equal to NULL, so duplicates slip through.
  • Soft-deleted rows must be excluded from uniqueness via a partial index, or deletion becomes permanent blocking.
  • Multi-tenant uniqueness is almost always scoped to the tenant, not global — check every unique rule for a missing tenant column.
  • Foreign keys need an explicit delete behaviour: cascade, nullify, or restrict. Defaulting silently is how orphans or accidental mass deletes happen.
  • A race between two simultaneous requests will defeat a check-then-insert; the database constraint is what actually stops it, so the code must handle the raised error.
  • Seed data, fixtures, and bulk importers frequently bypass model validation and will start failing the moment constraints land — fix them in the same change.
  • Adding a NOT NULL column to a large table without a default can rewrite the table; stage it as nullable, backfill, then constrain.

Definition of done

9
  • Every business rule identified as critical has a matching database constraint.
  • Existing violating rows were found and resolved before each constraint was added.
  • Migrations avoid long exclusive locks on large tables.
  • Uniqueness is correctly scoped for tenants, soft deletes, and nullable columns.
  • Foreign keys declare an explicit delete behaviour.
  • Constraint violations surface as field-level user messages, never raw database errors.
  • Concurrent duplicate requests produce one row, not two.
  • The feature matches the existing design system.
  • No existing functionality is broken.

Related features

How it works

  1. 1

    Copy the link

    Grab the Markdown instruction URL for this feature.

  2. 2

    Give it to your AI

    Paste it into Claude Code, Cursor, v0, Lovable — whatever you build with.

  3. 3

    It inspects, then implements

    Your agent reads your existing app first, then adds the feature to fit it.

Works with your stack

These instructions are written to adapt. They tell the agent to detect your framework, match your existing design system, and reuse what you already have — rather than assuming a particular stack.

Need it tighter than that? Customize the feature and tell it exactly what you're running.