mcpField
D
database-schema

database-schema

github.com/alinaqiデータ・データベース711301 回インストール2 週間前に更新
リポジトリ

database-schema について

データベースコードを書く前にスキーマを確認するための Claude 向けスキルです。カラムや型、リレーション、NULL 許容性、生成型を検証し、スキーマに起因するミスを減らします。

主な機能

  1. 01実装前のスキーマ確認
  2. 02カラム・型・関係・NULL許容性の検証
  3. 03ORM生成型の利用
  4. 04マイグレーションと型生成の手順

活用シーン

  1. 01データベースを使う機能の実装
  2. 02クエリのフィールドと型の確認
  3. 03スキーマ変更後のマイグレーションと型生成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alinaqi/maggy --skill database-schema

インストール後、Claude Code で/database-schemaを入力して読み込まれたか確認します。

詳細

データベーススキーマを意識するスキル

問題: Claude はセッション中にスキーマの詳細を忘れてしまい、誤ったカラム名や不足しているフィールド、誤った型を使用することがあります。TDD なら実行時に検出できますが、もっと早い段階で防止できます。


基本ルール:データベースコードを書く前にスキーマを読む

必須:データベースに関わるコードを書く前に、必ず以下を行ってください。

┌─────────────────────────────────────────────────────────────┐
│  1. READ the schema file (see locations below)              │
│  2. VERIFY columns/types you're about to use exist          │
│  3. REFERENCE schema in your response when writing queries  │
│  4. TYPE-CHECK using generated types (Drizzle/Prisma/etc)   │
└─────────────────────────────────────────────────────────────┘

スキーマファイルが存在しない場合 → 作業を進める前に作成してください。


スキーマファイルの場所(スタック別)

スタックスキーマの場所型生成
Drizzlesrc/db/schema.ts または drizzle/schema.tsTypeScript に組み込み
Prismaprisma/schema.prismanpx prisma generate
Supabasesupabase/migrations/*.sql +型supabase gen types typescript
SQLAlchemyapp/models/*.py または src/models.pyPydantic モデル
TypeORMsrc/entities/*.tsデコレーター=型
Raw SQLschema.sql または migrations/手動で型を定義する必要あり
スキーマ参照ファイル(推奨)

すぐに参照できるよう、_project_specs/schema-reference.md を作成します。

# Database Schema Reference

*Auto-generated or manually maintained. Claude: READ THIS before database work.*

## Tables

### users
| Column | Type | Nullable | Default | Notes |
|--------|------|----------|---------|-------|
| id | uuid | NO | gen_random_uuid() | PK |
| email | text | NO | - | Unique |
| name | text | YES | - | Display name |
| created_at | timestamptz | NO | now() | - |
| updated_at | timestamptz | NO | now() | - |

### orders
| Column | Type | Nullable | Default | Notes |
|--------|------|----------|---------|-------|
| id | uuid | NO | gen_random_uuid() | PK |
| user_id | uuid | NO | - | FK → users.id |
| status | text | NO | 'pending' | enum: pending/paid/shipped/delivered |
| total_cents | integer | NO | - | Amount in cents |
| created_at | timestamptz | NO | now() | - |

## Relationships
- users 1:N orders (user_id)

## Enums
- order_status: pending, paid, shipped, delivered

コードを書く前のチェックリスト(データベース作業)

データベースコードを書く前に、Claude は必ず以下を行います。

### Schema Verification Checklist
- [ ] Read schema file: `[path to schema]`
- [ ] Columns I'm using exist: [list columns]
- [ ] Types match my code: [list type mappings]
- [ ] Relationships are correct: [list FKs]
- [ ] Nullable fields handled: [list nullable columns]

実際の例:

### Schema Verification for TODO-042 (Add order history endpoint)

- [x] Read schema: `src/db/schema.ts`
- [x] Columns exist: orders.id, orders.user_id, orders.status, orders.total_cents, orders.created_at
- [x] Types: id=uuid→string, total_cents=integer→number, status=text→OrderStatus enum
- [x] Relationships: orders.user_id → users.id (many-to-one)
- [x] Nullable: none of these columns are nullable

型生成コマンド

Drizzle(TypeScript)
// Schema defines types automatically
// src/db/schema.ts
import { pgTable, uuid, text, integer, timestamp } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const orders = pgTable('orders', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => users.id),
  status: text('status').notNull().default('pending'),
  totalCents: integer('total_cents').notNull(),
  createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Inferred types - USE THESE
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
export type Order = typeof orders.$inferSelect;
export type NewOrder = typeof orders.$inferInsert;
Prisma
// prisma/schema.prisma
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String?
  orders    Order[]
  createdAt DateTime @default(now()) @map("created_at")

  @@map("users")
}

model Order {
  id         String   @id @default(uuid())
  userId     String   @map("user_id")
  user       User     @relation(fields: [userId], references: [id])
  status     String   @default("pending")
  totalCents Int      @map("total_cents")
  createdAt  DateTime @default(now()) @map("created_at")

  @@map("orders")
}
# Generate types after schema changes
npx prisma generate
Supabase
# Generate TypeScript types from live database
supabase gen types typescript --local > src/types/database.ts

# Or from remote
supabase gen types typescript --project-id your-project-id > src/types/database.ts
// Use generated types
import { Database } from '@/types/database';

type User = Database['public']['Tables']['users']['Row'];
type NewUser = Database['public']['Tables']['users']['Insert'];
type Order = Database['public']['Tables']['orders']['Row'];
SQLAlchemy(Python)
# app/models/user.py
from sqlalchemy import Column, String, DateTime
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
from app.db import Base
import uuid

class User(Base):
    __tablename__ = "users"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    email = Column(String, nullable=False, unique=True)
    name = Column(String, nullable=True)
    created_at = Column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    orders = relationship("Order", back_populates="user")
# app/schemas/user.py - Pydantic for API validation
from pydantic import BaseModel, EmailStr
from uuid import UUID
from datetime import datetime

class UserBase(BaseModel):
    email: EmailStr
    name: str | None = None

class UserCreate(UserBase):
    pass

class User(UserBase):
    id: UUID
    created_at: datetime

    class Config:
        from_attributes = True

スキーマを意識した TDD ワークフロー

データベース作業向けに、標準的な TDD ワークフローを拡張します。

┌─────────────────────────────────────────────────────────────┐
│  0. SCHEMA: Read and verify schema before anything else     │
│     └─ Read schema file                                     │
│     └─ Complete Schema Verification Checklist               │
│     └─ Note any missing columns/tables needed               │
├─────────────────────────────────────────────────────────────┤
│  1. RED: Write tests that use correct column names          │
│     └─ Import generated types                               │
│     └─ Use type-safe queries in tests                       │
│     └─ Tests should fail on logic, NOT schema errors        │
├─────────────────────────────────────────────────────────────┤
│  2. GREEN: Implement with type-safe queries                 │
│     └─ Use ORM types, not raw strings                       │
│     └─ TypeScript/mypy catches column mismatches            │
├─────────────────────────────────────────────────────────────┤
│  3. VALIDATE: Type check catches schema drift               │
│     └─ tsc --noEmit / mypy catches wrong columns            │
│     └─ Tests validate runtime behavior                      │
└─────────────────────────────────────────────────────────────┘

よくあるスキーマの間違い(およびその防止方法)

間違い例防止方法
カラム名が誤っているuser.userName と user.nameスキーマを読み、生成された型を使用する
型が誤っているtotalCents を文字列として扱う型生成で検出できます
NULL 許容チェックの漏れNULL 許容の場合に user.name! を使用するスキーマで NULL 許容フィールドを確認する
外部キーのリレーションシップが誤っているorder.userId と order.user_idスキーマでカラム名を確認する
カラムが不足している存在しない user.avatar を使用するコードを書く前にスキーマを読む
列挙値が誤っているstatus: 'complete' と 'completed'スキーマ参照に列挙値を記載する
型安全なクエリの例

Drizzle(コンパイル時にエラーを検出):

// ✅ Correct - uses schema-defined columns
const user = await db.select().from(users).where(eq(users.email, email));

// ❌ Wrong - TypeScript error: 'userName' doesn't exist
const user = await db.select().from(users).where(eq(users.userName, email));

Prisma(コンパイル時にエラーを検出):

// ✅ Correct
const user = await prisma.user.findUnique({ where: { email } });

// ❌ Wrong - TypeScript error
const user = await prisma.user.findUnique({ where: { userName: email } });

Raw SQL(保護機能なし—使用を避ける):

// ❌ Dangerous - no type checking, easy to get wrong
const result = await db.query('SELECT * FROM users WHERE user_name = $1', [email]);
// Should be 'email' not 'user_name' - won't catch until runtime

マイグレーションのワークフロー

スキーマの変更が必要な場合:

┌─────────────────────────────────────────────────────────────┐
│  1. Update schema file (Drizzle/Prisma/SQLAlchemy)          │
├─────────────────────────────────────────────────────────────┤
│  2. Generate migration                                       │
│     └─ Drizzle: npx drizzle-kit generate                    │
│     └─ Prisma: npx prisma migrate dev --name add_column     │
│     └─ Supabase: supabase migration new add_column          │
├─────────────────────────────────────────────────────────────┤
│  3. Regenerate types                                         │
│     └─ Prisma: npx prisma generate                          │
│     └─ Supabase: supabase gen types typescript              │
├─────────────────────────────────────────────────────────────┤
│  4. Update schema-reference.md                               │
├─────────────────────────────────────────────────────────────┤
│  5. Run type check - find all broken code                    │
│     └─ npm run typecheck                                    │
├─────────────────────────────────────────────────────────────┤
│  6. Fix type errors, update tests, run full validation       │
└─────────────────────────────────────────────────────────────┘

セッション開始時の手順

データベース作業を行うセッションを開始する際は、次の手順を実行します。

  1. すぐにスキーマファイルを読む
  2. _project_specs/schema-reference.md があれば読む
  3. 関連するテーブルやカラムをセッションの状態に記録する
  4. コードを書く際にスキーマを明示的に参照する

セッション状態の例:

## Current Session - Database Context

**Schema read:** ✓ src/db/schema.ts
**Tables in scope:** users, orders, order_items
**Key columns:**
- users: id, email, name, created_at
- orders: id, user_id, status, total_cents
- order_items: id, order_id, product_id, quantity, price_cents

アンチパターン

  • ❌ カラム名を推測する - 必ず最初にスキーマを読む
  • ❌ 生の SQL 文字列を使う - 型生成に対応した ORM を使う
  • ❌ 確認せずにハードコードする - カラムを使用する前にスキーマを確認する
  • ❌ 型エラーを無視する - スキーマの不整合は型エラーとして現れる
  • ❌ 型を再生成しない - マイグレーション後は必ず再生成する
  • ❌ NULL 許容だと思い込む - NULL 許容カラムかどうかをスキーマで確認する

チェックリスト

セットアップ
  • 標準の場所にスキーマファイルがある
  • 型生成が設定されている
  • _project_specs/schema-reference.md が作成されている
  • スキーマ変更時に型が再生成される
タスクごと
  • データベースコードを書く前にスキーマを読んだ
  • スキーマ検証チェックリストを完了した
  • 生成された型を使用している(生の文字列ではない)
  • 型チェックに合格している(カラムのエラーを検出する)
  • テストで正しいスキーマを使用している

コメント