@incidental/project-templates
Version:
Claude Code template library for JavaScript projects with framework auto-detection
226 lines (187 loc) • 5.27 kB
Markdown
---
name: database-schema
description: Design and implement database schemas with proper relationships, constraints, and migrations
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
---
# Database Schema Skill
Design and implement database schemas following best practices.
## When to Use
Use this skill when you need to:
- Design database schema
- Create migration files
- Define models/entities
- Set up relationships
- Add indexes and constraints
## What This Skill Does
This skill generates database schemas including:
1. **Schema design** with proper normalization
2. **Migration files** for version control
3. **Model definitions** using ORMs (Prisma, TypeORM, Sequelize)
4. **Relationships** (one-to-one, one-to-many, many-to-many)
5. **Constraints** (unique, foreign keys, check constraints)
6. **Indexes** for query performance
## Schema Design Principles
### Normalization
- First Normal Form (1NF): Atomic values
- Second Normal Form (2NF): No partial dependencies
- Third Normal Form (3NF): No transitive dependencies
### Naming Conventions
- Tables: plural, lowercase with underscores (e.g., `users`, `blog_posts`)
- Columns: lowercase with underscores (e.g., `created_at`, `first_name`)
- Primary keys: `id` or `table_name_id`
- Foreign keys: `referenced_table_id` (e.g., `user_id`)
- Junction tables: combine table names (e.g., `users_roles`)
## Prisma Schema Example
```prisma
// User model
model User {
id String @id @default(cuid())
email String @unique
name String?
password String
role Role @default(USER)
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([email])
@@map("users")
}
// Profile model (one-to-one)
model Profile {
id String @id @default(cuid())
bio String?
avatar String?
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("profiles")
}
// Post model (one-to-many)
model Post {
id String @id @default(cuid())
title String
content String
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
tags Tag[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId])
@@index([published])
@@map("posts")
}
// Tag model (many-to-many)
model Tag {
id String @id @default(cuid())
name String @unique
posts Post[]
@@map("tags")
}
// Enum
enum Role {
USER
ADMIN
MODERATOR
}
```
## SQL Migration Example
```sql
-- Create users table
CREATE TABLE users (
id VARCHAR(36) PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(255),
password VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'USER',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_email (email)
);
-- Create profiles table
CREATE TABLE profiles (
id VARCHAR(36) PRIMARY KEY,
bio TEXT,
avatar VARCHAR(255),
user_id VARCHAR(36) NOT NULL UNIQUE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Create posts table
CREATE TABLE posts (
id VARCHAR(36) PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
published BOOLEAN DEFAULT FALSE,
author_id VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_author (author_id),
INDEX idx_published (published)
);
-- Create tags table
CREATE TABLE tags (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
-- Create posts_tags junction table (many-to-many)
CREATE TABLE posts_tags (
post_id VARCHAR(36) NOT NULL,
tag_id VARCHAR(36) NOT NULL,
PRIMARY KEY (post_id, tag_id),
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
```
## Relationship Types
### One-to-One
```prisma
model User {
profile Profile?
}
model Profile {
user User @relation(fields: [userId], references: [id])
userId String @unique
}
```
### One-to-Many
```prisma
model User {
posts Post[]
}
model Post {
author User @relation(fields: [authorId], references: [id])
authorId String
}
```
### Many-to-Many
```prisma
model Post {
tags Tag[]
}
model Tag {
posts Post[]
}
```
## Best Practices
### Indexing
- Index foreign keys
- Index frequently queried columns
- Composite indexes for multi-column queries
- Don't over-index (slows writes)
### Constraints
- Use NOT NULL where appropriate
- Add unique constraints for unique data
- Use check constraints for validation
- Set proper ON DELETE behavior (CASCADE, SET NULL, RESTRICT)
### Data Types
- Use appropriate types (INT, VARCHAR, TEXT, TIMESTAMP, etc.)
- Use ENUM for fixed sets of values
- Use JSON for flexible data (sparingly)
- Consider UUID vs auto-increment IDs
### Migrations
- Never edit existing migrations
- Create new migration for each change
- Test migrations before production
- Include both up and down migrations
- Back up data before running migrations