db-constraints について
データベース監査向けのスキルで、宣言的制約とNULL許容性に関するスキーマの正確性リスクを確認します。必須値、有効範囲、一意な識別子、想定どおりに適用されない可能性のある制約を扱います。
主な機能
- 01NOT NULL 制約の欠落を検出
- 02CHECK 制約によるドメイン規則を確認
- 03一意制約の欠落や大文字小文字の問題を特定
- 04NULL 許容列の UNIQUE の落とし穴を検出
- 05未検証の制約を発見
活用シーン
- 01必須の外部キーや列をレビュー
- 02数量、価格、日付の規則を確認
- 03メールやユーザー名の一意性を監査
- 04論理削除テーブルの重複リスクを調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ hainrixz/ claude-db --skill db-constraintsインストール後、Claude Code で/db-constraintsを入力して読み込まれたか確認します。
詳細
db-constraints (M5)
制約は、どのアプリ、スクリプト、マイグレーションが行を書き込む場合でも、データベースが保証する不変条件です。制約がなければ、「これは常に正しい」は事実ではなく、期待にすぎません。このモジュールは設計軸(制約カテゴリ)です。宣言的制約を適用するエンジンが対象です。ドキュメントストアは、代わりに Validación-schema カテゴリに分類します。
チェック内容
- NOT NULL の不足:必須の意味を持つカラム(必須の親への外部キー、
email、status、タイムスタンプ)が NULL を許可したままになっており、不完全または不正な行を許している。 - CHECK の不足:ドメインルールが適用されていない —
quantity >= 0、price >= 0、status IN (...)、start_date <= end_date、email ~ '@'。アプリは「検証」しますが、データベースは検証しません。 - UNIQUE の不足:メールアドレス、ユーザー名、スラッグ、外部 ID などの自然キーに UNIQUE 制約がなく、重複を許してしまい、結合や認証を破損させる。
- 大文字・小文字を区別しない一意性(メールアドレス):大文字・小文字が混在するカラム(例:
email)に通常のUNIQUEを設定しても、[email protected]と[email protected]は別の行として登録でき、ID が重複します。解決策として、citextカラム型、またはlower(col)に対するUNIQUE式インデックス(例:CREATE UNIQUE INDEX ON users (lower(email)))を明記し、大文字・小文字を正規化した値が競合するようにします。 - NULL を許容する UNIQUE の落とし穴:エンジンが各 NULL を個別の値として扱う場合、NULL 許容カラムに対する UNIQUE 制約では重複を防げません(例:ソフト削除時の一意性に使う
UNIQUE(user_id, deleted_at)は、deleted_atが NULL の場合に機能しません)。部分/フィルター付き一意インデックス、またはNULLS NOT DISTINCTを推奨します。 - NOT VALID / NOCHECK として宣言され、検証されないままの制約。
軸と重大度
- 軸:設計。重大度は範囲で示し、違反件数を捏造しません。
- 重複 ID を許す認証キー/自然キーに対する UNIQUE の不足:重大度 4、
fail/warn、信頼度directional。 - 重複を気づかれないまま許す、NULL を許容する UNIQUE の落とし穴:重大度 4、
warn(見落としやすく、影響が大きい)。 - 必須の外部キー/カラムに対する NOT NULL の不足:重大度 3、
warn。 - 明示されたドメインルールに対する CHECK の不足:重大度 2~3、
warn、fixable: proposed。 - M5 は重大度 5 の上限を設けません。制約カテゴリの値を形成します。
Tier-0 静的チェック
scripts/parse-schema.mjs で DDL/スナップショットを解析し、NOT NULL がないカラムを列挙します。UNIQUE/一意インデックスがない自然キー名のカラムを検出します。メンバーカラムが NULL を許容する UNIQUE 制約(NULL を許容する落とし穴)を特定します。数量/価格/日付範囲のカラムに対する CHECK の欠落をスキャンします。プログラムソースの解析結果は directional のままです。
Tier-1 検証クエリ
制約と NULL 許容性を一覧表示します:
-- $DATABASE_URL, read-only
SELECT c.table_name, c.column_name, c.is_nullable,
tc.constraint_type
FROM information_schema.columns c
LEFT JOIN information_schema.constraint_column_usage ccu
ON ccu.table_name = c.table_name AND ccu.column_name = c.column_name
LEFT JOIN information_schema.table_constraints tc
ON tc.constraint_name = ccu.constraint_name AND tc.constraint_type IN ('UNIQUE','CHECK')
WHERE c.table_schema NOT IN ('pg_catalog','information_schema');
NULL を許容する UNIQUE に実際に重複があることを確認します:
SELECT user_id, count(*) FROM memberships WHERE deleted_at IS NULL
GROUP BY user_id HAVING count(*) > 1;
検出結果
schema/finding.schema.json に従って出力します。例:
M5.users.email_no_unique—emailに UNIQUE 制約がなく、ID が重複する可能性がある(重大度 4、warn、軸design、fixable: proposed)。M5.memberships.over_nullable_unique—UNIQUE(user_id, deleted_at)により、deleted_atが NULL の場合に重複が可能になる(重大度 4、warn、軸design)。M5.order_items.quantity_no_check—CHECK (quantity >= 0)がない(重大度 3、warn)。M5.events.user_id_nullable— 必須の外部キーカラムが NULL を許容している(重大度 3、warn)。 各検出結果では、evidence.observedにカラム/制約の DDL をそのまま引用します。verification.reproduceは上記の実行可能なクエリ(method: ddl_parse/constraint_check/query_stat)とします。expected_impactは範囲で示し、信頼度タグを付けます。
誠実さ
- アプリ層の検証はリスクを軽減しますが、データベース制約の代わりにはなりません — ジョブ、管理者用スクリプト、レプリカなど複数の書き込み元はアプリを経由しません。この点を明確に述べ、アプリでの検証を同等のものとして扱わないでください。
- NULL を許容する UNIQUE の落とし穴はエンジン固有です(Postgres は 15 より前では NULL を個別の値として扱います。15 以降は
NULLS NOT DISTINCTを使用できます)。検出されたエンジン/バージョンに合わせて助言し、一般化しないでください。 - Tier-1 で件数を確認していない限り、重複や違反が存在すると断言しないでください。静的チェックの場合は
directionalです。
コメント
Markdown 対応