はじめに
既に完成しているアプリケーションにAIを用いて追加開発や改修を行う際、影響範囲を十分に考慮しないまま修正を加えてしまい、最終的に手作業での修正が必要になるケースが少なくありません。今回は、そうした課題を改善するための取り組みです。
具体的には、Serena MCPを活用してコードの依存関係や影響範囲を正確に把握し、SDD(仕様駆動開発)の手法と組み合わせることで、よりAIに適した開発プロセスを実現できるかを検証しました。
その結果、サンプルプロジェクトの規模こそ小さいものの、影響範囲を意識した安全で安定した開発が可能であることを確認できました。
例えば、Buttonコンポーネントがどういうふうに使われているかを調べたい時、人間であればIDEの参照機能などを使って調べることになると思います。
対してAIに、
Buttonコンポーネントの使用例を教えて。
と聞いた時、どのような動きをするでしょうか。
Claude Codeの場合、会話ログは~/.claude/projects/<project>/<session-id>.jsonlに格納されています。これを確認すると grep のようなリテラル文字列の検索を行ったり、cat のようなものでファイルの中身を見ていることがわかると思います。
(参考:https://github.com/anthropics/claude-code/issues/2168)
今回は指示が明確なため、Agentは簡単に回答を用意してくれるでしょう。
しかし、これがプロジェクト参画直後で、プロジェクト固有の専門用語や難しい技術的用語を使って質問した場合、AIが理解に時間を要したり、よくわからない回答になったりするのは、想像に難くありません。
Serena MCPとは
そこで登場するのが Serena MCP です。
Serena はLSP(Language Server Protocol)を利用して、コードをセマンティックに解析するための機能(Tools)をAIエージェントに提供するサーバーです。
(参考:https://github.com/oraios/serena#list-of-tools)
LSPは、もともとIDEが高機能なコード補完や定義ジャンプなどを実現するために使われているプロトコルです。Serena MCPは、このLSPの力をAIエージェントに与えることで、AIは単なるテキスト検索ではなく、「この関数の定義元はどこか」「この変数はどこで参照されているか」といった、構造的なコード解析が可能で、AIが人間と同じようにコードの「意味」を理解できるようにします。
これはつまり、「AIが以下の能力を獲得する手助けになるのでは?」と考えたのが、今回Serena MCPを使った理由です。
- 依存関係の把握:ある関数がどこで使われているかを瞬時に調査
- アーキテクチャの理解:コンポーネント間の関係性を構造的に把握
- 影響範囲の特定:変更時の影響を受ける箇所を正確に予測
- コードパターンの発見:既存の実装パターンを学習し、一貫性のあるコードを提案
導入方法
Serena MCPの導入
想定環境
- macOS
- Cursor
プロジェクトのルートディレクトリに以下を作成するとmcpサーバを有効化するか聞かれるので許可しましょう。
{
"mcpServers": {
"serena": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/oraios/serena",
"serena-mcp-server",
"--context",
"ide-assistant"
]
}
}
}
これだけです!
Cursor Rules
Cursor Rulesはドキュメントによると、
再利用可能でスコープ化された指示で、Agent モデルの動作を制御する。
とされています。要は、AIに「このプロジェクトではこういう風に動いてね」と事前に伝えておく仕組みです。.cursor/rulesディレクトリに配置することで利用できます。
複数のルールを使い分けることで用途ごとの命令を作ることができますが、今回の例で紹介するのは与えられたタスクに対して、どのように取り組めば良いのかの調査と実装手順を作ってもらうためのルール作成です。
今回は、要件定義から実装まで一貫した流れで開発を進めるために、以下の記事を参考にspec.mdcを作成します。
> Cursorで実践するスペック駆動開発:Kiro流フローを完全再現
---
alwaysApply: false
---
# Serena仕様駆動開発ワークフロー
このワークフローは、Serena MCPの機能を最大限活用した仕様駆動開発を実現します。なお、猫になったつもりでお願いします。
## Serenaツールの活用方針
Serenaには強力なコード分析・編集ツールが用意されています:
- **調査・分析ツール**:コードベースの理解、シンボル検索、依存関係の確認
- **編集ツール**:シンボル単位での安全なコード編集、リネーム
- **メモリーツール**:仕様書の永続的な保存と読み込み
### フェーズごとのツール使用方針
- **要件定義・設計・実装計画**:調査・分析ツール + メモリーツール
- **実装**:調査・分析ツール + 編集ツール
## 実行ルール
### ファイル操作
- 新規タスク開始時:既存の仕様ファイルの**内容を全て削除して白紙から書き直す**
- ファイル編集前に必ず現在の内容を確認する
- 各フェーズの成果物は`mcp_serena_write_memory`ツールを使用して`.serena/memories/`配下に保存する
- 仕様書ファイル名:`spec_{プロジェクト名}_{フェーズ名}.md`
### Serenaツールの活用
- **コードベース分析(必須)**:
- `mcp_serena_list_dir`でディレクトリ構造を把握
- `mcp_serena_get_symbols_overview`でファイル概要を確認(**read_fileより優先**)
- `mcp_serena_find_symbol`でシンボルを検索
- **依存関係調査**:`mcp_serena_find_referencing_symbols`で影響範囲を確認
- **パターン検索**:`mcp_serena_search_for_pattern`で類似実装を探す
- **プロジェクト理解**:`.serena/memories/`内の既存メモリーを参照
- **重要**:read_fileは最小限に留め、Serenaツールで体系的に調査すること
### フェーズ管理
- 各段階開始時:前段階のメモリーファイルを`mcp_serena_read_memory`で読み込んでから作業を開始
- 各段階の最後に、期待通りの結果になっているか確認する
- `spec_{プロジェクト名}_requirements.md`メモリーが存在しない場合は必ず要件定義フェーズから始める
- **各フェーズ完了後、必ずユーザーの承認を得てから次のフェーズに進む**
### 実行方針
- 段階的に進める:一度に全てを決定せず、フェーズごとに確実に進めること
- 複数のタスクを同時並行で進めないこと
- 不明点がある場合は、推測せず必ずユーザーに確認すること
- ユーザからの指示に無い機能を勝手に追加しないこと
- 各フェーズで作成した文書は、開発者が実装時に参照できる形式にすること
---
## フェーズ1:要件定義
### 前提作業
1. **既存メモリーの確認**
- `mcp_serena_list_memories`で既存の仕様書を確認
- 関連する既存メモリー(`project_overview.md`など)があれば`mcp_serena_read_memory`で読み込む
2. **コードベースの理解(Serenaツールを必ず使用)**
- `mcp_serena_list_dir`でプロジェクト全体の構造を確認
- `mcp_serena_get_symbols_overview`で関連する主要ファイルの概要を把握(**read_fileより優先**)
- `mcp_serena_find_symbol`で関連するクラス・関数・コンポーネントを検索
- `mcp_serena_search_for_pattern`で類似実装や既存パターンを探す
- **read_fileは最小限に留め、Serenaツールで体系的に調査すること**
### 目的
ユーザからの指示に対して **「何を作るのか」「何を達成したいのか」を明確に定める**
### 実施内容
1. **目的の明確化**
- このプロジェクト/機能で達成したいこと
- 解決したい課題や問題
2. **現状分析**
- 現在のシステムや状況(Serenaツールで既存コードを調査)
- 既存の制約や前提条件
- 利用可能な技術スタック
3. **機能要件の定義**
- 必須機能(MUST)
- 推奨機能(SHOULD)
- 可能であれば実装したい機能(COULD)
- 明確に対象外とする機能(WON'T)
4. **非機能要件の定義**
- パフォーマンス要件
- セキュリティ要件
- 保守性・拡張性の要件
- ユーザビリティ要件
5. **制約条件の整理**
- 技術的制約
- リソース制約
- スケジュール制約
### 成果物の保存
`mcp_serena_write_memory`ツールを使用して以下の形式で保存:
- **memory_name**: `spec_{プロジェクト名}_requirements`
- **content**: 上記の実施内容を構造化して文書化したMarkdown
### 完了確認
**「要件定義フェーズが完了しました。設計フェーズに進んでよろしいですか?」**とユーザーに確認し、承認を得てから次へ進む
---
## フェーズ2:設計
### 前提条件
- **必ず`mcp_serena_read_memory`で`spec_{プロジェクト名}_requirements.md`を読み込んでから開始すること**
### 前提作業
1. **既存コードの調査**
- `mcp_serena_find_symbol`で関連するクラスや関数を検索
- `mcp_serena_get_symbols_overview`で既存ファイルの構造を理解
- `mcp_serena_search_for_pattern`で類似実装パターンを探す
2. **依存関係の確認**
- `mcp_serena_find_referencing_symbols`で影響範囲を確認
### 目的
要件定義で決定した内容をもとに **「どのように作るか」「内部でどのように処理するか」を設計する**
### 実施内容
1. **アーキテクチャ設計**
- システム全体の構造
- 主要なコンポーネント/モジュールの構成
- コンポーネント間の関係性と責務
- **既存コードとの整合性を考慮**(Serenaツールで調査した結果を反映)
2. **データ設計**
- データモデルの定義
- データの流れ
- データの永続化方法
3. **インターフェース設計**
- API設計(エンドポイント、パラメータ、レスポンス)
- コンポーネント間のインターフェース
- ユーザーインターフェース(必要に応じて)
- **既存のインターフェースとの互換性**
4. **処理フロー設計**
- 主要な処理の流れ
- エラーハンドリング
- 状態管理
5. **技術選定**
- 使用するライブラリやフレームワーク
- 選定理由と代替案の検討
- **既存の技術スタックとの整合性**
6. **実装詳細の設計**
- 新規作成するファイル・クラス・関数のリスト
- 修正が必要な既存ファイルのリスト
- 各関数/メソッドのシグネチャと役割
- 疑似コードやフローチャート
### 詳細化レベル
- **プログラマーが実際にコーディングできるレベルまで詳細化すること**
- 主要な関数/メソッドのシグネチャや役割を明記すること
- 疑似コードやフローチャートを活用すること
- **既存コードのどの部分を活用/修正するかを明記すること**
### 成果物の保存
`mcp_serena_write_memory`ツールを使用して以下の形式で保存:
- **memory_name**: `spec_{プロジェクト名}_design`
- **content**: 上記の実施内容を構造化して文書化したMarkdown
### 完了確認
**「設計フェーズが完了しました。実装計画フェーズに進んでよろしいですか?」**とユーザーに確認し、承認を得てから次へ進む
---
## フェーズ3:実装計画
### 前提条件
- **必ず`mcp_serena_read_memory`で`spec_{プロジェクト名}_design.md`を読み込んでから開始すること**
### 目的
設計内容を実装可能な単位に分解し、優先順位をつけて実装の順序を決定する
### 実施内容
1. **タスク分解**
- 設計内容を独立して実装可能な単位に分解
- 各タスクは1〜3日程度で完了できる粒度を目安とする
- 各タスクに一意の識別子を付与(例:TASK-001)
2. **依存関係の整理**
- タスク間の依存関係を明確化
- 並行して実装可能なタスクの識別
- 前提となるタスクの明記
3. **優先順位の設定**
- 各タスクの優先度を設定(High/Medium/Low)
- 優先度設定の理由を明記
- MVPとして必要な最小機能セットの特定
4. **実装順序の提案**
- 依存関係と優先度を考慮した実装順序
- 段階的にリリース可能なマイルストーンの設定
5. **各タスクの詳細定義**
- タスク名と識別子
- 実装内容の説明
- 完了条件(Definition of Done)
- 必要なファイルの作成・修正リスト
- **使用するSerenaツール**(`mcp_serena_replace_symbol_body`、`mcp_serena_insert_after_symbol`など)
- 見積もり工数(目安)
- 依存タスク
- 注意点やリスク
### 成果物の保存
`mcp_serena_write_memory`ツールを使用して以下の形式で保存:
- **memory_name**: `spec_{プロジェクト名}_implementation_plan`
- **content**: 上記の実施内容を構造化して文書化したMarkdown
- タスクリストは表形式や構造化された形式で見やすく整理する
### 完了確認
**「実装計画フェーズが完了しました。実装を進めてよろしいですか?」**とユーザーに確認し、承認を得てから次へ進む
---
## フェーズ4:実装
### 前提条件
- **必ず`mcp_serena_read_memory`で`spec_{プロジェクト名}_implementation_plan.md`を読み込んでから開始すること**
- 実装計画で定義したタスクを順番に実装していく
### 実装時の推奨ツール活用
#### 1. コード調査・分析
- `mcp_serena_find_symbol`: 修正対象のシンボルを検索
- `mcp_serena_get_symbols_overview`: ファイル全体の構造を把握
- `mcp_serena_find_referencing_symbols`: 影響範囲の確認
#### 2. コード編集
- `mcp_serena_replace_symbol_body`: 関数やメソッドの本体を置き換え
- `mcp_serena_insert_after_symbol`: シンボルの後に新しいコードを挿入
- `mcp_serena_insert_before_symbol`: シンボルの前に新しいコードを挿入
- `mcp_serena_rename_symbol`: シンボルの名前変更(全参照を自動更新)
#### 3. パターン検索
- `mcp_serena_search_for_pattern`: 特定のパターンのコードを検索
### 実装フロー
1. **タスクの選択**
- 実装計画から次のタスクを選択
- 依存関係を確認
2. **コードベースの調査**
- `mcp_serena_find_symbol`で対象のコードを特定
- `mcp_serena_find_referencing_symbols`で影響範囲を確認
3. **実装**
- 設計書と実装計画に従って実装
- 適切なSerenaツールを使用してコードを編集
- テストコードも同時に作成
4. **動作確認**
- 実装したコードをテスト
- エラーがあれば修正
5. **次のタスクへ**
- 完了したタスクを記録
- 次のタスクへ進む
### 実装時の注意点
- **一度に複数のタスクを実装しない**
- **設計書から逸脱する場合は、必ず理由を説明し、ユーザーの承認を得る**
- **既存コードとの整合性を保つ**
- **適切なエラーハンドリングを実装する**
- **コードコメントで設計の意図を説明する**
### タスク完了の報告
各タスク完了時に以下を報告:
- 実装した内容
- 変更したファイルのリスト
- テスト結果
- 次のタスクの提案
---
## 助言とベストプラクティス
### Serenaツール活用の助言
- **分析フェーズ(要件定義・設計・実装計画)**:コードを直接編集せず、調査と分析に徹する
- **実装フェーズ**:`mcp_serena_replace_symbol_body`などの専用ツールを優先的に使用
- **既存メモリーを活用**:`.serena/memories/`内のファイルを積極的に参照
- **段階的な実装**:一度に全てを実装せず、タスク単位で確実に進める
### 要件定義での助言
- 「なぜこの機能が必要か」を明確にすることで、後の設計判断がしやすくなります
- スコープは最初から広げすぎず、MVP(最小限の実装)を意識しましょう
- 不明点や曖昧な点は推測せず、必ずユーザーに確認しましょう
- **Serenaツールを必ず使用**:
- `mcp_serena_list_dir`でプロジェクト構造を体系的に把握
- `mcp_serena_get_symbols_overview`でファイルの概要を確認(read_fileより優先)
- `mcp_serena_find_symbol`で関連コンポーネントを検索
- `mcp_serena_search_for_pattern`で既存パターンを探す
- **read_fileに頼らず、Serenaツールで現状を正確に把握しましょう**
### 設計での助言
- 拡張性を考慮しつつ、過度な抽象化は避けましょう
- **`mcp_serena_find_symbol`で既存コードを調査**し、整合性を重視しましょう
- テスト可能な設計を心がけましょう
- セキュリティとエラーハンドリングを設計段階から考慮しましょう
- **既存のパターンを`mcp_serena_search_for_pattern`で探し**、統一感のある設計にしましょう
### 実装計画での助言
- 大きなタスクは適切な粒度に分解しましょう(1タスク=1〜3日程度)
- 早い段階で動くものを作れるよう、End-to-Endの最小実装を優先しましょう
- リスクの高いタスクや技術検証が必要なタスクは早めに着手しましょう
- テストコードの作成もタスクに含めましょう
- **各タスクで使用するSerenaツールを明記**しましょう
### 実装での助言
- **`mcp_serena_replace_symbol_body`を活用**:関数の中身だけを置き換え、シグネチャは保持
- **`mcp_serena_rename_symbol`を活用**:名前変更時に全ての参照を自動更新
- **影響範囲を事前確認**:`mcp_serena_find_referencing_symbols`で影響範囲を把握してから実装
- **テストを忘れずに**:実装と同時にテストコードも作成
### 全般的な助言
- 各フェーズの成果物は、後から見返したときに理解できる文書にしましょう
- 決定事項だけでなく、「なぜその決定をしたか」の理由も記録しましょう
- 完璧を求めすぎず、イテレーティブに改善していく姿勢を持ちましょう
- 実装中に設計の問題が見つかった場合は、遠慮なく設計に戻って見直しましょう
- **メモリーファイルを活用**:`.serena/memories/`に保存した仕様書は、実装中いつでも参照可能
---
## 使用例
### 開始方法(コマンドまたは手動)
#### 方法1:専用コマンドを使用
```
@spec.md に従って、仕様駆動開発を開始します。
機能名:ユーザー認証機能
プロジェクト名:auth-system
要件定義フェーズから開始し、以下の成果物を作成してください:
- メモリーファイル:spec_auth-system_requirements.md
```
#### 方法2:手動で指示
```
仕様駆動開発で「ユーザー認証機能」を実装したいです。
プロジェクト名は「auth-system」です。
要件定義から始めてください。
```
### フェーズ間の移行
各フェーズ完了時に表示される確認メッセージに対して「はい」「進めてください」などと返答することで次のフェーズに進みます。
### 実装フェーズへの移行
実装計画フェーズ完了後、以下のように実装を開始できます:
```
TASK-001から実装を開始してください。
```
または:
```
実装計画の優先順位に従って、実装を進めてください。
```
### 途中からの再開
仕様書が既に作成されている場合:
```
プロジェクト「auth-system」の仕様書を確認して、実装計画から再開してください。
```
---
## Serenaツール活用のクイックリファレンス
### 調査・分析ツール(要件定義・設計・実装計画)
| ツール | 用途 | 使用例 |
|-------|------|--------|
| `mcp_serena_list_memories` | 既存メモリー一覧 | 仕様書の確認 |
| `mcp_serena_read_memory` | メモリー読み込み | 前フェーズの成果物を読む |
| `mcp_serena_list_dir` | ディレクトリ構造 | プロジェクト構造の把握 |
| `mcp_serena_get_symbols_overview` | ファイル概要 | クラス・関数の一覧取得 |
| `mcp_serena_find_symbol` | シンボル検索 | 特定のクラス・関数を探す |
| `mcp_serena_find_referencing_symbols` | 参照検索 | 依存関係の調査 |
| `mcp_serena_search_for_pattern` | パターン検索 | 類似実装の探索 |
| `mcp_serena_write_memory` | メモリー保存 | 仕様書の保存 |
### 編集ツール(実装フェーズ)
| ツール | 用途 | 使用例 |
|-------|------|--------|
| `mcp_serena_replace_symbol_body` | シンボル置換 | 関数の中身を書き換え |
| `mcp_serena_insert_after_symbol` | 後に挿入 | 新しいメソッドを追加 |
| `mcp_serena_insert_before_symbol` | 前に挿入 | インポート文を追加 |
| `mcp_serena_rename_symbol` | 名前変更 | リファクタリング |
---
## トラブルシューティング
### Q: 成果物が保存されない
A: `mcp_serena_write_memory`ツールを使用していることを確認してください。コマンドに`@spec.md`が含まれているか確認してください。
### Q: 分析と実装を区別する方法は?
A: フェーズを明確に分けることで区別します。要件定義・設計・実装計画では調査・分析ツールのみを使用し、実装フェーズで編集ツールを使用します。
### Q: 既存コードとの整合性が取れない
A: `mcp_serena_find_symbol`と`mcp_serena_search_for_pattern`で既存の実装パターンを調査し、それに従って設計してください。
### Q: 実装中に設計の問題が見つかった
A: 遠慮なく設計フェーズに戻りましょう。メモリーファイルを更新し、実装計画も見直してください。
(ここでは実際に実装してもらうまでを規定していますが、今回は触れません)
Cursor Commands
Cursor Commandsはドキュメントによると、
再利用可能なワークフロー用のコマンドを定義する
とされています。ざっくり説明すると、「いつも使っているプロンプト」を先に保存しておいて/をつけることでその命令を実行させるためのものです。.cursor/commandsディレクトリ配下に以下のようなファイルを作成するだけでOKです。
今回は以下のものを作成します。
実際のファイル構成はこんな感じになっています:
.
├── commands
└── spec
├── spec-driven-dev.md # 要件定義開始用
├── start-implementation.md # 実装フェーズ用
├── continue-design.md # 設計フェーズ用
└── continue-implementation-plan.md # タスク細分化用
それぞれの内容は以下の通りです。
---
title: "仕様駆動開発を開始"
description: "Serenaツールを活用して要件定義から始める仕様駆動開発を開始します"
icon: "📋"
---
@spec.md に従って、Serena仕様駆動開発を開始します。
**機能名:** {{feature_name}}
**プロジェクト名:** {{project_name}}
## 実行内容
1. 既存メモリーを`mcp_serena_list_memories`で確認
2. 関連するコードベースを`mcp_serena_list_dir`と`mcp_serena_get_symbols_overview`で調査
3. 要件定義フェーズを実施
4. `mcp_serena_write_memory`で成果物を保存
- memory_name: `spec_{{project_name}}_requirements`
調査・分析ツールを使用して要件定義を開始してください。
---
title: "実装を開始"
description: "実装計画に基づいて実装を開始します"
icon: "🚀"
---
@spec.md に従って、実装フェーズを開始します。
実装計画の優先順位に従って、最初のタスクから実装を進めてください。
## 実行内容
1. 実装計画を確認
2. 最優先タスクから順次実装
3. Serena編集ツールを活用してコードを編集
4. 各タスク完了後に報告
---
title: "設計フェーズに進む"
description: "要件定義が完了後、設計フェーズに進みます"
icon: "🎨"
---
@spec.md に従って、設計フェーズに進めてください。
要件定義ファイルを読み込んでから、設計フェーズの成果物を作成してください。
# タスクデータ永続化機能 - 実装計画
## 概要
本実装計画は、設計書に基づいてタスクデータ永続化機能を段階的に実装するためのロードマップです。各タスクは独立して実装可能で、1〜3日程度で完了できる粒度に分解されています。
## タスク一覧
| ID | タスク名 | 優先度 | 見積工数 | 依存タスク | ステータス |
|----|---------|--------|---------|-----------|----------|
| TASK-001 | StorageService実装 | High | 2-3時間 | なし | 未着手 |
| TASK-002 | StorageServiceテスト実装 | High | 1-2時間 | TASK-001 | 未着手 |
| TASK-003 | TaskContext修正 | High | 1時間 | TASK-001 | 未着手 |
| TASK-004 | TagContext修正 | High | 1時間 | TASK-001 | 未着手 |
| TASK-005 | ListContext修正 | High | 1時間 | TASK-001 | 未着手 |
| TASK-006 | 既存テスト実行と修正 | High | 1-2時間 | TASK-003, TASK-004, TASK-005 | 未着手 |
| TASK-007 | E2Eテストと動作確認 | Medium | 1-2時間 | TASK-006 | 未着手 |
**総見積工数**: 8-12時間(1-2日)
## 依存関係グラフ
```
TASK-001 (StorageService実装)
├─→ TASK-002 (テスト実装)
├─→ TASK-003 (TaskContext修正)
├─→ TASK-004 (TagContext修正)
└─→ TASK-005 (ListContext修正)
↓
TASK-006 (既存テスト実行)
↓
TASK-007 (E2Eテスト)
```
## 実装順序
### フェーズ1: コア機能実装(MUST)
1. **TASK-001**: StorageService実装
2. **TASK-002**: StorageServiceテスト実装
### フェーズ2: Context統合(MUST)
3. **TASK-003**: TaskContext修正
4. **TASK-004**: TagContext修正
5. **TASK-005**: ListContext修正
### フェーズ3: 検証(MUST)
6. **TASK-006**: 既存テスト実行と修正
7. **TASK-007**: E2Eテストと動作確認
---
## TASK-001: StorageService実装
### タスク概要
localStorageを抽象化したStorageServiceを実装します。DataHydrationServiceと同様のパターンで、タスク、タグ、タスクリストの永続化機能を提供します。
### 優先度
**High** - 全ての機能の基盤となるため最優先
### 実装内容
1. `src/common/utils/StorageService.js`を新規作成
2. 以下の機能を実装:
- `saveTasks()`, `loadTasks()` - タスクの保存・読み込み
- `saveTags()`, `loadTags()` - タグの保存・読み込み
- `saveTaskLists()`, `loadTaskLists()` - タスクリストの保存・読み込み
- `saveVersion()`, `loadVersion()` - バージョン管理
- `clearAll()` - 全データ削除
- `isAvailable()` - localStorage利用可否チェック
- `getStorageSize()` - 使用容量計算
3. エラーハンドリング実装:
- QuotaExceededError(容量超過)
- JSONパースエラー
- localStorage利用不可
### 完了条件(Definition of Done)
- [ ] StorageService.jsファイルが作成されている
- [ ] 全ての公開APIが実装されている
- [ ] JSDocコメントが全関数に記載されている
- [ ] エラーハンドリングが適切に実装されている
- [ ] DataHydrationServiceと同じコーディングスタイルに従っている
- [ ] ESLintエラーがない
### ファイル作成・修正リスト
- **新規作成**: `src/common/utils/StorageService.js`
### 使用するツール
- `write` - 新規ファイル作成
### 実装コード(設計書より)
```javascript
/**
* Browser localStorage wrapper service for Task Dashboard
* Provides persistent storage for tasks, tags, and task lists
*/
const STORAGE_KEYS = {
TASKS: 'taskDashboard_tasks',
TAGS: 'taskDashboard_tags',
TASK_LISTS: 'taskDashboard_taskLists',
VERSION: 'taskDashboard_version'
};
const CURRENT_VERSION = '1.0.0';
/**
* Generic function to save data to localStorage
* @private
*/
const saveData = (key, data) => {
try {
if (!isAvailable()) {
console.warn('localStorage is not available');
return false;
}
const jsonString = JSON.stringify(data);
localStorage.setItem(key, jsonString);
return true;
} catch (error) {
if (error.name === 'QuotaExceededError') {
console.error('localStorage quota exceeded:', error);
} else {
console.error(`Failed to save data to ${key}:`, error);
}
return false;
}
};
/**
* Generic function to load data from localStorage
* @private
*/
const loadData = (key) => {
try {
if (!isAvailable()) {
return null;
}
const jsonString = localStorage.getItem(key);
if (jsonString === null) {
return null;
}
return JSON.parse(jsonString);
} catch (error) {
console.error(`Failed to load data from ${key}:`, error);
return null;
}
};
/**
* Check if localStorage is available
* @private
*/
const isAvailable = () => {
try {
const testKey = '__storage_test__';
localStorage.setItem(testKey, 'test');
localStorage.removeItem(testKey);
return true;
} catch (e) {
return false;
}
};
export const StorageService = {
// Tasks
saveTasks: (tasks) => saveData(STORAGE_KEYS.TASKS, tasks),
loadTasks: () => loadData(STORAGE_KEYS.TASKS),
// Tags
saveTags: (tags) => saveData(STORAGE_KEYS.TAGS, tags),
loadTags: () => loadData(STORAGE_KEYS.TAGS),
// Task Lists
saveTaskLists: (taskLists) => saveData(STORAGE_KEYS.TASK_LISTS, taskLists),
loadTaskLists: () => loadData(STORAGE_KEYS.TASK_LISTS),
// Version
saveVersion: (version) => saveData(STORAGE_KEYS.VERSION, {
version,
lastUpdated: Date.now()
}),
loadVersion: () => {
const versionData = loadData(STORAGE_KEYS.VERSION);
return versionData ? versionData.version : null;
},
// Utilities
clearAll: () => {
try {
Object.values(STORAGE_KEYS).forEach(key => {
localStorage.removeItem(key);
});
return true;
} catch (error) {
console.error('Failed to clear storage:', error);
return false;
}
},
isAvailable: isAvailable,
getStorageSize: () => {
let total = 0;
Object.values(STORAGE_KEYS).forEach(key => {
const value = localStorage.getItem(key);
if (value) {
total += value.length + key.length;
}
});
return total;
}
};
```
### 注意点・リスク
- **localStorage利用可否**: プライベートブラウジングモードではlocalStorageが無効な場合があるため、`isAvailable()`で必ず確認
- **容量制限**: localStorageは通常5-10MBだが、ブラウザにより異なる。QuotaExceededErrorの適切なハンドリングが必須
- **JSONシリアライズ**: 循環参照や特殊なオブジェクトは保存できないが、現在のデータモデルでは問題なし
- **コーディングスタイル**: DataHydrationService.jsと同じスタイルで実装すること
### 見積工数
**2-3時間**
### 依存タスク
なし
---
## TASK-002: StorageServiceテスト実装
### タスク概要
StorageServiceの単体テストを実装します。既存のテストパターン(Vitest + Testing Library)に従い、全ての公開APIをテストします。
### 優先度
**High** - コア機能の品質保証
### 実装内容
1. `src/common/utils/StorageService.test.js`を新規作成
2. 以下のテストケースを実装:
- **Tasks**: 保存・読み込み、データなし時の挙動
- **Tags**: 保存・読み込み、データなし時の挙動
- **TaskLists**: 保存・読み込み、データなし時の挙動
- **Version**: 保存・読み込み
- **Utilities**: clearAll, isAvailable, getStorageSize
- **エラーケース**: localStorage無効時、容量超過時(モック)
3. beforeEachでlocalStorageをクリア
### 完了条件(Definition of Done)
- [ ] StorageService.test.jsファイルが作成されている
- [ ] 全ての公開APIがテストされている
- [ ] 正常系・異常系の両方がカバーされている
- [ ] テストカバレッジが90%以上
- [ ] 全てのテストがパスする
- [ ] テストコードが既存のテストパターンに従っている
### ファイル作成・修正リスト
- **新規作成**: `src/common/utils/StorageService.test.js`
### 使用するツール
- `write` - 新規ファイル作成
### 実装コード(設計書より)
```javascript
import { describe, test, expect, beforeEach, vi } from 'vitest';
import { StorageService } from './StorageService';
describe('StorageService', () => {
beforeEach(() => {
localStorage.clear();
});
describe('Tasks', () => {
test('should save and load tasks', () => {
const tasks = [
{ id: 1, title: 'Test Task', isCompleted: false, tags: [] }
];
const saved = StorageService.saveTasks(tasks);
expect(saved).toBe(true);
const loaded = StorageService.loadTasks();
expect(loaded).toEqual(tasks);
});
test('should return null when no tasks stored', () => {
const loaded = StorageService.loadTasks();
expect(loaded).toBeNull();
});
});
describe('Tags', () => {
test('should save and load tags', () => {
const tags = ['work', 'personal'];
const saved = StorageService.saveTags(tags);
expect(saved).toBe(true);
const loaded = StorageService.loadTags();
expect(loaded).toEqual(tags);
});
});
describe('TaskLists', () => {
test('should save and load task lists', () => {
const lists = [
{ id: 'default', title: 'All Tasks', filters: [] }
];
const saved = StorageService.saveTaskLists(lists);
expect(saved).toBe(true);
const loaded = StorageService.loadTaskLists();
expect(loaded).toEqual(lists);
});
});
describe('Version', () => {
test('should save and load version', () => {
const saved = StorageService.saveVersion('1.0.0');
expect(saved).toBe(true);
const loaded = StorageService.loadVersion();
expect(loaded).toBe('1.0.0');
});
});
describe('Utilities', () => {
test('should clear all storage', () => {
StorageService.saveTasks([{ id: 1 }]);
StorageService.saveTags(['tag']);
const cleared = StorageService.clearAll();
expect(cleared).toBe(true);
expect(StorageService.loadTasks()).toBeNull();
expect(StorageService.loadTags()).toBeNull();
});
test('should check storage availability', () => {
expect(StorageService.isAvailable()).toBe(true);
});
test('should calculate storage size', () => {
StorageService.saveTasks([{ id: 1, title: 'Task' }]);
const size = StorageService.getStorageSize();
expect(size).toBeGreaterThan(0);
});
});
});
```
### 注意点・リスク
- **localStorage.clear()**: 各テスト前に必ずクリアすること
- **モック不要**: localStorageはJSDOMで自動的にモック化される
- **エラーケーステスト**: 容量超過のテストは実装が複雑なため、初期実装では省略可能
### 見積工数
**1-2時間**
### 依存タスク
- TASK-001(StorageService実装)
---
## TASK-003: TaskContext修正
### タスク概要
TaskContextにStorageServiceを統合し、タスクの自動保存・自動復元機能を実装します。
### 優先度
**High** - メイン機能(タスク管理)の永続化
### 実装内容
1. インポート追加:`import { StorageService } from '../common/utils/StorageService';`
2. useState初期化ロジック修正:
- まずStorageService.loadTasks()を試行
- データがあればそれを使用
- なければ既存のハイドレーションロジックを使用
3. useEffect追加:
- tasksの変更を監視
- StorageService.saveTasks(tasks)を呼び出し
### 完了条件(Definition of Done)
- [ ] StorageServiceがインポートされている
- [ ] useState初期化でlocalStorageから読み込み
- [ ] useEffectで自動保存が実装されている
- [ ] 既存のCRUD操作が正常に動作する
- [ ] ESLintエラーがない
- [ ] ブラウザリロード後にタスクが復元される
### ファイル修正リスト
- **修正**: `src/context/TaskContext.jsx`
### 使用するSerenaツール
1. `mcp_serena_insert_before_symbol` - インポート文追加(TaskContextシンボルの前)
2. `mcp_serena_find_symbol` - TaskProvider内のuseState部分を特定
3. `search_replace` または 手動編集 - useState初期化ロジック変更
4. `mcp_serena_insert_after_symbol` - useEffect追加(既存のuseEffectの後)
### 修正箇所
#### 修正1: インポート追加
```javascript
// 既存のインポート
import React, { createContext, useState, useContext, useEffect } from 'react';
import { DataHydrationService } from '../common/utils/DataHydrationService';
// ↓ 追加
import { StorageService } from '../common/utils/StorageService';
```
#### 修正2: useState初期化の変更
```javascript
// 修正前
const [tasks, setTasks] = useState(() => {
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTasks()
: [];
});
// 修正後
const [tasks, setTasks] = useState(() => {
// まずlocalStorageから読み込み
const storedTasks = StorageService.loadTasks();
if (storedTasks !== null) {
return storedTasks;
}
// localStorageにデータがない場合、ハイドレーションを確認
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTasks()
: [];
});
```
#### 修正3: useEffect追加
```javascript
// 既存のuseEffect(stats更新)の後に追加
// タスクをlocalStorageに自動保存
useEffect(() => {
StorageService.saveTasks(tasks);
}, [tasks]);
```
### 注意点・リスク
- **初回レンダリング**: useState初期化時に即座に保存が走るが、これは意図した動作
- **パフォーマンス**: タスク数が多い場合でも、JSON.stringifyは十分高速
- **既存機能**: 全てのCRUD操作が変更なく動作することを確認
### 見積工数
**1時間**
### 依存タスク
- TASK-001(StorageService実装)
---
## TASK-004: TagContext修正
### タスク概要
TagContextにStorageServiceを統合し、タグの自動保存・自動復元機能を実装します。
### 優先度
**High** - タグ機能の永続化
### 実装内容
1. インポート追加:`import { StorageService } from '../common/utils/StorageService';`
2. useState初期化ロジック修正:
- まずStorageService.loadTags()を試行
- データがあればそれを使用
- なければ既存のハイドレーションロジックを使用
3. useEffect追加:
- tagsの変更を監視
- StorageService.saveTags(tags)を呼び出し
### 完了条件(Definition of Done)
- [ ] StorageServiceがインポートされている
- [ ] useState初期化でlocalStorageから読み込み
- [ ] useEffectで自動保存が実装されている
- [ ] 既存のタグ操作が正常に動作する
- [ ] ESLintエラーがない
- [ ] ブラウザリロード後にタグが復元される
### ファイル修正リスト
- **修正**: `src/context/TagContext.jsx`
### 使用するSerenaツール
1. `mcp_serena_insert_before_symbol` - インポート文追加
2. `search_replace` - useState初期化ロジック変更
3. `mcp_serena_insert_after_symbol` - useEffect追加
### 修正箇所
#### 修正1: インポート追加
```javascript
import { StorageService } from '../common/utils/StorageService';
```
#### 修正2: useState初期化の変更
```javascript
// 修正前
const [tags, setTags] = useState(() => {
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTags()
: [];
});
// 修正後
const [tags, setTags] = useState(() => {
const storedTags = StorageService.loadTags();
if (storedTags !== null) {
return storedTags;
}
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTags()
: [];
});
```
#### 修正3: useEffect追加
```javascript
// タグをlocalStorageに自動保存
useEffect(() => {
StorageService.saveTags(tags);
}, [tags]);
```
### 注意点・リスク
- **タスクとの連携**: TagContextはTaskContextに依存しているが、永続化は独立して動作
- **タグの自動収集**: tasksからのタグ収集ロジックは既存のまま維持
### 見積工数
**1時間**
### 依存タスク
- TASK-001(StorageService実装)
---
## TASK-005: ListContext修正
### タスク概要
ListContextにStorageServiceを統合し、タスクリストの自動保存・自動復元機能を実装します。
### 優先度
**High** - リスト機能の永続化
### 実装内容
1. インポート追加:`import { StorageService } from '../common/utils/StorageService';`
2. useState初期化ロジック修正:
- まずStorageService.loadTaskLists()を試行
- データがあればそれを使用
- なければ既存のハイドレーションロジックを使用
3. useEffect追加:
- taskListsの変更を監視
- StorageService.saveTaskLists(taskLists)を呼び出し
### 完了条件(Definition of Done)
- [ ] StorageServiceがインポートされている
- [ ] useState初期化でlocalStorageから読み込み
- [ ] useEffectで自動保存が実装されている
- [ ] 既存のリスト操作が正常に動作する
- [ ] ESLintエラーがない
- [ ] ブラウザリロード後にタスクリストが復元される
### ファイル修正リスト
- **修正**: `src/context/ListContext.jsx`
### 使用するSerenaツール
1. `mcp_serena_insert_before_symbol` - インポート文追加
2. `search_replace` - useState初期化ロジック変更
3. `mcp_serena_insert_after_symbol` - useEffect追加
### 修正箇所
#### 修正1: インポート追加
```javascript
import { StorageService } from '../common/utils/StorageService';
```
#### 修正2: useState初期化の変更
```javascript
// 修正前
const [taskLists, setTaskLists] = useState(() => {
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTaskLists()
: [{ id: 'default', title: 'All Tasks', filters: [] }];
});
// 修正後
const [taskLists, setTaskLists] = useState(() => {
const storedLists = StorageService.loadTaskLists();
if (storedLists !== null) {
return storedLists;
}
return DataHydrationService.shouldHydrate()
? DataHydrationService.getInitialTaskLists()
: [{ id: 'default', title: 'All Tasks', filters: [] }];
});
```
#### 修正3: useEffect追加
```javascript
// タスクリストをlocalStorageに自動保存
useEffect(() => {
StorageService.saveTaskLists(taskLists);
}, [taskLists]);
```
### 注意点・リスク
- **デフォルトリスト**: localStorageが空の場合でも、デフォルトの'All Tasks'リストは必ず作成される
- **フィルター設定**: フィルター設定も含めて永続化されることを確認
### 見積工数
**1時間**
### 依存タスク
- TASK-001(StorageService実装)
---
## TASK-006: 既存テスト実行と修正
### タスク概要
既存の全テストを実行し、永続化機能の追加により影響を受けるテストを修正します。
### 優先度
**High** - 既存機能の破壊防止
### 実装内容
1. `npm test`または`npm run test`で全テストを実行
2. 失敗したテストを特定
3. 失敗原因を分析:
- localStorage関連のモックが必要か
- テストの前提条件が変わったか
4. 必要に応じてテストを修正:
- beforeEachでlocalStorage.clear()を追加
- StorageServiceをモック化
5. 全テストがパスすることを確認
### 完了条件(Definition of Done)
- [ ] 全ての既存テストが実行されている
- [ ] 失敗したテストが特定されている
- [ ] 失敗原因が分析されている
- [ ] 必要な修正が実施されている
- [ ] 全テストがパスする
- [ ] テストカバレッジが低下していない
### ファイル修正リスト
- **修正候補**:
- `src/context/TaskContext.test.jsx`(存在する場合)
- `src/context/TagContext.test.jsx`(存在する場合)
- `src/context/ListContext.test.jsx`(存在する場合)
- `src/features/tasks/components/*.test.jsx`
- `src/features/tags/components/*.test.jsx`
- `src/features/lists/components/*.test.jsx`
### 使用するツール
- `run_terminal_cmd` - テスト実行
- `grep` - 失敗したテストの検索
- `read_file` - テストファイルの確認
- `search_replace` - テストコードの修正
### テスト修正パターン
#### パターン1: localStorageのクリア追加
```javascript
import { describe, test, expect, beforeEach } from 'vitest';
describe('TaskContext', () => {
beforeEach(() => {
// 各テスト前にlocalStorageをクリア
localStorage.clear();
});
// ... テストケース
});
```
#### パターン2: StorageServiceのモック
```javascript
import { vi } from 'vitest';
// StorageServiceをモック化
vi.mock('../common/utils/StorageService', () => ({
StorageService: {
loadTasks: vi.fn(() => null),
saveTasks: vi.fn(() => true),
// ... 他のメソッド
}
}));
```
### 注意点・リスク
- **Context層のテスト**: 既存でContext層の単体テストがない可能性が高い
- **コンポーネントテスト**: コンポーネント層のテストは影響を受けにくいが、念のため確認
- **localStorage依存**: テスト環境(JSDOM)でlocalStorageが正しく動作することを確認
### 見積工数
**1-2時間**
### 依存タスク
- TASK-003(TaskContext修正)
- TASK-004(TagContext修正)
- TASK-005(ListContext修正)
---
## TASK-007: E2Eテストと動作確認
### タスク概要
ブラウザで実際にアプリケーションを動かし、永続化機能が正しく動作することを確認します。
### 優先度
**Medium** - 最終確認
### 実装内容
1. 開発サーバーを起動:`npm run dev`
2. 以下のシナリオを手動テスト:
**シナリオ1: 初回起動**
- localStorageをクリア(DevTools)
- アプリを開く
- ハイドレーション設定により適切な初期状態が表示されることを確認
**シナリオ2: タスク追加と復元**
- 新しいタスクを3つ追加
- ブラウザをリロード(F5)
- 追加した3つのタスクが表示されることを確認
**シナリオ3: タスク編集と復元**
- タスクを完了状態に変更
- タグを追加
- ブラウザをリロード
- 変更が保持されていることを確認
**シナリオ4: タスクリスト作成と復元**
- 新しいタスクリストを作成
- フィルター設定を追加
- ブラウザをリロード
- リストとフィルター設定が保持されていることを確認
**シナリオ5: タグ管理**
- タグを追加・編集・削除
- ブラウザをリロード
- タグの変更が保持されていることを確認
**シナリオ6: データ削除**
- 全タスクを削除
- ブラウザをリロード
- 空の状態が保持されていることを確認
3. DevToolsでlocalStorageの内容を確認:
- `taskDashboard_tasks`
- `taskDashboard_tags`
- `taskDashboard_taskLists`
- データ形式が正しいことを確認
4. エラーログの確認:
- コンソールにエラーが出ていないことを確認
- ネットワークエラーがないことを確認
### 完了条件(Definition of Done)
- [ ] 全シナリオがテストされている
- [ ] 全シナリオが期待通りに動作する
- [ ] localStorageに正しいデータが保存されている
- [ ] コンソールエラーがない
- [ ] パフォーマンス劣化がない
- [ ] 動作確認結果がドキュメント化されている
### 使用するツール
- `run_terminal_cmd` - 開発サーバー起動
- ブラウザDevTools - localStorage確認、コンソール確認
### チェックリスト
| シナリオ | 期待結果 | 実際の結果 | 合否 |
|---------|---------|-----------|------|
| 初回起動 | ハイドレーションまたは空状態 | | |
| タスク追加と復元 | リロード後も表示される | | |
| タスク編集と復元 | 変更が保持される | | |
| リスト作成と復元 | リストとフィルターが保持される | | |
| タグ管理 | タグの変更が保持される | | |
| データ削除 | 空の状態が保持される | | |
### 注意点・リスク
- **ハイドレーション設定**: VITE_ENABLE_DATA_HYDRATION環境変数の値により挙動が変わる
- **ブラウザ依存**: 異なるブラウザで動作確認することが望ましい
- **プライベートモード**: プライベートブラウジングモードでの動作も確認
### 見積工数
**1-2時間**
### 依存タスク
- TASK-006(既存テスト実行と修正)
---
## 実装時の全体的な注意事項
### コーディング規約
- 既存のコードスタイル(DataHydrationServiceのパターン)に従う
- JSDocコメントを必ず記載
- ESLintルールに従う
- PascalCase、camelCaseの命名規約を守る
### テスト方針
- 全ての公開APIをテスト
- 正常系・異常系の両方をカバー
- localStorageは各テスト前にクリア
### エラーハンドリング
- try-catchで適切にエラーを捕捉
- console.errorでログ出力
- アプリケーションはクラッシュさせない
### パフォーマンス
- JSON.stringifyは十分高速
- debounceは初期実装では不要
- 将来的に必要になれば検討
### ドキュメント
- 重要な設計判断はコメントで記録
- README.mdの更新は不要(機能追加のみ)
---
## マイルストーン
### マイルストーン1: コア機能完成
- **タスク**: TASK-001, TASK-002
- **ゴール**: StorageServiceが完成し、単体テストがパス
- **期間**: 3-5時間
### マイルストーン2: Context統合完成
- **タスク**: TASK-003, TASK-004, TASK-005
- **ゴール**: 全Contextで永続化が動作
- **期間**: 3時間
### マイルストーン3: リリース準備完了
- **タスク**: TASK-006, TASK-007
- **ゴール**: 全テストがパスし、動作確認完了
- **期間**: 2-4時間
**総期間**: 8-12時間(1-2日)
---
## リスクと対策
| リスク | 影響 | 対策 |
|--------|------|------|
| 既存テストの失敗 | 高 | localStorage.clear()を追加、モック化 |
| localStorage利用不可 | 中 | isAvailable()でチェック、フォールバック |
| パフォーマンス劣化 | 低 | 大量データでテスト、必要に応じてdebounce |
| データ破損 | 中 | try-catchで適切に処理、初期状態に戻す |
---
## 次のステップ
実装計画が承認されたら、以下の手順で実装を進めます:
1. **TASK-001**から順番に実装
2. 各タスク完了時に動作確認
3. 問題があれば即座に修正
4. 全タスク完了後、最終レビュー
**実装計画フェーズが完了しました。実装を進めてよろしいですか?**
---
**作成日**: 2025-10-23
**プロジェクト名**: task-persistence
**フェーズ**: 実装計画
**次フェーズ**: 実装
Rulesである程度のルールや方針を定めているので、「それを参考にしてね」という内容と、「開発時にはこのツールを使ってね」という指示が書かれています。
実際にSerena MCPを使ってみる
onbording_toolで概要を掴む
必要なものが導入できたところで実際にやってみましょう。今回は、サンプルのReactプロジェクトとしてTodoリストを作成する task-dashboard を利用します。README.mdに従ってリポジトリをクローンしたら、早速AIエージェントに以下のプロンプトを渡しましょう。
onboarding toolを使ってプロジェクト概要を把握してください。
使うAIモデルによって内容は異なりますが、project_overview.md , project_structure.md などいくつかのmdファイルが生成されます。
以下は、実際に生成されたproject_overview.mdの一部です。
<!-- project_overview.md -->
# Task Dashboard プロジェクト概要
## プロジェクトの目的
Task Dashboardは、タスク管理アプリケーションです。ユーザーがタスクの作成、整理、フィルタリングを行えるモダンでレスポンシブなUIを提供します。このアプリケーションはデモンストレーション目的のみで、本番環境での使用は想定されていません。
## 主要機能
- **タスク管理**: タスクの作成、完了、削除
- **タスクタグ**: カスタマイズ可能なタグでタスクを整理
- **タスクリスト**: カスタムフィルターを持つ複数のリスト作成
- **リストフィルター**: タグや完了ステータスによるタスクフィルタリング
- **アニメーション**: Framer Motionによるスムーズなトランジション
- **レスポンシブデザイン**: デスクトップとモバイルデバイスに対応
## 技術スタック
- **React**: 関数コンポーネントとフックを使用したモダンなReact
- **Tailwind CSS**: スタイリング用のユーティリティファーストCSSフレームワーク
- **Framer Motion**: React用アニメーションライブラリ
- **Vite**: 高速でモダンなビルドツールと開発サーバー
- **Vitest**: Viteと互換性のあるテストフレームワーク
- **@testing-library/react**: Reactコンポーネントのテスト
- **@heroicons/react**: アイコンライブラリ
## アーキテクチャ
### 状態管理
アプリケーションはReact Contextを使用して状態管理を行います:
- **TaskContext**: タスクの状態と操作(追加、切り替え、削除)を管理
- **TagContext**: タグとタスクとの関係を管理
- **ListContext**: タスクリストとフィルタリングロジックを管理
### 主要コンポーネント
- **TaskList**: タスクのリストをレンダリング
- **TaskItem**: 個別のタスクをレンダリング
- **TaskBoard**: 複数のタスクリストを管理
- **TagManager**: タグの作成と管理のインターフェース
- **GlobalTaskForm**: 新しいタスク作成フォーム
- **ListAddTask**: 特定のリストにタスクを追加するフォーム
- **TaskListConfig**: タスクリストの設定インターフェース
### データハイドレーション
アプリケーションはオプションのハイドレーションプロセスを通じてサンプルデータで事前設定をサポート:
- サンプルデータは`src/data/initialData.json`で定義
- `VITE_ENABLE_DATA_HYDRATION`環境変数でハイドレーションの有効/無効を制御
- 開発用の便利なスクリプトが提供される
project_overview.mdには、プロジェクトの概要がまとめられています。AIがLSPを利用して、コードのセマンティック解析を行うことで、コードの変更箇所を簡単に特定し、その影響範囲を短時間で把握することができるよう、AIの参照先としてまとめられているファイルです。
これがそのまま人間にとっても有用なドキュメントとなります。仮に不明点などあった場合にはAIに与える指示も曖昧なものになり、結果として意図通りの出力を得ることができないことがよくあります。
そのため、各モジュールがどのモジュールと関わっているのか、依存関係やデータフローがどのようになっているかを明確に整理することは、この基盤を築くうえで欠かせないプロセスといえます。
こうした情報を短時間で把握するために、
〇〇のデータフローがどうなっているか調査して
といった具体的な調査依頼をAIにすることで、それに関する詳しい資料をAIが作成してくれます。
これにより、プロジェクトの細部に至るまで全体像を体系的に把握しやすくなり、この情報をドキュメントとして残すことも可能になります。
結果として、開発プロセス全体がよりAIフレンドリーになり、継続的な改善や知識共有を促進できるようになります。
まとめ
今回は、AIがコードの構造を理解し、影響範囲を把握できるようにするための仕組みづくりについて紹介しました。
こうした基盤を整えることで、人とAIが協力して安全かつ効率的に開発を進められるようになります。
次回は、この仕組みを活かして要件定義から実装までをAIとともに進めるプロセスを紹介します。
ぜひ続編もご覧ください。








