Manage Apple Reminders via the `remindctl` CLI on macOS (list, add, edit, complete, delete)....
npx skills add dannypenrose/agent-skills --skill "database-and-migrations"
Install specific skill from multi-skill repository
# Description
>
# SKILL.md
name: database-and-migrations
description: >
Enforce database design and migration standards when working with database schemas, queries,
migrations, or ORM configurations. Use this skill whenever the user creates or modifies Prisma
schemas, Entity Framework models, SQLAlchemy models, Django models, raw SQL, database indexes,
migration files, seed data, or data backfill scripts. Also applies when discussing query
optimization, N+1 problems, connection pooling, naming conventions, or zero-downtime migrations
-- even if the user doesn't explicitly mention 'database standards'.
Database & Migration Standards
When this skill triggers, follow these steps:
1. Read the Standards
Always read the database standards document first:
https://raw.githubusercontent.com/dannypenrose/engineering-standards/main/governance/database-standards.md
If the task involves a data migration (backfill, transform, platform migration, cleanup, merge/split), also read:
https://raw.githubusercontent.com/dannypenrose/engineering-standards/main/development/data-migration.md
Fetch these documents before writing or reviewing any database code. Do not rely on the quick-reference below as a substitute for the full standards on complex tasks.
2. Quick-Reference (Critical Rules)
For simple schema changes, apply these rules directly. For anything complex, read the full doc.
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Tables | snake_case, plural | users, order_items |
| Columns | snake_case | created_at, user_id |
| Primary keys | id |
id |
| Foreign keys | {referenced_table_singular}_id |
user_id, order_id |
| Indexes | idx_{table}_{columns} |
idx_users_email |
| Unique constraints | uq_{table}_{columns} |
uq_users_email |
| Check constraints | chk_{table}_{description} |
chk_orders_positive_total |
Required Columns (Every Table)
Every table must have these columns:
id-- primary key (UUID v4/v7 or BIGSERIAL depending on context)created_at--TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()updated_at--TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()(with trigger or ORM auto-update)deleted_at-- nullable, only when soft deletes are needed
In Prisma, use @map() and @@map() to ensure database-level snake_case:
model User {
id String @id @default(uuid()) @db.Uuid
email String @unique
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("users")
}
Index Patterns
- Always index foreign key columns
- Composite indexes: column order must match query patterns (leftmost prefix rule)
- Use partial indexes for filtered queries (
WHERE status = 'pending') - Use
CREATE INDEX CONCURRENTLYin production (avoids table lock) - No redundant indexes -- a composite index on
(a, b)already covers queries on(a)
Migration Safety Rules
| Rule | Details |
|---|---|
| New columns must be nullable or have a DEFAULT | Never add NOT NULL without a default to an existing table |
| Never drop columns in one step | Step 1: stop writing. Step 2: deploy code that doesn't read. Step 3: drop in separate migration |
| Create indexes concurrently | CREATE INDEX CONCURRENTLY to avoid locking |
| No in-place type changes on large tables | Add new column, backfill, switch reads, drop old column |
| Rename columns via add/backfill/switch/drop | Not ALTER COLUMN RENAME (breaks running code) |
| Test on production-size data | Small test DBs hide performance problems |
N+1 Prevention
When reviewing or writing queries:
// BAD: N+1
const users = await prisma.user.findMany();
for (const user of users) {
const posts = await prisma.post.findMany({ where: { userId: user.id } });
}
// GOOD: Eager loading
const users = await prisma.user.findMany({ include: { posts: true } });
// GOOD: Batch with IN clause
const userIds = users.map(u => u.id);
const posts = await prisma.post.findMany({ where: { userId: { in: userIds } } });
Data Migration Rules (Backfills/Transforms)
When writing data migrations, enforce:
- Idempotent: Safe to run multiple times (use guard conditions like
WHERE full_name IS NULL) - Batched: Process in chunks (1000 rows), never one giant transaction
- Cursor-based: Use cursor pagination, not OFFSET
- Dry-run mode: Support
--dry-runflag that logs what would change without writing - Pause/resume: Support resuming from a cursor after interruption
- Reversible: Document rollback procedure before execution
- Validated: Pre-migration checks (row counts, edge cases) and post-migration verification (spot checks, integrity)
3. Enforcement Checklist
Before approving any database change, verify:
- [ ] Naming conventions followed (snake_case tables plural, snake_case columns)
- [ ]
id,created_at,updated_atpresent on every new table - [ ] Foreign keys have explicit
ON DELETEactions - [ ] Foreign key columns are indexed
- [ ] New columns on existing tables are nullable or have defaults
- [ ] Indexes created concurrently (production contexts)
- [ ] No N+1 query patterns in associated application code
- [ ] Migrations are reversible (Down/rollback defined)
- [ ] If data migration: idempotent, batched, dry-run supported, rollback documented
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.