Skip to content

Instantly share code, notes, and snippets.

@hdknr
Created March 26, 2026 08:39
Show Gist options
  • Select an option

  • Save hdknr/f5ab8a75db3bb3c18b90b546c49aeb23 to your computer and use it in GitHub Desktop.

Select an option

Save hdknr/f5ab8a75db3bb3c18b90b546c49aeb23 to your computer and use it in GitHub Desktop.
Claude Code で Laravel→Django 全自動移行をやってみた(全3回)

Claude Code で Laravel→Django 全自動移行をやってみた(1/3)計画編

はじめに

業務管理システム(PHP/Laravel 6.20)を Python/Django 4.2 に移行するプロジェクトを、Claude Code の自律実行でほぼ全自動で完遂しました。

  • 移行元: Laravel 6.20 / PHP 8.0 / MySQL 5.7 / Blade テンプレート
  • 移行先: Django 4.2 LTS / Python 3.11+ / MySQL 8.0 / Django Templates
  • 所要時間: 約 5.5 時間(準備フェーズ除く)
  • 成果物: 17 モデル / 50+ テンプレート / 199 テスト / 15,000 行の Python コード

本記事は 3 部構成です。

  1. 計画編(本記事)— なぜやったか、どう計画したか
  2. 自動化基盤編 — Claude Code を自律実行させるフレームワークの設計
  3. 実行結果・教訓編 — 実際に何が起きたか、次回への教訓

プロジェクトの背景

移行対象は、ある業種特化の業務管理システムです。契約管理・マスタ管理・CSV インポート・Excel エクスポート・月次締処理・外部サービス連携(OAuth2 / REST / GraphQL)など、典型的な業務アプリの機能を一通り備えています。

Laravel 側のコードベースの規模感:

  • コントローラ: 27 個
  • Eloquent モデル: 21 個
  • DB テーブル: 21 個(レコード数: 契約 4.1 万件、顧客マスタ 4.1 万件、外注先 4,800 件)
  • 外部 API 連携: OAuth2 認証 + REST + GraphQL

「手で移行したら何人月かかるか」を考えたとき、Claude Code に全部やらせてみよう、という実験的な発想でプロジェクトが始まりました。


移行方針の決定

1. 既存 DB をそのまま使う(inspectdb 方式)

最も重要な設計判断は、既存の本番 DB ダンプをそのまま使い、Django の inspectdb でモデル雛形を自動生成する方式を採用したことです。

既存 DB ダンプ取得 → Docker MySQL にリストア → inspectdb でモデル生成
→ managed = True に変更 → migrate --fake で初回適用

これにより:

  • モデル定義の正確性が大幅に向上(カラム名・型・制約が実 DB と完全一致)
  • 既存データで動作確認が可能(テストデータを作る手間がない)
  • テーブル名の typo(例: infomations)もそのまま維持して互換性確保

当初は「Laravel のモデル定義を読んで手動でDjango モデルを書く」方針でしたが、ユーザー(自分)の「それで大丈夫か?」という問いかけで方針転換しました。ユーザーの素朴な疑問がアーキテクチャ改善に繋がった好例です。

2. 外部 API の事前動作確認

Laravel のコードに書かれている API エンドポイントと、実際に動く API が一致しているとは限りません。準備段階で実際に curl で叩いて確認したところ、いくつかの重要な差異が見つかりました:

  • GraphQL のクエリ名: コード上は customers → 実際は customer_set
  • フィールド名: branchCode → 実際は company_code
  • 認証方式: client_credentials grant → 実際は assertion grant のみ

これらの差異を事前に CLAUDE.md(Claude Code が読むプロジェクト設定ファイル)に記録したことで、全フェーズを通じて同じ間違いを繰り返さずに済みました。

3. フロントエンドは「コピー&ペースト」

Laravel 側で使っていた UI テーマ(jQuery + Bootstrap ベース)の CSS/JS をそのまま Django の static/ にコピーする方針を取りました。カスタム SASS/JS ビルドは不要 — プリビルドファイルをそのまま使います。

Django テンプレートでは {% load static %} で参照するだけ。フロントエンドのビルドパイプラインを移行する必要がないため、バックエンドのビジネスロジック移行に集中できました。


フェーズ設計

移行作業を 8 フェーズ・15 の GitHub Issue に分割しました。各 Issue に依存関係を定義し、順序通りに自動実行する設計です。

Phase 0: 初期セットアップ(Docker + Django プロジェクト)
    ↓
Phase 1: モデル定義
  ├── 1-1: マスタ系 10 モデル
  ├── 1-2: 契約系 4 モデル
  └── 1-3: 入金・会計系モデル
    ↓
Phase 2: 認証 & 外部 API 連携
    ↓
Phase 3: テンプレート & CRUD
  ├── 3-1: 共通レイアウト + 静的ファイル
  └── 3-2: マスタ管理画面(9 種 × CRUD)
    ↓
Phase 4: 契約管理
  ├── 4-1: 一覧・検索(28 フィールドフィルタ)
  ├── 4-2: 登録・編集・削除(3 ステップフォーム)
  └── 4-3: 支払更新・番号修正・入金管理
    ↓
Phase 5: データ入出力
  ├── 5-1: CSV インポート(3 種)
  └── 5-2: Excel エクスポート(4 種)
    ↓
Phase 6: 月次締処理 & ダッシュボード
    ↓
Phase 7: テスト & 品質保証
    ↓
Phase 8: 本番デプロイ準備

技術スタック対応表

項目 Laravel(移行元) Django(移行先)
言語 PHP 8.0 Python 3.11+
フレームワーク Laravel 6.20 Django 4.2 LTS
ORM Eloquent Django ORM
テンプレート Blade Django Templates
フォーム Form Request Django Forms
Excel 処理 Maatwebsite Excel openpyxl
HTTP クライアント Guzzle httpx
テスト PHPUnit pytest-django
パッケージ管理 Composer / npm uv
コンテナ PHP-FPM + Nginx Gunicorn + Nginx

CLAUDE.md — Claude Code への「設計書」

Claude Code はプロジェクトルートの CLAUDE.md を自動的に読み込み、プロジェクト固有のルールとして従います。ここに移行プロジェクト特有の情報を集約しました:

# 記載した内容の例

## DB 移行方針
- inspectdb で雛形生成、managed = True に変更
- テーブル名の typo もそのまま使用

## 設計方針
- 認証: 実際の OAuth2 フローをそのまま実装(モック不要)
- フロントエンド: 既存テーマの CSS/JS をそのまま使用
- 外部 API: ハイブリッド構成(DB キャッシュ + API クライアント)

## GraphQL クエリ名の注意
- 顧客: customer_set(Laravel コードの customers は誤り)
- フィールド: company_code(branch_code は存在しない)

## 禁止事項
- git branch / checkout / switch を実行しない
- git push を実行しない
- gh pr create / merge を実行しない

特に重要だったのは 「やってはいけないこと」の明示 です。Claude Code は指示がなければ自律判断しますが、禁止事項がないと予期しない操作(ブランチ切替、main への直接 push 等)を行うことがあります。これは後述する「ブランチ分岐問題」の原因にもなりました。


品質保証の設計

自律実行では人間のコードレビューが介在しないため、品質保証の仕組みを多層的に設計しました。

1. Pre-commit Hook

# コミット前に自動実行
uv run ruff format <staged files>
uv run ruff check --fix <staged files>

2. PostToolUse Hook(Claude Code 固有)

Claude Code がファイルを編集するたびに ruff check を自動実行。構文エラーやスタイル違反を即座にフィードバックします。

3. GitHub Actions CI

push/PR → ruff format + ruff check → Django check → pytest

4. verify-phase.sh

各フェーズ完了後に実行する検証スクリプト:

  • ファイル存在チェック
  • lint / format チェック
  • Django システムチェック
  • マイグレーション整合性チェック
  • テスト実行

5. code-reviewer サブエージェント

Claude Code 内部で別の Claude インスタンスをコードレビュアーとして起動し、セキュリティ問題やロジックエラーを検出します。実際に GraphQL インジェクション、XSS、URL エンコード漏れなどを検出・修正できました。


次回予告

計画編では「何を、なぜ、どう設計したか」を紹介しました。

次の自動化基盤編では、この計画を実際に自律実行するためのフレームワーク — run-issue.sh の設計と、Claude Code をどう制御するかを解説します。

Claude Code で Laravel→Django 全自動移行をやってみた(2/3)自動化基盤編

前回の計画編では、移行の方針とフェーズ設計を紹介しました。本記事では、計画を実際に自律実行するためのフレームワーク設計を解説します。


全体アーキテクチャ

自律移行の仕組みは、大きく 3 つのレイヤーで構成されています。

┌─────────────────────────────────────────────────┐
│  オーケストレーション層: run-issue.sh             │
│  - Issue 読み込み → ブランチ作成 → Claude 起動    │
│  - リトライ → Push → PR 作成 → マージ → Issue 閉じ │
└──────────────────┬──────────────────────────────┘
                   ↓
┌─────────────────────────────────────────────────┐
│  実行層: Claude Code (claude -p)                 │
│  - ソースコード調査 → 設計 → 実装 → テスト        │
│  - コミット(push はしない)                      │
│  - サブエージェント: explorer / architect / reviewer│
└──────────────────┬──────────────────────────────┘
                   ↓
┌─────────────────────────────────────────────────┐
│  品質保証層: Hooks + CI + verify-phase.sh        │
│  - Pre-commit: ruff format + check              │
│  - PostToolUse: 編集時の即座リント               │
│  - CI: lint → Django check → pytest             │
│  - Phase 検証: ファイル存在 + 機能チェック        │
└─────────────────────────────────────────────────┘

責務分離の原則

最も重要な設計原則は、ワークフロー制御と実装作業の責務分離です。

責務 担当 理由
ブランチ作成・切替 スクリプト 確定的に実行する必要がある
git push スクリプト タイミングを制御する必要がある
PR 作成・マージ スクリプト ワークフローの一部
Issue クローズ スクリプト 完了判定はスクリプトが行う
コード実装 Claude Code 創造的判断が必要
テスト作成 Claude Code 実装と一体
コミット Claude Code こまめにコミットさせる
コードレビュー Claude Code(サブエージェント) 品質チェック

この分離が不十分だったことが後述の「ブランチ分岐問題」の根本原因でした。


run-issue.sh の設計

約 800 行の Bash スクリプトで、Issue 単位の自律実行を制御します。

実行フロー

./scripts/run-issue.sh <issue_number>
1. GitHub Issue を読み込み(gh issue view)
2. 依存 Issue の完了チェック
3. feature ブランチを作成(main から分岐)
4. Claude Code を起動(claude -p <prompt>)
5. 完了判定(コミット有無 + テスト結果)
6. 失敗時: 最大 3 回リトライ(10 秒クールダウン)
7. 成功時: push → PR 作成 → マージ → Issue クローズ
8. 実行ログを execution.md に追記

バッチ実行

./scripts/run-issue.sh all    # 全 Issue を順次実行
./scripts/run-issue.sh resume # 中断した Issue から再開

all モードでは、Issue の依存関係を解決しながら順次実行します。前の Issue が失敗したら停止し、手動介入を待ちます。

リトライ機構

Claude Code のセッションは非決定的です。同じプロンプトでも異なる結果になり得ます。リトライ時には前回の失敗情報をコンテキストとして渡します:

# リトライ時のプロンプト(概念)
"前回の実行が失敗しました。
git status, git diff, git log を確認し、
前回の作業状態を把握してから再開してください。"

実際に 15 Issue 中 8 Issue がリトライを経験しましたが、全て 2〜3 回目で成功しています。


Claude Code に渡すプロンプトの設計

run-issue.sh が Claude Code を起動する際のプロンプトは約 360 行で、以下のステップで構成されています。

10 ステップの作業指示

Step 1: Issue を読む(gh issue view で全文取得)
Step 2: ソースコード調査(feature-dev:code-explorer サブエージェント)
Step 3: 設計(feature-dev:code-architect サブエージェント、複雑な場合)
Step 4: 実装(Django のベストプラクティスに従う)
Step 5: テスト作成(pytest-django)
Step 6: 品質チェック(ruff format + check + Django check)
Step 7: コードレビュー(feature-dev:code-reviewer サブエージェント)
Step 8: 指摘事項の修正
Step 9: verify-phase.sh の実行
Step 10: execution.md への記録

サブエージェントの活用

Claude Code には「サブエージェント」機能があり、メインの Claude とは別のコンテキストで専門的なタスクを実行できます。本プロジェクトでは 3 種類を活用しました:

code-explorer: Laravel のソースコードを深く調査し、移植すべきビジネスロジックを特定

「Laravel の ContractController を調査し、
 全メソッドのビジネスロジックを整理してください」

code-architect: 複雑な機能の設計方針を決定

「28 フィールドの検索フォームを Django で実装する
 最適なアーキテクチャを設計してください」

code-reviewer: 実装済みコードのセキュリティ・品質レビュー

「変更されたファイルをレビューし、
 セキュリティ問題・ロジックエラーを報告してください」

権限管理

Claude Code の権限は .claude/settings.json で制御します。自律実行に必要な操作のみをホワイトリストで許可しました。

{
  "permissions": {
    "allow": [
      "Bash(git *)",
      "Bash(docker compose *)",
      "Bash(uv run *)",
      "Bash(gh issue view *)",
      "Read", "Edit", "Write", "Glob", "Grep"
    ]
  }
}

ただし、CLAUDE.md の禁止事項で git push / git branch / gh pr create を禁止しているため、実質的には「読み取り + 実装 + コミット」に限定されます。


品質保証の実装

Pre-commit Hook

#!/bin/bash
# .githooks/pre-commit
STAGED_PY=$(git diff --cached --name-only --diff-filter=d -- '*.py')
[ -z "$STAGED_PY" ] && exit 0

uv run ruff format $STAGED_PY
uv run ruff check --fix $STAGED_PY
git add $STAGED_PY

Claude Code がコミットするたびに自動フォーマット + lint 修正が走ります。

PostToolUse Hook

Claude Code 固有の機能で、Edit や Write ツールが実行されるたびにフック関数が呼ばれます。

#!/bin/bash
# .claude/hooks/post-edit-lint.sh
# Claude が Python ファイルを編集するたびに ruff check を実行
uv run ruff check "$FILE_PATH"

これにより、コミット前の段階でスタイル違反を検出・フィードバックできます。

verify-phase.sh

各フェーズ完了後の検証チェックリスト:

#!/bin/bash
# scripts/verify-phase.sh <issue_number>

echo "=== Phase 検証開始 ==="

# 共通チェック
check "git 状態がクリーン" git diff --quiet HEAD
check "ruff format" uv run ruff format --check .
check "ruff check" uv run ruff check .
check "Django check" uv run python manage.py check
check "マイグレーション整合性" uv run python manage.py makemigrations --check --dry-run

# Phase 固有チェック(ファイル存在確認など)
case $ISSUE in
  2) check "masters/models.py が存在" test -f masters/models.py ;;
  5) check "accounts/middleware.py が存在" test -f accounts/middleware.py ;;
  # ...
esac

# テスト実行
check "pytest 全パス" uv run pytest

GitHub Actions CI

# .github/workflows/ci.yml
jobs:
  lint:
    steps:
      - run: uv run ruff format --check .
      - run: uv run ruff check .

  django-check:
    needs: lint
    services:
      mysql: { image: mysql:8.0 }
    steps:
      - run: uv run python manage.py check
      - run: uv run python manage.py makemigrations --check --dry-run

  test:
    needs: django-check
    steps:
      - run: uv run pytest

Docker 環境

開発環境は docker-compose で完結させ、Claude Code が Docker 内で動作確認できるようにしました。

# docker-compose.yml
services:
  db:
    image: mysql:8.0
    volumes:
      - ./docker/mysql/init/001-dump.sql:/docker-entrypoint-initdb.d/001-dump.sql
    # ↑ 既存 DB ダンプを初回起動時に自動リストア

  app:
    build: .
    depends_on:
      db: { condition: service_healthy }
    volumes:
      - .:/app  # ライブリロード用

  nginx:
    image: nginx:alpine
    ports: ["8080:80"]

41MB の本番 DB ダンプを docker/mysql/init/ に配置し、docker-compose up だけで既存データ入りの環境が立ち上がります。Claude Code は docker compose exec app pytest でテスト実行、docker compose exec app python manage.py check で Django チェックを行えます。


実行ログの自動記録

execution.md にタイムスタンプ付きの実行ログを自動記録します。

### Issue #2: マスタ系モデル定義
- 開始: 2026-03-26 12:18:50
- リトライ 2: 2026-03-26 12:31:22
- 完了: 2026-03-26 12:33:21
- 所要時間: 14分32秒
- 試行回数: 2
- 結果: 成功

#### 作業内容
- inspectdb で全テーブルのモデル雛形を自動生成
- マスタ系 10 モデルを分類・整理
- ForeignKey リレーション設定
- Django Admin に登録
...

「作業内容」と「成果物」のセクションは Claude Code 自身が記述します。スクリプトはタイムスタンプと結果のみを書き込みます。


設計で重視したこと

1. 冪等性

リトライ時に副作用が蓄積しないよう設計。ブランチが既に存在すれば再利用、コミットが既にあれば追加のみ。

2. 障害の局所化

1 つの Issue が失敗しても他に影響しない。各 Issue は独立したブランチで作業し、main にマージされるまで他の Issue に影響しません。

3. 可観測性

実行ログ・git log・GitHub Issue/PR のコメントで、何が起きたかを事後に追跡可能。

4. 中断耐性

「こまめなコミット」を指示することで、Claude Code のセッションが中断しても未コミットの変更を最小化。実際に中断からの復旧に成功したケースがありました。


次回予告

自動化基盤編では「どう動かすか」の設計を解説しました。

次の実行結果・教訓編では、実際に 15 Issue を自律実行した結果 — 成功パターン、発生した問題(ブランチ分岐問題)、そして次回のプロジェクトに活かすべき教訓を紹介します。

Claude Code で Laravel→Django 全自動移行をやってみた(3/3)実行結果・教訓編

計画編で方針を、自動化基盤編でフレームワークを紹介しました。最終回では、実際に 15 Issue を自律実行した結果と、得られた教訓を共有します。


実行結果サマリー

タイムライン

12:06 ── Phase 0: 初期セットアップ ────── 12分 (リトライ1回)
12:18 ── Phase 1-1: マスタモデル ──────── 14分 (リトライ1回)
12:33 ── Phase 1-2: 契約モデル ──────── 12分
12:45 ── Phase 1-3: 入金・会計モデル ──── 9分
12:57 ── Phase 2: 認証 & API ────────── 12分 (リトライ1回)
13:09 ── Phase 3-1: テンプレート ──────── 16分 (リトライ2回)
13:25 ── Phase 3-2: マスタ CRUD ────── 21分
13:46 ── Phase 4-1: 契約検索 ──────── 12分
13:58 ── Phase 4-2: 契約 CRUD ──────── 16分
14:14 ── Phase 4-3: 支払・入金 ──────── 21分 (リトライ1回)
14:35 ── Phase 5-1: CSV インポート ──── 24分 (リトライ1回)
14:59 ── Phase 5-2: Excel エクスポート ── 24分 (リトライ1回)
15:00 ── Phase 6: 月次締処理 ──────── 10分
15:34 ── Phase 7: テスト ──────────── 20分 (リトライ2回)
15:54 ── Phase 8: デプロイ準備 ──────── 8分
                            合計: 約 5.5 時間

数値で見る結果

項目 数値
完了 Issue 15 / 15
総コミット 84
うち修正コミット (fix:) 16 (19%)
リトライ発生 Issue 8 / 15 (53%)
最大リトライ回数 2 回
Python コード行数 約 15,000 行
テンプレート 50+ ファイル
テスト数 199
テスト通過率 100%
1 Issue あたり平均時間 15〜25 分

うまくいったこと

1. inspectdb による正確なモデル定義

既存 DB ダンプから inspectdb でモデル雛形を生成し、それを整理する方式は非常に効果的でした。カラム名・型・制約が実 DB と完全一致するため、「モデル定義を書いたが DB と合わない」問題が発生しませんでした。

2. 外部 API の差異を事前に発見・記録

準備段階で API エンドポイントを実際に叩き、Laravel コードとの差異を CLAUDE.md に記録しました。GraphQL のクエリ名やフィールド名の違いを事前に把握していたことで、Phase 2(API 連携)がスムーズに進みました。

教訓: コードに書いてあることと実際の動作が違う情報は特に価値が高い。

3. code-reviewer サブエージェントの効果

Claude Code 内で別の Claude インスタンスをレビュアーとして起動し、以下のセキュリティ問題を検出・修正できました:

  • GraphQL インジェクション(ユーザー入力をクエリ文字列に直接埋め込み)
  • XSS(テンプレートでのエスケープ漏れ)
  • URL エンコード漏れ
  • 型不一致(Django フォームのバリデーション漏れ)

自分自身(Claude)がレビューする限界はありますが、ないよりは確実に品質が上がりました。

4. こまめなコミットによる中断耐性

「大きな作業の途中でもこまめにコミットする」という指示が功を奏しました。Phase 3-1 でセッションが中断した際、直前のコミットまでの作業が保存されており、リトライ時にスムーズに復旧できました。

5. 品質ツールチェーンの連携

Pre-commit Hook → PostToolUse Hook → CI の 3 層で品質を担保した結果、最終的なコードベースは ruff lint / Django check / pytest 全パスの状態で納品できました。


最大の問題: ブランチ分岐

何が起きたか

Phase 4-2(契約 CRUD)の完了後、2 つのブランチが独立して進行しました。

main ─── Phase 0〜4-2 ──┬── feature/phase-4-3 ── Phase 4-3 → 5-1 → 5-2
                         │
                         └── feature/phase-7 ──── Phase 6 → 7 → 8

結果:

  • feature/phase-7 に Phase 4-3〜5-2 の機能が含まれていない
  • TES 支払更新、CSV インポート、Excel エクスポートが欠落
  • 3 件の PR が Open のまま main にマージされていない

なぜ起きたか

表面的には「PR がマージされないまま次の Phase が別ブランチで始まった」ですが、根本原因を調査した結果、スクリプトにブランチ管理のロジックが存在しなかったことが判明しました。

具体的な問題:

  1. ブランチ作成がスクリプトにない: Claude Code の自律判断に委ねていた
  2. PR マージがスクリプトにない: 完了処理は gh issue close のみ
  3. push 先が固定: origin main に直接 push しようとしていた
  4. ブランチの連続性が未保証: 前の Issue のブランチの上にいる保証がない

どう修復したか

  1. feature/phase-4-3(4-3〜5-2 の成果)を feature/phase-7(6〜8 の成果)にマージ
  2. コンフリクト解消(2 ファイル: URL 設定と実行ログ)
  3. 検証: ruff / Django check / pytest 199 テスト全パス
  4. main にマージ & push

コンフリクトは 2 ファイルだけで、統合自体はスムーズでした。


教訓: 次回やるべきこと

1. ワークフロー制御は Claude に任せない

最重要の教訓。ブランチ作成・push・PR・マージなどの「ワークフロー制御」は、スクリプト側で確定的に実行すべきです。Claude Code には「実装とテスト」に集中させます。

❌ Claude にブランチ切替を任せる
   → セッションごとに異なる判断をする
   → ブランチ分岐・コード欠落のリスク

✅ スクリプトがブランチを作成・管理
   → 確定的な動作
   → Issue 間の状態遷移を保証

2. 禁止事項を明示する

CLAUDE.md には「やること」だけでなく「やってはいけないこと」を書くべきです。

## 禁止事項
- git branch / checkout / switch を実行しない
- git push を実行しない
- gh pr create / merge を実行しない
- 他の Issue のファイルを変更しない

Claude Code は「指示がない = 自律判断してよい」と解釈します。禁止されていない操作は実行される可能性があります。

3. テストは各フェーズで書く

テストを最後(Phase 7)にまとめて書いた結果、ブランチ分岐で欠落した機能のテストが不十分だった可能性があります。

❌ Phase 1〜6: 実装のみ → Phase 7: テスト一括作成
✅ 各 Phase: 実装 + テスト をセットで作成

4. 依存関係をスクリプトで強制する

Issue の依存関係は計画ドキュメントに表として書いただけで、スクリプトが検証していませんでした。

# 次の Issue に進む前に
check_dependencies() {
  # 依存 Issue が main にマージ済みであることを確認
  for dep in $(get_dependencies $ISSUE); do
    if ! is_merged_to_main $dep; then
      echo "依存 Issue #$dep が未マージです"
      exit 1
    fi
  done
}

5. ドライランを実施する

15 Issue の全自動実行を開始する前に、最初の 1〜2 Issue でドライランすべきでした。品質ツール(ruff、CI、verify-phase.sh)の検証には時間をかけましたが、ワークフロー自体の検証は行いませんでした。

品質ツールは「実装の品質」を保証しますが、「ワークフローの正しさ」は保証しません。

6. プロンプトと CLAUDE.md の重複を排除する

CLAUDE.md の「作業フロー」とプロンプトの「作業手順」が重複し、内容が微妙に異なっていました。Claude Code は両方を読むため、どちらに従うか不安定になります。

CLAUDE.md: プロジェクト固有の技術情報(DB 方針、設計方針、API 差異)
プロンプト: 作業手順・ステップ

を明確に分離すべきです。

7. 実行中のセルフチェック

--max-turns 80 で長い作業を許容していましたが、方向を間違えたまま走り続けるリスクがあります。

「20ターンごとに git status を確認し、
 正しいブランチにいること・
 未コミットの変更が溜まりすぎていないことを検証する」

のようなセルフチェックポイントを設けるべきでした。

8. ファイルサイズのガイドライン

contracts/views.py が 1,546 行、exports/views.py が 1,023 行に膨張しました。Claude Code は「動くコード」を書くのは得意ですが、適切なファイル分割の判断は弱い傾向があります。

# CLAUDE.md に追加すべきルール
- 1 ファイル 500 行を超える場合は分割を検討
- views.py → views/ パッケージ化(機能ごとにファイル分割)

自己レビューの限界

84 コミット中 16 件が修正系(fix:)で、ほとんどが code-reviewer サブエージェントの指摘対応でした。レビュー自体は機能していましたが、根本的な限界があります:

  • 同じモデルの盲点は検出できない: 書く Claude もレビューする Claude も同じ傾向を持つ
  • ワークフローの問題はコードレビューで検出されない: ブランチ分岐問題はコードの品質とは無関係
  • 「動いているが設計が悪い」を指摘しにくい: 1,500 行の views.py は動くが保守性が低い

対策: コードレビューとは別に、ワークフローの正しさを検証する仕組み(ブランチ状態チェック、依存 Issue のマージ確認)が必要。


成功パターンのまとめ

次回の同様なプロジェクトで再利用すべきパターン:

パターン 効果
既存 DB ダンプ + inspectdb モデル定義の正確性が大幅向上
外部 API の事前動作確認 実装中の手戻りを防止
CLAUDE.md への差異記録 全 Phase で同じ間違いを防止
code-reviewer サブエージェント セキュリティ問題を複数検出
こまめなコミット指示 中断からの復旧が可能
Pre-commit + PostToolUse Hook コード品質の自動担保
verify-phase.sh Phase 完了の客観的確認

改善すべき点のまとめ

問題 改善方針
ブランチ管理が Claude 任せ スクリプトで確定的に制御
禁止事項が未定義 CLAUDE.md に明示
テストが最後に一括作成 各 Phase でセットで作成
依存関係の検証なし スクリプトでゲートチェック
ワークフローのドライランなし 最初の 1-2 Issue で検証
プロンプトと CLAUDE.md の重複 責務を分離
実行中のセルフチェックなし チェックポイントを設定
ファイルサイズの制限なし 500 行上限のガイドライン
実行の可観測性が不足 通知・タイムアウト検知

総括

Claude Code による全自動移行は「実用的」か?

Yes、ただし条件付き

5.5 時間で 15,000 行の Django コード + 199 テスト + 50 テンプレートを生成し、ruff / Django check / pytest 全パスの状態で納品できたのは、人間が手作業で行う場合と比較して圧倒的に高速です。

ただし:

  • ワークフロー制御は人間(またはスクリプト)が握るべき — Claude に任せるとブランチ分岐のような非決定的な問題が発生する
  • 事前の設計・計画は人間が行うべき — フェーズ分割、依存関係、技術方針は Claude に決めさせるより人間が決めた方が確実
  • 品質保証は多層的に設計すべき — Claude の自己レビューだけでは不十分、自動テスト + CI + Hook の組み合わせが必要

Claude Code の適性

得意 不得意
コード実装(量産力が高い) ワークフロー制御(非決定的)
テスト作成 ファイル分割の判断
セキュリティレビュー アーキテクチャの長期的判断
ドキュメント生成 実行中の自己モニタリング
エラー修正・リトライ セッション間の状態引き継ぎ

最後に

本プロジェクトの最大の学びは、「Claude Code に何を任せ、何を任せないか」の境界設計が成否を分けるということです。

実装力は十分。品質も(多層的な仕組みがあれば)担保できる。しかし、ワークフローの制御 — ブランチ管理、依存関係の検証、状態の引き継ぎ — は確定的なスクリプトに任せるべきです。

Claude Code は優秀な「実装者」ですが、「プロジェクトマネージャー」ではありません。この区別を意識すれば、フレームワーク移行のような大規模タスクも自律実行で回せる — それが本プロジェクトの結論です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment