Agent skill

database-designer

Conçoit des schémas de base de données avec ERD, migrations, indexes et optimisations. Utiliser pour les projets avec persistence, quand on définit des modèles, ou quand l'utilisateur dit "database", "schema", "tables", "migrations". Peut être déclenché après PRD ou Architecture.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/database-designer

SKILL.md

Database Designer 🗄️

Mode activé : Conception de Base de Données

Je vais concevoir un schéma de base de données complet avec ERD, migrations et optimisations.


📥 Contexte à charger

Au démarrage, identifier l'environnement de base de données.

Contexte Pattern/Action Priorité
PRD existant Glob: docs/planning/prd/*.md Optionnel
Architecture Glob: docs/planning/architecture/*.md Optionnel
API existante Glob: docs/api/*.yaml Optionnel
Schémas existants Glob: schema.prisma *.sql drizzle.config.* Optionnel
ORM détecté Grep: package.json pour prisma/drizzle-orm/typeorm/sequelize/knex Requis
Base de données Grep: package.json pour pg/mysql2/better-sqlite3/@libsql/mongodb Requis

Instructions de chargement

  1. Chercher le PRD pour les entités métier
  2. Vérifier l'architecture technique
  3. Scanner les schémas existants pour cohérence
  4. Détecter l'ORM et le type de base de données

Activation

Avant de commencer, je vérifie :

  • PRD ou description des données disponible
  • Type de base de données identifié (SQL/NoSQL)
  • ORM/Query builder choisi (ou à recommander)

Rôle & Principes

Rôle : Architecte de données qui conçoit des schémas performants, maintenables et évolutifs.

Principes :

  1. Data First : Le schéma avant le code
  2. Normalization : 3NF par défaut, dénormaliser si justifié
  3. Performance : Indexes dès la conception
  4. Evolution : Migrations réversibles

Règles :

  • ⛔ Ne JAMAIS stocker de mots de passe en clair
  • ⛔ Ne JAMAIS utiliser de CASCADE DELETE sans réflexion
  • ⛔ Ne JAMAIS ignorer les contraintes d'intégrité
  • ✅ Toujours définir les indexes pour les FK
  • ✅ Toujours inclure created_at/updated_at
  • ✅ Toujours utiliser des UUIDs ou ULID pour les IDs publics

Process

1. Analyse des entités

Input requis : PRD, API spec, ou description fonctionnelle

Je détermine :

Aspect Questions
Entités Quels objets métier ?
Relations 1:1, 1:N, N:M ?
Volume Rows attendus par table ?
Accès Lecture vs Écriture ?

⏸️ STOP - Valider les entités avant de continuer


2. Modélisation des entités

Pour chaque entité, je définis :

yaml
Entity: User
  Description: Utilisateur de l'application
  Table: users

  Columns:
    - id: uuid PRIMARY KEY DEFAULT gen_random_uuid()
    - email: varchar(255) UNIQUE NOT NULL
    - password_hash: varchar(255) NOT NULL
    - name: varchar(100)
    - role: enum('user', 'admin') DEFAULT 'user'
    - email_verified_at: timestamp
    - created_at: timestamp DEFAULT now()
    - updated_at: timestamp DEFAULT now()

  Indexes:
    - idx_users_email: (email) UNIQUE
    - idx_users_role: (role)

  Constraints:
    - email must be valid format (app level)

Types de données recommandés

Type PostgreSQL MySQL SQLite
ID uuid char(36) text
String varchar(n) varchar(n) text
Long text text text text
Integer integer int integer
Big int bigint bigint integer
Decimal numeric(p,s) decimal(p,s) real
Boolean boolean tinyint(1) integer
Date date date text
Datetime timestamp datetime text
JSON jsonb json text
Enum enum type enum text

⏸️ STOP - Valider les colonnes avant les relations


3. Design des relations

┌─────────────┐       ┌─────────────┐
│   users     │       │   posts     │
├─────────────┤       ├─────────────┤
│ id (PK)     │──┐    │ id (PK)     │
│ email       │  │    │ title       │
│ name        │  └───<│ user_id(FK) │
└─────────────┘       │ content     │
                      └─────────────┘

Types de relations

Relation Implémentation Exemple
1:1 FK + UNIQUE User → Profile
1:N FK sur le "N" User → Posts
N:M Table de jonction Posts ↔ Tags

Table de jonction (N:M)

sql
CREATE TABLE post_tags (
  post_id uuid REFERENCES posts(id) ON DELETE CASCADE,
  tag_id uuid REFERENCES tags(id) ON DELETE CASCADE,
  created_at timestamp DEFAULT now(),
  PRIMARY KEY (post_id, tag_id)
);

CREATE INDEX idx_post_tags_tag ON post_tags(tag_id);

⏸️ STOP - Valider les relations avant l'ERD


4. ERD (Entity Relationship Diagram)

Je génère un ERD en ASCII :

┌──────────────────┐         ┌──────────────────┐
│      users       │         │      posts       │
├──────────────────┤         ├──────────────────┤
│ * id: uuid [PK]  │────┐    │ * id: uuid [PK]  │
│ * email: varchar │    │    │ * title: varchar │
│   name: varchar  │    └───<│ * user_id: uuid  │
│ * role: enum     │         │   content: text  │
│ * created_at     │         │   published_at   │
│ * updated_at     │         │ * created_at     │
└──────────────────┘         └──────────────────┘
        │                            │
        │                            │
        ▼                            ▼
┌──────────────────┐         ┌──────────────────┐
│    profiles      │         │    post_tags     │
├──────────────────┤         ├──────────────────┤
│ * id: uuid [PK]  │         │ * post_id [PK,FK]│
│ * user_id [FK,U] │         │ * tag_id [PK,FK] │
│   avatar_url     │         │ * created_at     │
│   bio: text      │         └──────────────────┘
└──────────────────┘                  │
                                      │
                              ┌───────┴───────┐
                              ▼
                      ┌──────────────────┐
                      │      tags        │
                      ├──────────────────┤
                      │ * id: uuid [PK]  │
                      │ * name: varchar  │
                      │ * slug: varchar  │
                      └──────────────────┘

Legend: * = NOT NULL, [PK] = Primary Key, [FK] = Foreign Key, [U] = Unique

5. Indexes & Performance

Index Strategy

Type Quand utiliser
Primary Key Automatique
Foreign Key Toujours sur les FK
Unique Contraintes business (email, slug)
Composite Requêtes multi-colonnes
Partial Sous-ensemble de données
GIN/GiST JSON, full-text, arrays

Checklist indexes

sql
-- FK indexes (obligatoires)
CREATE INDEX idx_posts_user_id ON posts(user_id);

-- Colonnes WHERE fréquentes
CREATE INDEX idx_posts_published ON posts(published_at)
  WHERE published_at IS NOT NULL;

-- Colonnes ORDER BY
CREATE INDEX idx_posts_created ON posts(created_at DESC);

-- Recherche full-text (PostgreSQL)
CREATE INDEX idx_posts_search ON posts
  USING GIN(to_tsvector('english', title || ' ' || content));

6. Migrations

Je génère les migrations dans l'ordre :

migrations/
├── 001_create_users.sql
├── 002_create_posts.sql
├── 003_create_tags.sql
├── 004_create_post_tags.sql
└── 005_add_indexes.sql

Format migration (SQL)

sql
-- Migration: 001_create_users
-- Description: Create users table
-- Created: 2024-01-20

-- UP
CREATE TABLE users (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  email varchar(255) UNIQUE NOT NULL,
  password_hash varchar(255) NOT NULL,
  name varchar(100),
  role varchar(20) DEFAULT 'user' CHECK (role IN ('user', 'admin')),
  email_verified_at timestamp,
  created_at timestamp DEFAULT now(),
  updated_at timestamp DEFAULT now()
);

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role ON users(role);

-- DOWN
DROP TABLE IF EXISTS users;

Format migration (Prisma)

prisma
model User {
  id              String    @id @default(uuid())
  email           String    @unique
  passwordHash    String    @map("password_hash")
  name            String?
  role            Role      @default(USER)
  emailVerifiedAt DateTime? @map("email_verified_at")
  createdAt       DateTime  @default(now()) @map("created_at")
  updatedAt       DateTime  @updatedAt @map("updated_at")

  posts           Post[]
  profile         Profile?

  @@index([role])
  @@map("users")
}

enum Role {
  USER
  ADMIN
}

Format migration (Drizzle)

typescript
import { pgTable, uuid, varchar, timestamp, pgEnum } from 'drizzle-orm/pg-core';

export const roleEnum = pgEnum('role', ['user', 'admin']);

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: varchar('email', { length: 255 }).unique().notNull(),
  passwordHash: varchar('password_hash', { length: 255 }).notNull(),
  name: varchar('name', { length: 100 }),
  role: roleEnum('role').default('user'),
  emailVerifiedAt: timestamp('email_verified_at'),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
}, (table) => ({
  roleIdx: index('idx_users_role').on(table.role),
}));

7. Seed Data

typescript
// seeds/001_users.ts
export const seedUsers = [
  {
    id: '00000000-0000-0000-0000-000000000001',
    email: 'admin@example.com',
    name: 'Admin User',
    role: 'admin',
  },
  {
    id: '00000000-0000-0000-0000-000000000002',
    email: 'user@example.com',
    name: 'Test User',
    role: 'user',
  },
];

Output Template

markdown
# Database Design: [Project Name]

## Overview

| Aspect | Value |
|--------|-------|
| **Database** | PostgreSQL / MySQL / SQLite |
| **ORM** | Prisma / Drizzle / TypeORM |
| **Tables** | [X] |
| **Relations** | [X] |

## ERD

[ASCII diagram]

## Tables

### [Table 1]
[Columns, types, constraints]

### [Table 2]
...

## Indexes

[Index list with justification]

## Migrations

See: `migrations/` or `prisma/migrations/`

## Seed Data

See: `seeds/`

## Performance Notes

[Query patterns, expected load, optimization tips]

Fichier : docs/database/DB-{slug}.md Schema : prisma/schema.prisma ou src/db/schema.ts Migrations : migrations/ ou prisma/migrations/


Output Validation

✅ Checklist Output Database Designer

Critère Status
Entités identifiées et documentées ✅/❌
Relations définies (1:1, 1:N, N:M) ✅/❌
ERD généré ✅/❌
Indexes définis pour FK et requêtes ✅/❌
Migrations générées ✅/❌
Seed data créé ✅/❌
Format ORM correct (si applicable) ✅/❌

Score minimum : 6/7


Auto-Chain

markdown
## 🔗 Prochaine étape

✅ Database Design terminé et sauvegardé.

→ 🔌 **Lancer `/api-designer`** pour concevoir l'API sur ce schéma ?
→ 📝 **Lancer `/pm-stories`** pour créer les stories d'implémentation ?

---

**[A] API Designer** | **[S] Stories** | **[P] Pause**

Transitions

  • Depuis PRD : "Tu veux que je design la base de données maintenant ?"
  • Depuis Architecture : "L'architecture mentionne une DB, je la design ?"
  • Vers API : "Schema prêt, je design l'API CRUD ?"
  • Vers Stories : "Prêt à créer les stories d'implémentation ?"

Exemples

Design pour un blog

bash
/database-designer blog-platform

Design depuis PRD

bash
/database-designer docs/planning/prd/PRD-saas-dashboard.md

Design avec ORM spécifique

bash
/database-designer --orm prisma e-commerce

Démarrage 🚀

Arguments reçus : $ARGUMENTS

Je vais maintenant :

  1. Analyser les besoins (PRD, description)
  2. Identifier les entités et relations
  3. Générer l'ERD
  4. Définir les indexes
  5. Créer les migrations

Analyse en cours...

Didn't find tool you were looking for?

Be as detailed as possible for better results