# Comprehensive Design Review

> このスキルは、ユーザーが "/comprehensive-design-review" を呼び出したとき、または DB スキーマに対する包括的な設計レビューを依頼したときに使用する。SQL アンチパターンのような局所的・短期的な失敗パターンではなく、正しさ・整合性、長期負債化しやすい設計選択、非機能要件、変更容易性といった横断的・長期的な観点でレビューする。

- Skill: `ken3pei/comprehensive-design-review` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ken3pei/comprehensive-design-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ken3pei/comprehensive-design-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: KEN3pei (https://skillmd.com/u/ken3pei)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/ken3pei/comprehensive-design-review

---


# DB 設計レビュー（包括的観点）

SQL アンチパターン本のような「局所的・短期的な失敗パターン」のチェックでは拾いきれない、
**横断的・長期的な観点**で DB スキーマをレビューする。

主に以下 4 軸で評価する：

- **軸 A: 正しさ・整合性** — バグや不整合を生む設計
- **軸 B: 長期負債化しやすい設計選択** — 初期は便利でも運用年数とともに利息が膨らむ選択
- **軸 C: 非機能要件** — パフォーマンス、セキュリティ、コンプライアンス、運用性
- **軸 D: 命名・一貫性・変更容易性** — 未来の変更コストを左右する設計

---

## レビュー観点

### 軸 A: 正しさ・整合性

#### A-1: 制約網羅性
- `NOT NULL` / `CHECK` / `UNIQUE` / `FOREIGN KEY` が業務不変条件を表現しているか
- 「アプリ側で担保している」前提の暗黙制約が DB に落ちていないか
- `ON DELETE` / `ON UPDATE` のアクション（CASCADE / SET NULL / RESTRICT）が業務意味と一致しているか
- enum 的な値が `CHECK (col IN (...))` または別マスタテーブルで縛られているか

#### A-2: NULL セマンティクス
- 「未入力」「該当なし」「未確定」などの異なる意味が同じ NULL で表現されていないか
- NULL を許容することで 3 値論理の罠（`WHERE col != 'x'` が NULL を除外する等）が生じないか
- 「A が NULL のときは B が必須」のような相関制約が CHECK で表現されているか

#### A-3: TOCTOU・競合
- 「存在チェック → INSERT」「残数チェック → 減算」のような 2 段階処理が想定されている箇所はないか
- `UNIQUE` 制約 + UPSERT 系構文で原子化できる構造になっているか
- カウンタ・残高系の更新が `UPDATE ... SET col = col + ?` 形式（CAS 相当）になっているか、楽観ロック用カラム（`version`）が必要か
- 在庫・残高系で行ロックが必要なフローはあるか（採用 DB の分離レベル既定値を踏まえて評価）

#### A-4: 時刻制御の落とし穴
- 時刻系カラムがタイムゾーン情報を保持する型を採用しているか（DB により型名は異なる）
- デフォルト値関数（`now()` / `current_timestamp` 等）のタイムゾーン挙動の理解は正しいか
- `created_at` / `updated_at` / `deleted_at` / `*_expires_at` などの命名・粒度の一貫性
- アプリ層の時刻と DB 時刻のどちらを正にするかが決まっているか
- 「未来日時」「9999-12-31 終端」「epoch 0」などのセンチネル値の混入

---

### 軸 B: 長期負債化しやすい設計選択

短期的には便利・安全に見えて、運用年数とともに利息が膨らむ設計選択。
**「変更容易性」観点と独立して**評価すること（変更容易性 = 未来の変更コスト、こちらは過去の選択の利息）。

#### B-1: 論理削除負債（soft delete）
参照: <https://syu-m-5151.hatenablog.com/entry/2025/12/24/110101>

- `deleted_at` / `is_deleted` カラムを使った soft delete を採用していないか
- 採用している場合：
  - 全クエリで `WHERE deleted_at IS NULL` が必須となり、付け忘れによるバグ温床になっていないか
  - `UNIQUE` 制約が論理削除済みレコードと衝突しないか（部分 UNIQUE インデックスや別カラムで回避できているか）
  - 関連レコードの整合性（親が論理削除されたとき子はどうなるか）が定義されているか
  - GDPR・個人情報保護法の「削除権」と両立できるか（論理削除では消えていない）
  - 不要レコードの蓄積で集計・インデックスが重くなっていないか
  - そもそも「履歴を残す」目的なら、論理削除ではなく**履歴テーブル / イベントテーブル**の方が適切ではないか

#### B-2: 状態フラグの増殖
- `is_active` / `is_archived` / `is_published` / `is_deleted` などの boolean が同じテーブルに 3 つ以上ないか
- これらの組合せで表現される「状態」が指数的に増え、暗黙の状態機械化していないか
- → 単一の `status` カラム（CHECK 制約付き）または状態遷移テーブルへの集約を検討

#### B-3: 「便利カラム」（集計値のキャッシュ）
- `comment_count`, `like_count`, `view_count` のような集計値キャッシュカラムがあるか
- ある場合：
  - 整合性維持コード（トリガー or アプリ層更新）が散らばっていないか
  - 不整合時の再計算ジョブが用意されているか
  - そもそもオンデマンド計算で十分ではないか

#### B-4: enum / マスタテーブルの選択ミス
- CHECK 制約で済むか、別マスタテーブルにすべきか
- 取り得る値が頻繁に増減する / 値ごとに付帯情報がある → マスタテーブル化
- 固定的・少数 → CHECK 制約
- 逆方向への変更コストが高いため、現状の選択が業務実態と合っているか

#### B-5: JSON / 配列の濫用
- スキーマレス領域（`JSON` / `JSONB` / 配列型）に重要なデータを格納していないか
- 入っている場合：
  - 検索・JOIN・集計に使われていないか（使うなら正規化が必要）
  - インデックスは適切か
  - 「とりあえず」で入れた結果、後から正規化できなくなっていないか

#### B-6: 採番戦略の硬直化
- 主キーが単調増加（連番）になっていないか — 分散DB やホットレンジを生む書き込みパターンに弱い
- ソート性が必要な場合に UUID v7 / ULID など時系列ソート可能な ID 形式の検討余地があるか
- 外部公開する ID と内部 PK が同一だと、後から ID 形式を変えにくい
- 採用 ID 形式と業務要件（推測されにくさ・URL 短さ・分散性・ソート性）が一致しているか

---

### 軸 C: 非機能要件

#### C-1: パフォーマンス・コスト
- 想定アクセスパターン（クエリ）に対するインデックスがあるか
- 過剰なインデックス（書き込みコストとストレージ）はないか
- カバリングインデックス活用余地
- ホットテーブルのアクセスパターン設計
- マネージド DB の場合、課金単位（RU / IOPS / DTU 等）を意識した設計か

#### C-2: セキュリティ
- 認証情報（パスワードハッシュ、API キー、OAuth トークン）の保存形式
  - ハッシュアルゴリズム / ソルトの仕様は決まっているか
  - 平文保存していないか
- PII（メール、氏名、IP、位置情報）のカラム特定と取り扱い方針
- 行レベルセキュリティ (RLS) の要否
- 最小権限：アプリ用 DB ロールが必要以上の権限を持っていないか
- アプリ層との SQL インジェクション耐性（プレースホルダ利用の徹底）

#### C-3: コンプライアンス
- GDPR / 個人情報保護法等の「削除権」「アクセス権」に対応できる設計か
- データ保持期間 / TTL の方針
- 監査ログテーブルの有無と保管期間
- データ越境（リージョン）の制約

#### C-4: 運用・可観測性
- スロークエリ特定のための索引情報・統計が取れるか
- バックアップ / PITR の戦略
- メトリクス用カラムが分析クエリに耐えるか
- スキーマ変更時のオンライン DDL 可否（大規模テーブルの `ADD COLUMN NOT NULL DEFAULT` 影響など）

---

### 軸 D: 命名・一貫性・変更容易性

#### D-1: 命名規則
- テーブル名（単複の統一）、列名（snake_case / camelCase などの統一）、PK 命名（`id` vs `${entity}_id`）の一貫性
- 予約語との衝突回避
- 時刻系列名の規約（`_at` suffix 等）

#### D-2: 監査・履歴
- `created_at` / `updated_at` の全テーブル一貫採用
- 監査ログ要件（誰がいつ何を変更したか）
- 履歴保持が必要なテーブルで、現状の設計が要件を満たすか

#### D-3: スキーマ進化容易性
- 後方互換の取りやすい設計か（カラム追加でなく削除を要する変更が頻発しないか）
- マイグレーションがオンライン DDL で実行可能か
- expand-contract パターンでアプリのローリングデプロイと両立できるか
- 既存マイグレーション修正禁止ルールが運用に定着しているか

#### D-4: アプリ層・ORM 接続点
- DB の型がアプリ層の型に自然にマッピングできるか
- N+1 を誘発する深い親子関係になっていないか
- DTO へのマッピングが容易か（過度に正規化されすぎていないか）

#### D-5: 国際化
- 文字コード / コレーションの方針
- 多言語コンテンツを保持する場合の設計（言語別カラム vs 翻訳テーブル）
- 通貨・単位の保持方式（最小単位整数 vs 小数）

---

## レビュー手順

1. 軸 A → B → C → D の順でチェックリストを走査
2. 各観点で「該当あり / 該当なし / 要確認」を判定
3. 該当ありは具体的な箇所（テーブル名・列名）と改善策を提示
4. 業務要件が判断材料として必要な観点は「要確認」とし、判断に必要な情報を質問形式で残す
5. 最後に「優先度高（業務影響大 or 後から直しにくい）」観点を 3 件以内に絞った総評を書く

---

## 出力形式

```markdown
## DB 設計レビュー結果（包括的観点）

### 対象
- ファイル / スキーマ: ...
- 主要テーブル数: N

### 軸 A: 正しさ・整合性
- A-1 制約網羅性: [該当あり/なし/要確認]
  - 箇所:
  - 問題:
  - 改善策:
- A-2 NULL セマンティクス: ...
- A-3 TOCTOU・競合: ...
- A-4 時刻制御: ...

### 軸 B: 長期負債化しやすい設計選択
- B-1 論理削除負債: ...
- B-2 状態フラグの増殖: ...
- B-3 便利カラム: ...
- B-4 enum/マスタ選択: ...
- B-5 JSON/配列濫用: ...
- B-6 採番戦略: ...

### 軸 C: 非機能要件
- C-1 パフォーマンス・コスト: ...
- C-2 セキュリティ: ...
- C-3 コンプライアンス: ...
- C-4 運用・可観測性: ...

### 軸 D: 命名・一貫性・変更容易性
- D-1 命名規則: ...
- D-2 監査・履歴: ...
- D-3 スキーマ進化容易性: ...
- D-4 ORM 接続点: ...
- D-5 国際化: ...

### 総評
優先度高（業務影響大 or 後から直しにくいもの）を 3 件以内：
1. ...
2. ...
3. ...
```

---

## 留意事項

- **断定を避ける**: スキーマだけでは判断できない観点（業務要件・運用方針・コンプライアンス）は「要確認」として、判断に必要な情報を質問形式で残す
- **DB エンジン固有の詳細**: 採用 DB エンジン（PostgreSQL / MySQL / SQL Server / 分散 DB 等）固有の落とし穴がある場合は、エンジン名を明示した上で言及する
- **既存決定との整合**: 既に決定済みの ADR / 設計ドキュメントと矛盾する提案をする場合は、該当ドキュメントを引用した上で「再検討の必要あり」と明示する

