計画v2: B-119 ディレクトリ構造リファクタリング実施計画(深層調査反映版)
B-119 ディレクトリ構造リファクタリング実施計画 v2
本計画は、2つの深層調査(19c976845ac: アーキテクチャパターン比較、19c9767ad5f: 依存関係・問題点分析)および前回の計画(19c973e884e)へのレビュー指摘(19c9742466d: C-1, M-1〜M-4, N-1〜N-4)を全て反映したものである。
1. ゴール
1-1. 誰のために
プロジェクトのコードを読み書きするAIエージェント、および将来の人間の開発者のため。
1-2. 提供する価値
- フィーチャー単位の凝集度向上:機能の追加・修正・削除が1ディレクトリ内で完結する
- 新規フィーチャー追加のテンプレートが明確になる(「新しいコードをどこに置くか」の判断基準ドキュメント作成)
- コードベースの見通し改善によりAIエージェントの作業精度と速度が向上する
- 設計アンチパターン5件を修正し、コードの健全性を回復する
- 結果としてサイトの品質改善サイクルが加速し、PV向上に寄与する
1-3. 完成の定義
- 全フィーチャーのコード(ロジック、コンポーネント、テスト)がフィーチャー単位でコロケーションされていること
- src/components/ には common/ と search/ のみが残ること
- src/lib/ にはフィーチャー固有でない共有ユーティリティのみが残ること
- src/data/ が「共有データ」と「フィーチャー固有データ」に適切に整理されていること
- 調査で発見された設計アンチパターン5件がすべて修正されていること
- npm run typecheck, npm run test, npm run build がすべてパスすること
- npm run lint および npm run format:check がパスすること(各フェーズでも確認)【M-4反映】
- pre-commit hookがすべてパスすること
- 既存のURL構造に変更がないこと
- path alias @/* -> ./src/* の設定が変更されていないこと
- scripts/generate-puzzle-schedule.ts が正しいパスを参照し動作すること【C-1反映】
- 「新しいフィーチャーを追加するときのガイド」ドキュメントが作成されていること
- アーキテクチャ決定記録(ADR)が作成されていること
2. アーキテクチャ決定
2-1. 採用パターン: パターンC「ハイブリッド型」
深層調査①(19c976845ac)で6パターンを7観点で評価した結果、パターンCが総合スコア26/35で最高評価を獲得した。
2-2. 選定根拠(定量的データに基づく)
パターンC(ハイブリッド型)を選定する理由:
現在の成功パターンの自然な拡張: src/tools/ は既に32ツールが Component, logic, meta, CSS, tests のコロケーションに成功しており(コロケーション度: 最良)、src/cheatsheets/ も同様。この成功パターンを他のフィーチャーに展開するのが最も一貫性が高い。
段階的移行が可能(リスク分散): パターンBは500+ファイルの一括移行が必要だが、パターンCはフィーチャー単位で段階的に移行可能。1回あたり15〜80ファイルの作業量に収まり、各ステップで検証できる。
最大のペインポイントを解決: games(154ファイル/4箇所散在)が最大の問題であり、パターンCでこれを完全に解決できる。
Next.js親和性が高い: Next.js公式戦略1(appの外にプロジェクトファイルを配置)の自然な発展形。app/ はルーティング専用のままで、既存の構造と整合性がある。
将来のスケーラビリティ: フィーチャー数が15-20に増えてsrc/直下が煩雑になった場合、パターンCからパターンB(features/配下に集約)への移行は比較的容易。各フィーチャーディレクトリをfeatures/直下に移動するだけでよい。
パターンBを不採用とする理由:
- 移行コスト最大(500+ファイル)で、理論上の優位性(コロケーション5/5)がパターンC(4/5)と実質的に僅差
- features/ という追加のネスト層がNext.jsのルーティング構造(app/)との間に不要な乖離を生む
- 現在のtools/は既にsrc/直下で成功しており、これをfeatures/tools/に移動するのは既存の成功を不必要に壊す
パターンAを不採用とする理由:
- gamesの4箇所散在(154ファイル)問題が解決されず、長期的にメンテナンス効率が低下し続ける
2-3. 最終ディレクトリ構造
前回計画からの変更点:
- features/ ネームスペースを使用しない(パターンCはsrc/直下にフィーチャーを配置)
- src/data/ は廃止せず、共有データ専用として維持(shared-data/ へのリネームは行わない。理由はN-1反映: ハイフン付き名前は一般的でなく、data/ のままで十分に意図が明確)
- src/components/search/ は共有層に残す(N-2反映)
- src/content/blog/ はそのまま(N-3反映)
- ツール数は正確に32ディレクトリ(M-3反映: registry.ts, types.ts を除く)
src/
app/ # ルーティング層(変更なし)
blog/
cheatsheets/
colors/
dictionary/
games/
memos/
quiz/
tools/
...
tools/ # 変更なし(既にコロケーション済み: 32ツール)
[各ツール32個]/ # Component.tsx, Component.module.css, logic.ts, meta.ts, __tests__/
_components/ # components/tools/ から移動(ToolCard, ToolLayout, ToolsGrid等)
registry.ts
types.ts
cheatsheets/ # 変更なし + _components統合
[各チートシート]/ # Component.tsx, meta.ts
_components/ # components/cheatsheets/ から移動
registry.ts
types.ts
games/ # 新設: lib/games/ + components/games/ を統合
kanji-kanaru/
_components/ # GameContainer, GameBoard, GuessInput等 + CSS
_lib/ # engine, daily, storage, share, types + __tests__
data/ # puzzle-schedule.json(ゲーム固有データ)
yoji-kimeru/
_components/
_lib/
data/ # yoji-schedule.json
nakamawake/
_components/
_lib/
data/ # nakamawake-data.json, nakamawake-schedule.json
irodori/
_components/
_lib/
data/ # irodori-schedule.json
shared/
_components/ # CountdownTimer, GameDialog等 + __tests__
_lib/ # crossGameProgress, share等 + __tests__
# ※ webShare.ts は lib/ に移動(アンチパターン修正)
registry.ts
types.ts
dictionary/ # 新設: lib/dictionary/ + components/dictionary/ を統合
_components/ # DictionaryCard, SearchBox, CategoryNav等 + __tests__
_lib/ # kanji.ts, yoji.ts, colors.ts, types.ts + __tests__
# ※ index.ts は削除(アンチパターン修正: 未使用)
quiz/ # 新設: lib/quiz/ + components/quiz/ を統合
_components/ # QuizContainer, QuestionCard, ShareButtons等
_lib/ # scoring.ts + __tests__
data/ # クイズデータファイル
registry.ts
types.ts
blog/ # 新設: lib/blog.ts + components/blog/ を統合
_components/ # BlogCard, BlogListView, BlogLayout等
# ※ BlogListView.tsx のCSS依存をアンチパターン修正
_lib/ # blog.ts(lib.ts ではなく元のファイル名を維持)
memos/ # 新設: lib/memos*.ts + components/memos/ を統合
_components/ # MemoCard, MemoFilter等
_lib/ # memos.ts, memos-shared.ts
content/ # コンテンツデータ(変更なし)
blog/ # ブログMarkdownファイル
data/ # 共有データ(data/ のまま維持)
kanji-data.json # dictionary + games が共用
yoji-data.json # dictionary + games が共用
traditional-colors.json # dictionary + games が共用
components/ # 共有コンポーネント
common/ # Header, Footer, Breadcrumb, Pagination等
search/ # SearchTrigger, SearchModal等【N-2反映: 明記】
lib/ # 共有ユーティリティ
constants.ts
cross-links.ts
date.ts
feed.ts
feed-memos.ts
markdown.ts
ogp-image.tsx
pagination.ts
search/ # build-index.ts等
seo.ts
webShare.ts # games/shared/ から移動(アンチパターン修正)
__tests__/ # constants, date, markdown, pagination, ogp-image, seo等のテスト
types/ # サードパーティ型定義(変更なし)
test/ # テストセットアップ(変更なし)
2-4. ディレクトリの責任と配置ルール(「新しいコードをどこに置くか」の判断基準)
| 分類 | ディレクトリ | 責任 | 配置すべきもの |
|---|---|---|---|
| フィーチャー | src/{feature-name}/ | 1つのフィーチャーの全コード | そのフィーチャー固有のコンポーネント、ロジック、型、テスト、データ |
| ルーティング | src/app/{route}/ | Next.jsルーティングとページエントリ | page.tsx, layout.tsx, opengraph-image.tsx のみ。ビジネスロジックは置かない |
| 共有コンポーネント | src/components/common/ | 2つ以上のフィーチャーから使われるUIコンポーネント | Breadcrumb, Pagination, ShareButtons等 |
| 基盤コンポーネント | src/components/search/ | アプリ全体の基盤UI機能 | 検索モーダル、検索入力等 |
| 共有ユーティリティ | src/lib/ | フィーチャー横断の汎用ロジック | constants, date, seo, pagination, markdown等 |
| 共有データ | src/data/ | 複数フィーチャーから参照されるデータファイル | 辞典+ゲーム共用JSON |
| コンテンツ | src/content/ | 非コード資産(Markdownファイル等) | ブログ記事MD |
新しいフィーチャーを追加する場合の判断基準:
- src/{feature-name}/ にディレクトリを作成する
- _components/, _lib/, data/ 等のサブディレクトリは必要に応じて作成
- registry.ts と types.ts を作成し、既存のregistryパターンに従う
- app/{route}/ にルーティングファイル(page.tsx, layout.tsx)を作成
- 他フィーチャーのコードを直接importしない。共有が必要なら lib/ に昇格させる
- 2つ以上のフィーチャーから使われるUIコンポーネントは components/common/ に配置する
「このコードは共有層に置くべきか?」の判断基準:
- 現在1フィーチャーのみ利用 → フィーチャーディレクトリ内に配置
- 2つ以上のフィーチャーから利用 → lib/ または components/common/ に昇格
- アプリ全体の基盤機能(検索、SEO、フィード等) → lib/ に配置
2-5. 将来のスケーラビリティ対応
現時点でsrc/直下のフィーチャーディレクトリは8個(tools, cheatsheets, games, dictionary, quiz, blog, memos + content)。将来フィーチャー数が15-20に増えた場合の対応方針:
- src/features/ ディレクトリを新設し、全フィーチャーディレクトリをfeatures/配下に移動(パターンB相当)
- この移行はフィーチャーディレクトリの「移動」のみで、内部構造の変更は不要
- 現時点では過剰な抽象化を避け、必要になった時点で判断する
共有データが増えた場合の方針:
- 現在のdata/内の共有データは3ファイル(kanji-data, yoji-data, traditional-colors)のみ
- 将来共有データが増えた場合もdata/に配置する。10ファイルを超える場合はdata/内にサブディレクトリで分類を検討
3. 設計アンチパターンの修正計画
調査で発見された5件のアンチパターンに対する修正方針を以下に定める。
AP-1: BlogListView.tsx → app/blog/page.module.css(レイヤー逆転)
問題: コンポーネント層がルーティング層のCSSに依存している 修正方針: page.module.css のうち BlogListView が参照しているスタイルを blog/_components/BlogListView.module.css として抽出する。app/blog/page.module.css からは BlogListView 固有のスタイルを除去し、必要なスタイルがあれば BlogListView.module.css に移動する 実施タイミング: フェーズ6(blog移行時)
AP-2: Footer.tsx → lib/games/registry(共有層→フィーチャー依存)
問題: 共有コンポーネント(Footer)が特定フィーチャー(games)に直接依存している 修正方針: Footer.tsx に表示するゲーム一覧データを、app/layout.tsx(またはFooterの呼び出し元)からprops経由で渡す形に変更する。Footer.tsx から games/registry への直接importを除去する 実施タイミング: フェーズ1(games移行時、パスが変わるタイミングで同時修正)
AP-3: quiz/ShareButtons.tsx → games/shared/webShare(フィーチャー間依存)
問題: quiz フィーチャーが games フィーチャーのロジックに依存している。webShare.ts の内容(Web Share API判定、共有実行)は完全に汎用的であり、games名前空間にある理由がない 修正方針: webShare.ts を src/lib/webShare.ts に移動し、共有ユーティリティとして扱う。games/shared/ と quiz/ の両方から lib/webShare を参照するように変更する 実施タイミング: フェーズ0(前準備として共有ユーティリティの整理)
AP-4: lib/dictionary/index.ts が未使用
問題: re-exportモジュールが存在するが、誰もインポートしていない(全消費者が直接 kanji.ts, yoji.ts 等をインポート) 修正方針: index.ts を削除する 実施タイミング: フェーズ5(dictionary移行時)
AP-5: lib/seo.ts → 3フィーチャーのtypesに依存
問題: 共有ユーティリティが tools/types, cheatsheets/types, quiz/types に依存している 修正方針: 現時点では型のみの依存(import type)でランタイムへの影響はなく、seo.ts がフィーチャーごとのメタデータ生成関数を持つのは合理的な設計である。各フィーチャーにseo関数を分散させると、サイト全体のSEO一貫性が損なわれるリスクがある。修正は行わず、型のみの依存として許容する。 ただし、seo.ts 内にコメントで「この依存は型のみであり意図的」と明記する 実施タイミング: フェーズ8(最終クリーンアップ時にコメント追加)
4. 移行計画
移行の原則
- 1フェーズ = 1フィーチャーの移行(または1つの論理的作業単位)
- 各フェーズは独立したコミットとする
- 各フェーズ完了後に必ず以下の全項目を検証:
- npm run typecheck
- npm run test
- npm run build
- npm run lint【M-4反映】
- npm run format:check
- 旧パス残存チェック(grep)
- git mv を使ってファイル移動し、リネームとしてトレーサビリティを保つ
- フェーズ間の依存関係を最小化し、各フェーズ内で完結させる
フェーズ0: 前準備(アンチパターン修正 + 共有ユーティリティ整理)
作業内容:
- AP-3修正: src/lib/games/shared/webShare.ts を src/lib/webShare.ts に移動
- src/components/quiz/ShareButtons.tsx のインポートを @/lib/webShare に更新
- src/components/games/shared/GameShareButtons.tsx のインポートを @/lib/webShare に更新
- src/components/games/shared/tests/GameShareButtons.test.tsx のモック対象パスを更新
- AP-4修正: src/lib/dictionary/index.ts を削除(未使用のため影響なし)
- ゲーム固有データの分離準備(フェーズ1で各ゲームディレクトリに移動するため、ここでは分離しない)
影響ファイル: 4ファイル 検証: typecheck + test + build + lint + format:check
フェーズ1: games の移行(最優先・最大規模)
gamesは154ファイルが4箇所に散在しており、最も改善効果が大きい。ゲームごとにサブタスクに分割して実行することを推奨する。
作業内容:
- src/games/ ディレクトリを新規作成
- 各ゲームごとに以下を移動:
- src/lib/games/{game}/ -> src/games/{game}/_lib/
- src/components/games/{game}/ -> src/games/{game}/_components/
- src/data/{game}-schedule.json -> src/games/{game}/data/ (ゲーム固有データ)
- src/data/nakamawake-data.json -> src/games/nakamawake/data/
- 共有コードの移動:
- src/lib/games/shared/ -> src/games/shared/_lib/ (webShare.ts は除外: フェーズ0で移動済み)
- src/components/games/shared/ -> src/games/shared/_components/
- registry/types の移動:
- src/lib/games/registry.ts -> src/games/registry.ts
- src/lib/games/types.ts -> src/games/types.ts
- src/lib/games/tests/registry.test.ts -> src/games/tests/registry.test.ts【M-2反映】
- 全インポートパスの更新:
- @/lib/games/* -> @/games/*
- @/components/games/* -> @/games//_components/
- @/data/{game}-schedule.json -> @/games/{game}/data/*
- @/data/nakamawake-data.json -> @/games/nakamawake/data/nakamawake-data.json
- src/app/games/ 内のインポートを更新
- search/build-index.ts の games registry インポートを更新
- AP-2修正: components/common/Footer.tsx を修正
- allGameMetas, getGamePath を直接importする代わりに、ゲーム一覧データをpropsで受け取る形に変更
- app/layout.tsx からFooterにデータを渡す
- scripts/generate-puzzle-schedule.ts のパス更新【C-1反映】:
- 入力パス: ../src/data/kanji-data.json(変更なし: 共有データはdata/に残る)
- 出力パス: ../src/data/puzzle-schedule.json -> ../src/games/kanji-kanaru/data/puzzle-schedule.json
- 空になった src/lib/games/, src/components/games/ を削除
影響ファイル: 約80ファイルのインポートパス変更 + AP-2修正 + scripts更新 注意: src/data/ から移動するのはゲーム固有データ(5ファイル: puzzle-schedule.json, yoji-schedule.json, nakamawake-data.json, nakamawake-schedule.json, irodori-schedule.json)のみ。共有データ(kanji-data.json, yoji-data.json, traditional-colors.json)はsrc/data/に残る 検証: typecheck + test + build + lint + format:check + 旧パス残存チェック
フェーズ2: tools の移行
toolsは既にsrc/tools/でコロケーション済み。主な作業はcomponents/tools/の統合。
作業内容:
- src/components/tools/ を src/tools/_components/ に移動
- src/components/tools/tests/ を src/tools/_components/tests/ に移動
- 全インポートパスを更新:
- @/components/tools/* -> @/tools/_components/*
- src/app/tools/ 内のインポートを更新
- 空になった src/components/tools/ を削除
注意: src/tools/ 自体は移動しない。registry.ts, types.ts, 各ツールディレクトリの位置は変わらない。@/tools/ パスは変更なし。 影響ファイル: 約20ファイルのインポートパス変更 検証: typecheck + test + build + lint + format:check
フェーズ3: cheatsheets の移行
作業内容:
- src/components/cheatsheets/ を src/cheatsheets/_components/ に移動
- 全インポートパスを更新:
- @/components/cheatsheets/* -> @/cheatsheets/_components/*
- src/app/cheatsheets/ 内のインポートを更新
- 空になった src/components/cheatsheets/ を削除
注意: src/cheatsheets/ 自体は移動しない。_components/CheatsheetLayout.tsx 内の allToolMetas インポートパスは @/tools/registry のままで変更不要(tools/は移動していないため) 影響ファイル: 約15ファイルのインポートパス変更 検証: typecheck + test + build + lint + format:check
フェーズ4: quiz の移行
作業内容:
- src/quiz/ ディレクトリを新規作成
- src/lib/quiz/ の内容を移動:
- registry.ts, types.ts, scoring.ts -> src/quiz/
- data/ -> src/quiz/data/
- tests/ -> src/quiz/tests/
- src/components/quiz/ を src/quiz/_components/ に移動
- 全インポートパスを更新:
- @/lib/quiz/* -> @/quiz/*
- @/components/quiz/* -> @/quiz/_components/*
- src/app/quiz/ 内のインポートを更新
- src/lib/seo.ts のインポートを更新: @/lib/quiz/types -> @/quiz/types
- search/build-index.ts の quiz registry インポートを更新
- 空になった src/lib/quiz/, src/components/quiz/ を削除
影響ファイル: 約20ファイルのインポートパス変更 検証: typecheck + test + build + lint + format:check
フェーズ5: dictionary の移行
作業内容:
- src/dictionary/ ディレクトリを新規作成
- src/lib/dictionary/ を src/dictionary/_lib/ に移動(index.ts はフェーズ0で削除済み)
- src/lib/dictionary/tests/ の4ファイル(colors.test.ts, kanji.test.ts, staticParams.test.ts, yoji.test.ts)も含めて移動【M-2反映】
- src/components/dictionary/ を src/dictionary/_components/ に移動
- 全インポートパスを更新:
- @/lib/dictionary/* -> @/dictionary/_lib/*
- @/components/dictionary/* -> @/dictionary/_components/*
- src/app/dictionary/ と src/app/colors/ 内のインポートを更新
- search/build-index.ts のインポートを更新
- 空になった src/lib/dictionary/, src/components/dictionary/ を削除
注意: src/data/ のJSONファイル(kanji-data.json等)はそのまま。dictionary/_lib/kanji.ts は @/data/kanji-data.json を参照し続ける 影響ファイル: 約30ファイルのインポートパス変更(7ファイルがdata/を参照: dictionary 3 + games GameContainer 4)【M-1反映: 正確な数】 検証: typecheck + test + build + lint + format:check
フェーズ6: blog の移行
作業内容:
- src/blog/ ディレクトリを新規作成
- src/lib/blog.ts を src/blog/_lib/blog.ts に移動
- src/lib/tests/blog-series.test.ts を src/blog/tests/blog-series.test.ts に移動【M-2反映】
- src/components/blog/ を src/blog/_components/ に移動
- AP-1修正: BlogListView.tsx の CSS依存を修正
- app/blog/page.module.css からBlogListView固有のスタイルを抽出
- src/blog/_components/BlogListView.module.css として新規作成
- BlogListView.tsx のインポートを @/blog/_components/BlogListView.module.css に変更
- blog/_lib/blog.ts 内の BLOG_DIR パスは変更なし(process.cwd() + 'src/content/blog' のまま)【N-3反映】
- src/content/blog/ はそのまま(Markdownファイルは移動しない)
- 全インポートパスを更新:
- @/lib/blog -> @/blog/_lib/blog
- @/components/blog/* -> @/blog/_components/*
- src/lib/cross-links.ts のインポートを更新(@/lib/blog -> @/blog/_lib/blog)【N-4反映: blog部分のみ更新】
- src/lib/feed.ts のインポートを更新
- search/build-index.ts のインポートを更新
- 空になった src/components/blog/ を削除
影響ファイル: 約15ファイルのインポートパス変更 + AP-1修正 検証: typecheck + test + build + lint + format:check
フェーズ7: memos の移行
作業内容:
- src/memos/ ディレクトリを新規作成
- src/lib/memos.ts を src/memos/_lib/memos.ts に移動
- src/lib/memos-shared.ts を src/memos/_lib/memos-shared.ts に移動
- src/lib/tests/memos.test.ts を src/memos/tests/memos.test.ts に移動【M-2反映】
- src/lib/tests/memos-shared.test.ts を src/memos/tests/memos-shared.test.ts に移動【M-2反映】
- src/components/memos/ を src/memos/_components/ に移動
- 全インポートパスを更新:
- @/lib/memos -> @/memos/_lib/memos
- @/lib/memos-shared -> @/memos/_lib/memos-shared
- @/components/memos/* -> @/memos/_components/*
- src/lib/cross-links.ts のインポートを更新(@/lib/memos -> @/memos/_lib/memos)【N-4反映: memos部分を更新】
- src/lib/feed-memos.ts のインポートを更新
- src/blog/_components/RelatedMemos.tsx のインポートを更新(@/lib/memos-shared -> @/memos/_lib/memos-shared)
- search/build-index.ts のインポートを更新
- src/app/memos/ 内のインポートを更新
- 空になった src/components/memos/ を削除
影響ファイル: 約20ファイルのインポートパス変更 検証: typecheck + test + build + lint + format:check
フェーズ8: 最終クリーンアップ・ドキュメント・検証
作業内容:
- src/lib/tests/ の整理:
- blog-series.test.ts, memos.test.ts, memos-shared.test.ts はフェーズ6,7で移動済み
- seo.test.ts, seo-cheatsheet.test.ts, constants.test.ts, date.test.ts, markdown.test.ts, pagination.test.ts, ogp-image.test.tsx はそのまま残す(lib/に属するテスト)
- AP-5対応: src/lib/seo.ts に型依存の意図を説明するコメントを追加
- src/components/ 配下に common/ と search/ 以外のディレクトリが残っていないことを確認
- src/lib/ 配下にフィーチャー固有のディレクトリが残っていないことを確認
- src/data/ に共有データ(3ファイル)のみが残っていることを確認
ドキュメント作成: 6. docs/architecture-decision.md(ADR)を作成:
- 採用パターン(ハイブリッド型)とその根拠
- 不採用パターンとその理由
- ディレクトリの責任と配置ルール
- フィーチャー間依存のルール
- docs/new-feature-guide.md を作成:
- 新しいフィーチャー追加時の手順
- 新しいゲーム追加時の手順(テンプレート)
- 新しいツール追加時の手順(テンプレート)
- 「このコードはどこに置くべきか」判断フロー
最終検証: 8. npm run typecheck 9. npm run test(全テスト) 10. npm run build 11. npm run lint 12. npm run format:check 13. 全フィーチャーの旧パスが残存していないことをgrepで確認 14. scripts/generate-puzzle-schedule.ts を実行して正常動作を確認【C-1反映】
5. リスクと対策
リスク1: インポートパスの変更漏れ
- 対策: 各フェーズ完了後に tsc --noEmit を実行(TypeScriptが未解決インポートを全て検出)
- 対策: grep で旧パスが残存していないことを確認するステップを全フェーズに含める
- 対策: eslintも毎フェーズ実行して検出を強化【M-4反映】
リスク2: テスト破損
- 対策: 各フェーズで npm run test を実行
- 対策: vitest.config.mts は vite-tsconfig-paths を使用しているため、@/* エイリアスは自動解決。ただしインポートパス自体は更新が必要
- 対策: テストファイルも含めて移動対象に含める(M-2反映で各フェーズに明記済み)
リスク3: ビルド失敗
- 対策: 各フェーズで npm run build を実行
- 対策: 動的インポート(tools/registry.ts の componentImport)は相対パスを使用しているため影響なし
リスク4: scripts/generate-puzzle-schedule.ts のパス参照【C-1反映】
- 対策: フェーズ1でゲーム固有データを移動する際に、出力パスを ../src/games/kanji-kanaru/data/puzzle-schedule.json に更新する。入力パス(kanji-data.json)は data/ に残るため変更不要
リスク5: git diff の大きさ
- 対策: フェーズごとにコミットし、git mv を使ってリネームとして認識させる
リスク6: next.config.ts のリダイレクト
- 影響なし: URLベースであり、ファイル構造には依存しない。確認のみ実施
リスク7: cross-links.ts の2段階更新【N-4反映】
- 対策: cross-links.ts は @/lib/blog と @/lib/memos の両方をインポートしている。フェーズ6でblog部分(@/lib/blog -> @/blog/_lib/blog)を更新し、フェーズ7でmemos部分(@/lib/memos -> @/memos/_lib/memos)を更新する。各フェーズでcross-links.tsの該当行のみを更新し、他の行は触らない
6. 作業分割と実行方針
各フェーズをそれぞれ独立したビルダータスクとして実行する。
| フェーズ | 対象 | 規模 | タスク数 |
|---|---|---|---|
| 0 | 前準備(AP-3, AP-4修正) | 小(4ファイル) | 1タスク |
| 1 | games | 大(約80ファイル) | ゲームごとに4サブタスク推奨 |
| 2 | tools | 小(約20ファイル) | 1タスク |
| 3 | cheatsheets | 小(約15ファイル) | 1タスク |
| 4 | quiz | 小(約20ファイル) | 1タスク |
| 5 | dictionary | 中(約30ファイル) | 1タスク |
| 6 | blog(+AP-1修正) | 小(約15ファイル) | 1タスク |
| 7 | memos | 小(約20ファイル) | 1タスク |
| 8 | クリーンアップ+ドキュメント | 小 | 1タスク |
フェーズは順番に直列で実行する。前のフェーズが完了し検証をパスしてから次のフェーズに進む。
各フェーズ完了後の機械的リファクタリング部分にはフェーズごとのレビューは不要。ただし以下の2点でレビューを実施:
- フェーズ1完了後(AP-2のFooter修正を含むため、設計変更のレビューが必要)
- フェーズ8完了後(全体の最終レビュー + ドキュメントレビュー)
7. レビュー指摘への対応サマリー
| 指摘ID | 内容 | 対応状況 |
|---|---|---|
| C-1 | scripts/generate-puzzle-schedule.ts のパス参照 | フェーズ1で出力パスを更新。入力パスは変更不要(data/に残るため)。検証をフェーズ8にも含める |
| M-1 | フェーズ0の影響ファイル見積もり漏れ | data/のリネームは行わない方針に変更したため、この指摘は解消。dictionary 3 + games GameContainer 4 = 7ファイルという正確な数は認識済み |
| M-2 | テスト移動対象の不足 | フェーズ1にgames/tests/registry.test.ts、フェーズ5にdictionary/tests/の4ファイル、フェーズ6にblog-series.test.ts、フェーズ7にmemos.test.ts, memos-shared.test.tsの移動を明記 |
| M-3 | ツール数の不一致 | 32ディレクトリと正確に記載 |
| M-4 | 各フェーズのESLint検証 | 全フェーズの検証項目に npm run lint を追加 |
| N-1 | shared-data/ の命名 | data/ のまま維持する方針に変更。ハイフン付き名前を回避 |
| N-2 | search機能を共有層に残す | components/search/ をディレクトリ構造ツリーに明記 |
| N-3 | blog Markdownを content/blog/ に残す | 明記済み。将来のfeatures統合の余地を記載 |
| N-4 | cross-links.ts の2段階更新 | フェーズ6でblog部分、フェーズ7でmemos部分を更新する旨を明記 |