スキル一覧に戻る
physics91

schema-reviewer

by physics91

Claude Code hooks를 활용하여 세션 컴팩션 시 AGENTS.md 컨텍스트를 자동으로 보존/복원하는 플러그인

0🍴 0📅 2025年12月29日
GitHubで見るManusで実行

SKILL.md


name: schema-reviewer description: | WHEN: Database schema review, table design, normalization, constraints, index planning WHAT: Normalization analysis + Constraint validation + Index strategy + Data types + Relationship design WHEN NOT: Query optimization → sql-optimizer, ORM code → orm-reviewer

Schema Reviewer Skill

Purpose

Reviews database schema design for normalization, constraints, indexes, and best practices.

When to Use

  • Database schema review
  • Table design review
  • Normalization check
  • Index planning
  • Constraint validation

Project Detection

  • Schema files (.sql, schema.prisma)
  • Migration files
  • Entity definitions
  • Database documentation

Workflow

Step 1: Analyze Schema

**Database**: PostgreSQL/MySQL
**Tables**: 15
**Relationships**: 1:N, N:M
**Normalization**: 3NF

Step 2: Select Review Areas

AskUserQuestion:

"Which areas to review?"
Options:
- Full schema review (recommended)
- Normalization and design
- Constraints and integrity
- Index strategy
- Data type optimization
multiSelect: true

Detection Rules

Normalization

CheckRecommendationSeverity
Repeating groupsMove to separate tableHIGH
Partial dependencyApply 2NFMEDIUM
Transitive dependencyApply 3NFMEDIUM
Over-normalizationConsider denormalization for readsLOW
-- BAD: 1NF violation (repeating groups)
CREATE TABLE orders (
    id INT PRIMARY KEY,
    product1_id INT,
    product1_qty INT,
    product2_id INT,
    product2_qty INT,
    product3_id INT,
    product3_qty INT
);

-- GOOD: Normalized with separate table
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL REFERENCES users(id),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE order_items (
    id SERIAL PRIMARY KEY,
    order_id INT NOT NULL REFERENCES orders(id),
    product_id INT NOT NULL REFERENCES products(id),
    quantity INT NOT NULL CHECK (quantity > 0),
    price DECIMAL(10,2) NOT NULL
);

-- BAD: 2NF violation (partial dependency)
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    product_name VARCHAR(100),  -- Depends only on product_id!
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

-- GOOD: Product name in products table only
CREATE TABLE order_items (
    order_id INT REFERENCES orders(id),
    product_id INT REFERENCES products(id),
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

Constraints

CheckRecommendationSeverity
Missing PRIMARY KEYAdd primary keyCRITICAL
Missing FOREIGN KEYAdd for relationshipsHIGH
No NOT NULLAdd where appropriateMEDIUM
No CHECK constraintsValidate data at DB levelMEDIUM
Missing UNIQUEAdd for natural keysHIGH
-- BAD: No constraints
CREATE TABLE users (
    id INT,
    email VARCHAR(255),
    status VARCHAR(20)
);

-- GOOD: Proper constraints
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    status VARCHAR(20) NOT NULL DEFAULT 'active'
        CHECK (status IN ('active', 'inactive', 'banned')),
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- With proper foreign keys
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL REFERENCES users(id)
        ON DELETE RESTRICT  -- Prevent user deletion with orders
        ON UPDATE CASCADE,
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'processing', 'shipped', 'delivered', 'cancelled')),
    total DECIMAL(12,2) NOT NULL CHECK (total >= 0)
);

Data Types

CheckRecommendationSeverity
VARCHAR for all stringsUse appropriate typesMEDIUM
INT for monetary valuesUse DECIMALHIGH
FLOAT for moneyUse DECIMALCRITICAL
TEXT without limitConsider VARCHAR with limitLOW
Missing timezoneUse TIMESTAMPTZHIGH
-- BAD: Poor data type choices
CREATE TABLE products (
    id INT,
    price FLOAT,              -- Precision issues!
    quantity VARCHAR(10),     -- Should be INT
    created_at TIMESTAMP,     -- No timezone!
    description TEXT          -- Unlimited
);

-- GOOD: Appropriate data types
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    sku VARCHAR(50) NOT NULL UNIQUE,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
    quantity INT NOT NULL DEFAULT 0 CHECK (quantity >= 0),
    description TEXT,  -- OK for long text
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Use ENUMs for fixed values (PostgreSQL)
CREATE TYPE order_status AS ENUM (
    'pending', 'processing', 'shipped', 'delivered', 'cancelled'
);

CREATE TABLE orders (
    status order_status NOT NULL DEFAULT 'pending'
);

Index Strategy

CheckRecommendationSeverity
No index on FKAdd indexHIGH
No index on filter columnsAdd indexHIGH
Too many single-column indexesUse compositeMEDIUM
Missing unique indexAdd for unique constraintsHIGH
-- Index planning
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL REFERENCES users(id),
    status VARCHAR(20) NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Foreign key index (not automatic in PostgreSQL!)
CREATE INDEX idx_orders_user_id ON orders(user_id);

-- Composite index for common queries
-- WHERE status = ? ORDER BY created_at DESC
CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);

-- Partial index for specific cases
CREATE INDEX idx_orders_pending ON orders(created_at)
WHERE status = 'pending';

-- Cover index (includes all needed columns)
CREATE INDEX idx_orders_user_summary ON orders(user_id, status, total);

Relationship Design

CheckRecommendationSeverity
N:M without junction tableCreate junction tableCRITICAL
Self-reference without depthAdd level/path columnMEDIUM
Circular referencesRedesign relationshipsHIGH
-- N:M relationship with junction table
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(200) NOT NULL
);

CREATE TABLE categories (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

CREATE TABLE product_categories (
    product_id INT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
    category_id INT NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
    PRIMARY KEY (product_id, category_id)
);

-- Hierarchical data (adjacency list)
CREATE TABLE categories (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    parent_id INT REFERENCES categories(id),
    level INT NOT NULL DEFAULT 0,
    path LTREE  -- PostgreSQL ltree extension
);

-- Create index for hierarchical queries
CREATE INDEX idx_categories_path ON categories USING GIST (path);

Audit Columns

-- Standard audit columns
CREATE TABLE entities (
    id SERIAL PRIMARY KEY,
    -- ... business columns ...
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    created_by INT REFERENCES users(id),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_by INT REFERENCES users(id),
    deleted_at TIMESTAMPTZ,  -- Soft delete
    deleted_by INT REFERENCES users(id)
);

-- Auto-update trigger
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_update_updated_at
    BEFORE UPDATE ON entities
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at();

Response Template

## Database Schema Review Results

**Database**: PostgreSQL 15
**Tables**: 12 | **Relationships**: 8

### Normalization
| Status | Table | Issue |
|--------|-------|-------|
| HIGH | orders | Repeating product columns |

### Constraints
| Status | Table | Issue |
|--------|-------|-------|
| CRITICAL | users | Missing PRIMARY KEY |
| HIGH | orders | Missing FOREIGN KEY to users |

### Data Types
| Status | Table.Column | Issue |
|--------|--------------|-------|
| CRITICAL | products.price | Using FLOAT instead of DECIMAL |

### Indexes
| Status | Table | Issue |
|--------|-------|-------|
| HIGH | orders.user_id | Missing index on foreign key |

### Recommended Changes
```sql
-- Add missing primary key
ALTER TABLE users ADD PRIMARY KEY (id);

-- Fix price data type
ALTER TABLE products
ALTER COLUMN price TYPE DECIMAL(10,2);

-- Add foreign key index
CREATE INDEX idx_orders_user_id ON orders(user_id);

## Best Practices
1. **Normalization**: 3NF default, denormalize for performance
2. **Constraints**: PK, FK, NOT NULL, CHECK, UNIQUE
3. **Data Types**: DECIMAL for money, TIMESTAMPTZ for time
4. **Indexes**: FK columns, filter columns, composites
5. **Audit**: created_at, updated_at, soft delete

## Integration
- `sql-optimizer`: Query performance
- `migration-checker`: Migration safety
- `orm-reviewer`: ORM mapping

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です