diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 0e27d57..006196b 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,14 +7,14 @@ }, "metadata": { "description": "AI-driven development toolkit for TDD and SDD workflows, providing comprehensive command templates and agents to enhance developer productivity with Claude Code", - "version": "1.2.0" + "version": "1.3.0" }, "plugins": [ { "name": "tsumiki", "source": "./", "description": "AI-driven development toolkit for TDD and SDD workflows, providing comprehensive command templates and agents to enhance developer productivity with Claude Code", - "version": "1.2.0", + "version": "1.3.0", "author": { "name": "makoto kuroeda", "email": "kuroeda.makoto@classmethod.jp" diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 3635b96..ce341c0 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "tsumiki", - "version": "1.2.0", + "version": "1.3.0", "description": "AI-driven development toolkit for TDD and SDD workflows, providing comprehensive command templates and agents to enhance developer productivity with Claude Code", "author": { "name": "makoto kuroeda", diff --git a/DCS_README.md b/DCS_README.md index 9886204..6397326 100644 --- a/DCS_README.md +++ b/DCS_README.md @@ -13,6 +13,7 @@ DCSは、ソフトウェア開発の各フェーズにおける様々な分析 - `/tsumiki:dcs:sequence-diagram-analysis` - シーケンス図作成 - `/tsumiki:dcs:state-transition-analysis` - 状態遷移分析 - `/tsumiki:dcs:impact-analysis` - 影響範囲分析 +- `/tsumiki:dcs:edgecase-analysis` - エッジケース・異常系分析 #### **実装計画フェーズ** - `/tsumiki:dcs:incremental-dev` - 増分開発計画 @@ -21,6 +22,9 @@ DCSは、ソフトウェア開発の各フェーズにおける様々な分析 - `/tsumiki:dcs:bug-analysis` - バグ原因分析 - `/tsumiki:dcs:performance-analysis` - 性能問題調査 +#### **コードベース理解** +- `/tsumiki:dcs:code-question` - ソースコードに関する質問回答 + --- ## コマンド詳細 @@ -271,6 +275,76 @@ DCSは、ソフトウェア開発の各フェーズにおける様々な分析 --- +### 8. code-question + +**用途** +ソースコードに関する質問に対して、コードベースを調査して分かりやすく回答します。 + +**概要** +ユーザーの質問内容を分析し、質問の種類(コードの場所/動作の仕方/設計の理由/使い方)に応じた適切なアプローチで調査を行います。追加質問にも対応し、最大3回まで深掘り可能です。 + +**使うタイミング** +- 特定の機能やクラスがどこにあるか知りたいとき +- コードの動作フローを理解したいとき +- 設計意図やアーキテクチャの理由を知りたいとき +- 特定のAPIや機能の使い方を確認したいとき + +**主な出力ファイル** +``` +.dcs/{{timestamp}}_{{question_topic}}/ +├── answer.md # 初回回答 +├── answer_2.md # 追加回答(該当する場合) +└── answer_3.md # 追加回答(該当する場合) +``` + +**特徴** +- 質問の種類に応じた調査アプローチの自動選択 +- 追加質問への対応(最大3回) +- 構造化された回答(概要→詳細→補足→まとめ) +- ファイルパスと行番号付きの参照 + +--- + +### 9. edgecase-analysis + +**用途** +システムの各レイヤーにおける包括的なエッジケース・エラー状態を詳細に分析し、見落としがちな異常系シナリオを洗い出します。 + +**概要** +要件定義書またはソースコードを入力として、アプリケーション層・UI・データ管理・ネットワーク・非同期処理・認証・エラーハンドリングなど各層で発生する複合的なエッジケースを網羅的に分析します。 + +**使うタイミング** +- 新機能の実装前にエッジケースを洗い出したいとき +- テストケースの網羅性を向上させたいとき +- 異常系の処理漏れがないか確認したいとき +- セキュリティや信頼性の観点でリスクを評価したいとき + +**主な出力ファイル** +``` +.dcs/{{timestamp}}_{{target_name}}/ +├── index.md # 分析情報のインデックス +├── check_list.md # エッジケースチェックリスト +└── (カテゴリ別分析ファイル) +``` + +**分析カテゴリ** +- アプリケーション層ビジネスロジック +- UI状態 +- データ管理層 +- ネットワーク通信層 +- 非同期処理・メッセージング +- 認証・認可 +- エラーハンドリング +- データモデル状態組み合わせ +- 複合的なエッジケース + +**特徴** +- 要件定義書ベースとソースコードベースの2つの分析モード +- 9カテゴリによる網羅的なエッジケース分析 +- チェックリスト形式での出力 + +--- + ## 共通の出力構造 すべてのコマンドは `.dcs/` ディレクトリ配下にタイムスタンプ付きのディレクトリを作成し、以下のような構造で結果を出力します: @@ -327,6 +401,16 @@ DCSは、ソフトウェア開発の各フェーズにおける様々な分析 /tsumiki:dcs:incremental-dev ユーザー認証機能の追加 ``` +### ソースコードへの質問 +``` +/tsumiki:dcs:code-question 認証フローはどのように実装されていますか +``` + +### エッジケース分析の実行 +``` +/tsumiki:dcs:edgecase-analysis ユーザー認証システム +``` + --- ## 注意事項 diff --git a/DEV_README.md b/DEV_README.md new file mode 100644 index 0000000..acbd205 --- /dev/null +++ b/DEV_README.md @@ -0,0 +1,405 @@ +# Dev Skills ドキュメント + +## 全体概要 + +Dev Skillsは、プロジェクトのコンテキスト分析から実装計画・テストファースト実装・検証・デバッグ・Webテストまでをカバーする統合的な開発スキル群です。 + +### ワークフロー + +``` +dev-init(新規向け) ─┐ + ├→ docs/dev/context.md +dev-context(既存向け)┘ + │ + ▼ + dev-plan ──→ docs/dev/plans// + │ + ├──→ dev-impl ──→ dev-verify + │ ↘ dev-debug(失敗時) + │ + ├──→ dev-run(自動連続実装: impl→verify→debug) + │ + ├──→ dev-screen-spec ──→ dev-webtest-plan ──→ dev-webtest + │ ↘ dev-debug webtest(問題修正) + │ + └──→ dev-navigate(やりたいことからスキルを選択) +``` + +### スキル一覧 + +| スキル | 説明 | +|-------|------| +| `dev-init` | 新規プロジェクトの技術スタック選定・初期化 | +| `dev-context` | 既存プロジェクトのコンテキスト自動分析 | +| `dev-navigate` | やりたいことから最適なスキルをナビゲーション | +| `dev-plan` | 要件をタスク分解して実装計画を作成 | +| `dev-impl` | TDDをガードレールとしたテストファースト実装 | +| `dev-run` | タスク範囲の自動連続実装(impl→verify→debug) | +| `dev-verify` | Plan単位のテスト・ビルド・Lint一括検証 | +| `dev-debug` | エラーカテゴリ別の診断・修正 | +| `dev-screen-spec` | ソースコードから画面仕様を自動生成・差分更新 | +| `dev-webtest-plan` | Playwright用Webテスト計画の生成・差分更新 | +| `dev-webtest` | Playwrightによる画面テスト実行 | + +--- + +## スキル詳細 + +### 1. dev-init + +**用途** +新規プロジェクトやまだ構成が固まっていないプロジェクトの技術スタックを対話的に決定し、コンテキストファイルを生成します。 + +**実行方法** +``` +/tsumiki:dev-init +``` + +**特徴**: +- インタラクティブなヒアリングで技術スタックを決定 +- `docs/dev/context.md` を生成(dev-context互換フォーマット) +- 承認制でプロジェクトスキャフォールディング(package.json、設定ファイル、ディレクトリ構造)も実行可能 +- CLAUDE.mdの自動生成 +- 信号機システムによる確信度表示(前工程指示/妥当な推測/AI推論補完) + +**出力**: +- `docs/dev/context.md` - プロジェクトコンテキスト +- プロジェクトファイル群(承認後) + +--- + +### 2. dev-context + +**用途** +既存プロジェクトの技術スタック・テストフレームワーク・コーディング規約・アーキテクチャを自動分析し、コンテキストファイルを生成します。 + +**実行方法** +``` +/tsumiki:dev-context +``` + +**特徴**: +- 4領域の並列探索(プロジェクトルート/テスト環境/ディレクトリ構造/コーディング規約) +- 500行以内のコンパクトなファイルに集約 +- 後続スキル(dev-plan/dev-impl/dev-verify/dev-debug)の共通基盤として機能 + +**出力**: +- `docs/dev/context.md` - プロジェクトコンテキスト(技術スタック、テスト設定、ビルドコマンド、規約等) + +--- + +### 3. dev-navigate + +**用途** +やりたいことを対話で把握し、最適なtsumikiスキルの開始ポイントを提案します。 + +**実行方法** +``` +/tsumiki:dev-navigate +``` + +**特徴**: +- 対話型のヒアリングでユーザーの目的を把握 +- tsumikiスキル全体から最適なスキルと実行順序を提案 +- 提案後、ユーザーの承認があればそのスキルを起動 + +--- + +### 4. dev-plan + +**用途** +ユーザーの要件をインターフェースファースト設計とテスト可能なタスクに分解し、実装計画を作成します。 + +**実行方法** +``` +# Lightweight モード(素早い計画) +/tsumiki:dev-plan auth "ユーザー認証機能を実装" + +# PRDファイルを入力とする +/tsumiki:dev-plan auth ./docs/prd.md + +# Full-spec モード(EARS要件定義付き) +# 実行時にモード選択 +``` + +**実行モード**: +| モード | 説明 | 出力 | +|-------|------|------| +| Lightweight | 素早い要件明確化→設計→タスク分解 | plan.md + tasks/ | +| Full-spec | EARS要件定義→ユーザーストーリー→受入基準→設計→タスク分解 | requirements.md + user-stories.md + acceptance-criteria.md + plan.md + tasks/ | + +**前提条件**: `docs/dev/context.md` が存在すること + +**出力**: `docs/dev/plans//` + +--- + +### 5. dev-impl + +**用途** +TDDをガードレールとして、テストを先に書いてから実装するテストファースト実装を行います。 + +**実行方法** +``` +# 通常モード(Plan+タスク指定) +/tsumiki:dev-impl auth 001 + +# クイックモード(Plan不要の軽量修正) +/tsumiki:dev-impl "バリデーションメッセージを日本語に変更" +``` + +**実行モード**: +| モード | 引数 | 用途 | +|-------|------|------| +| 通常モード | ` ` | Planのタスクを1つ実装 | +| クイックモード | `"修正指示"` | 軽量な修正・調整(Plan不要) | + +**特徴**: +- 品質 > 速度 > トークン消費の優先順位 +- インターフェースファーストでの最小限コンテキスト構築 +- Red→Green→Refactorのフロー +- 失敗時はdev-debugに委譲 + +--- + +### 6. dev-run + +**用途** +Plan内の指定範囲タスクをdev-impl/dev-verify/dev-debugのワークフローで自動連続実行します。 + +**実行方法** +``` +/tsumiki:dev-run auth 001 005 +``` + +**引数**: +- `plan-name`: 既存のPlan名 +- `from-task-id`: 開始タスクID(例: "001") +- `to-task-id`: 終了タスクID(例: "005") + +**特徴**: +- TaskCreate/TaskUpdateによる依存関係付き進捗管理 +- 各タスクをサブエージェントに委託 +- impl→verify→debugのループを自動実行 + +**前提条件**: `docs/dev/context.md` と `docs/dev/plans//` が存在すること + +--- + +### 7. dev-verify + +**用途** +Plan単位で全タスクの完了状態とテスト・ビルド・Lintの整合性を検証し、レポートを出力します。 + +**実行方法** +``` +/tsumiki:dev-verify auth +``` + +**特徴**: +- タスク完了状態のチェック +- 全テスト実行 +- ビルド・Lint確認 +- ファイルサイズチェック +- 検証レポートの出力 + +**出力**: `docs/dev/plans//reports/` + +--- + +### 8. dev-debug + +**用途** +テスト失敗、ビルドエラー、環境問題など様々なエラーパターンをカテゴリ別に診断し、最小コンテキストで修正します。 + +**実行方法** +``` +# 自動検出モード +/tsumiki:dev-debug + +# 手動指定モード +/tsumiki:dev-debug "TypeError: Cannot read properties of undefined" + +# webtestエラー修正モード +/tsumiki:dev-debug webtest +``` + +**エラーカテゴリ**: +| カテゴリ | 例 | +|---------|---| +| コンパイル/型エラー | 型不一致、missing import | +| テスト失敗 | assertion失敗、タイムアウト | +| ランタイムエラー | null参照、未処理例外 | +| 環境・設定 | 依存関係エラー、設定ミス | +| Lint/フォーマット | スタイル違反、未使用変数 | +| 依存関係 | バージョン競合、パッケージ不足 | +| webtestエラー | 視覚崩れ、a11y違反、レスポンシブ不備 | + +--- + +### 9. dev-screen-spec + +**用途** +ソースコードから画面仕様ドキュメントを自動生成・差分更新します。webtest計画の差分更新パイプラインで、ソースコード変更を画面単位の変更に翻訳する中間レイヤーとして機能します。 + +**実行方法** +``` +# 自動判定(初回 or 差分更新) +/tsumiki:dev-screen-spec + +# 強制的に初回生成 +/tsumiki:dev-screen-spec init + +# 差分更新(特定画面のみ) +/tsumiki:dev-screen-spec update login + +# Planの受け入れ条件から事前生成 +/tsumiki:dev-screen-spec from-plan auth +``` + +**出力**: `docs/dev/screen-specs/` + +--- + +### 10. dev-webtest-plan + +**用途** +dev-planの出力からPlaywright用のWebテスト計画ファイルを自動生成します。画面仕様の変更差分からテスト計画を更新する差分更新モードにも対応します。 + +**実行方法** +``` +# 新規生成 +/tsumiki:dev-webtest-plan auth + +# 差分更新(全計画対象) +/tsumiki:dev-webtest-plan update + +# 差分更新(特定計画のみ) +/tsumiki:dev-webtest-plan update auth +``` + +**前提条件**: `docs/dev/plans//` が存在すること + +**出力**: `docs/dev/webtests/plans/*.md` + +--- + +### 11. dev-webtest + +**用途** +Playwright CLIを使ってWebアプリケーションの動作確認・視覚テスト・アクセシビリティチェック等を実行し、検出した問題を記録します。 + +**実行方法** +``` +# 計画テスト(Markdownテスト計画に沿って自動実行) +/tsumiki:dev-webtest auth + +# 並列実行 +/tsumiki:dev-webtest auth --parallel 3 + +# モンキーテスト +/tsumiki:dev-webtest monkey http://localhost:3000 + +# クイックチェック(単一ページ) +/tsumiki:dev-webtest check http://localhost:3000/login + +# 再テスト(未解決エラーの再確認) +/tsumiki:dev-webtest retest +``` + +**実行モード**: +| モード | 引数 | 用途 | +|-------|------|------| +| 計画テスト | ` [--parallel N]` | Markdownテスト計画に沿って自動テスト | +| モンキーテスト | `monkey ` | ランダム操作でエラー・崩れを検出 | +| クイックチェック | `check ` | 単一ページの視覚・アクセシビリティ確認 | +| プラン選択 | (引数なし) | 利用可能なプラン一覧から選択して実行 | +| 再テスト | `retest` | 未解決エラーの再現手順を再実行 | + +**特徴**: +- Playwright CLI(メイン)/ Playwright MCP(フォールバック) +- スクリーンショット・スナップショットの保存 +- 検出した問題はエラーディレクトリに記録、修正はdev-debugに委譲 + +--- + +## クイックスタート + +### 新規プロジェクト + +```bash +# 1. プロジェクト初期化 +/tsumiki:dev-init + +# 2. 実装計画 +/tsumiki:dev-plan auth "ユーザー認証機能" + +# 3. 自動実装 +/tsumiki:dev-run auth 001 005 + +# 4. 検証 +/tsumiki:dev-verify auth +``` + +### 既存プロジェクト + +```bash +# 1. コンテキスト分析 +/tsumiki:dev-context + +# 2. 何をすべきかわからない場合 +/tsumiki:dev-navigate + +# 3. 実装計画 +/tsumiki:dev-plan payment "決済機能の追加" + +# 4. タスクごとに実装 +/tsumiki:dev-impl payment 001 + +# 5. 検証 +/tsumiki:dev-verify payment +``` + +### Webテストフロー + +```bash +# 1. 画面仕様の生成 +/tsumiki:dev-screen-spec + +# 2. テスト計画の生成 +/tsumiki:dev-webtest-plan auth + +# 3. テスト実行 +/tsumiki:dev-webtest auth + +# 4. 問題があればデバッグ +/tsumiki:dev-debug webtest +``` + +--- + +## 出力ディレクトリ構造 + +``` +docs/dev/ +├── context.md # プロジェクトコンテキスト +├── plans/ # 実装計画 +│ └── / +│ ├── plan.md # 計画概要 +│ ├── tasks/ # タスクファイル +│ │ ├── 001_.md +│ │ └── ... +│ └── reports/ # 検証レポート +├── screen-specs/ # 画面仕様 +│ └── .md +└── webtests/ # Webテスト + ├── plans/ # テスト計画 + │ └── .md + └── errors/ # 検出されたエラー +``` + +## 注意事項 + +1. **前提条件**: ほとんどのスキルは `docs/dev/context.md` の存在を前提とします。最初に `dev-init` または `dev-context` を実行してください。 +2. **Plan名**: 英数字とハイフンのみ使用可能です(日本語は自動変換されます)。 +3. **品質優先**: dev-implは「品質 > 速度 > トークン消費」の優先順位で動作します。 diff --git a/MANUAL.md b/MANUAL.md index fb82b2f..cdc7663 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -8,7 +8,7 @@ Claude Code Pluginを使用してTsumikiをインストールします: ```bash /plugin marketplace add https://github.com/classmethod/tsumiki.git -/plugin install tsumiki@tsumiki +/plugin install tsumiki@tsumiki ``` **注意**: コマンドは `/tsumiki:` プレフィックス付きで実行します(例:`/tsumiki:kairo-requirements`)。 @@ -26,7 +26,7 @@ Claude Code Pluginを使用してTsumikiをインストールします: **例**: `kairo-requirements` 実行時 ``` docs/rule/ # 全コマンド共通ルール -docs/rule/kairo/ # kairoコマンド共通ルール +docs/rule/kairo/ # kairoコマンド共通ルール docs/rule/kairo/requirements/ # kairo-requirements専用ルール ``` @@ -45,42 +45,6 @@ claude_docker/ ディレクトリを参考に構築してください(plugin 改善方法についてのPRをお待ちしてます -### TDDコマンド - -TASK作成時に `TDD` と判定している場合で個別にTDDプロセスを実行したい場合は、以下のコマンドを順次実行できます: - -``` -# TDD要件定義 -/tsumiki:tdd-requirements タスクファイル名 TASK番号 - -# テストケース作成 -/tsumiki:tdd-testcases タスクファイル名 TASK番号 - -# テスト実装(Red) -/tsumiki:tdd-red タスクファイル名 TASK番号 - -# 最小実装(Green) -/tsumiki:tdd-green タスクファイル名 TASK番号 - -# リファクタリング -/tsumiki:tdd-refactor タスクファイル名 TASK番号 - -# TDD完了確認 -/tsumiki:tdd-verify-complete タスクファイル名 TASK番号 -``` - -### DIRECTコマンド - -TASK作成時に `DIRECT` と判定している場合は、以下のコマンドを順次実行できます: - -``` -# DIRECT準備 -/tsumiki:direct-setup タスクファイル名 TASK番号 - -# DIRECT検証 -/tsumiki:direct-verify タスクファイル名 TASK番号 -``` - ### Kairoコマンド(包括的フロー) #### 1. 技術スタック初期化 @@ -157,7 +121,6 @@ Kairoは以下を生成します: #### 5. 実装 タスクを確認した後、実装を開始します: -(TDDサイクルまたはDIRECTを手動実行をお勧めします ``` # 全タスクを順番に実装 @@ -167,9 +130,8 @@ Kairoは以下を生成します: /tsumiki:kairo-implement タスクファイル名 TASK番号 # タスク範囲を指定して実装 タスクディレクトリ名 開始TASK番号 終了TASK番号 -/tsumiki:kairo-loop -(実行中にcompactが発動しても安定して「長時間処理」が可能です - +/tsumiki:kairo-loop +(実行中にcompactが発動しても安定して「長時間処理」が可能です) ``` Kairoは各タスクに対して内部的にTDDコマンドを使用して以下のプロセスを実行します: @@ -180,6 +142,60 @@ Kairoは各タスクに対して内部的にTDDコマンドを使用して以下 5. リファクタリング(tdd-refactor) 6. TDD完了確認(tdd-verify-complete) +#### kairo-implement(Skills版) + +Skills版のkairo-implementは、Claude Codeのタスクシステムと連携した高度な実装スキルです。 + +``` +/tsumiki:kairo-implement [要件名] [TASK-ID] [--hil] +``` + +**特徴**: +- Claude Codeタスクシステム(TaskList/TaskGet/TaskUpdate)との連携 +- `--hil` オプションによるHuman-in-the-loop対応 +- `--model`, `--think-model`, `--tdd-model`, `--note-model` によるモデル指定 +- TDDタスクとDIRECTタスクの自動判定・実行 + +**引数省略時の動作**: +- 要件名: Claude Codeタスクのmetadataから自動取得 +- TASK-ID: blockedByが空かつpendingの最初のタスクを自動選択 + +### TDDコマンド + +TASK作成時に `TDD` と判定している場合で個別にTDDプロセスを実行したい場合は、以下のコマンドを順次実行できます: + +``` +# TDD要件定義 +/tsumiki:tdd-requirements タスクファイル名 TASK番号 + +# テストケース作成 +/tsumiki:tdd-testcases タスクファイル名 TASK番号 + +# テスト実装(Red) +/tsumiki:tdd-red タスクファイル名 TASK番号 + +# 最小実装(Green) +/tsumiki:tdd-green タスクファイル名 TASK番号 + +# リファクタリング +/tsumiki:tdd-refactor タスクファイル名 TASK番号 + +# TDD完了確認 +/tsumiki:tdd-verify-complete タスクファイル名 TASK番号 +``` + +### DIRECTコマンド + +TASK作成時に `DIRECT` と判定している場合は、以下のコマンドを順次実行できます: + +``` +# DIRECT準備 +/tsumiki:direct-setup タスクファイル名 TASK番号 + +# DIRECT検証 +/tsumiki:direct-verify タスクファイル名 TASK番号 +``` + ### リバースエンジニアリングコマンド 既存のコードベースから各種文書を逆生成する場合は、以下のコマンドを順次実行できます: @@ -303,6 +319,82 @@ Kairoは各タスクに対して内部的にTDDコマンドを使用して以下 - 推定された要件は実際のビジネス要件と異なる場合があります - テストケースは実装状況から推定されるため、完全ではない可能性があります +### ユーティリティコマンド + +#### help + +tsumikiの利用可能なコマンド一覧の表示、個別コマンドの詳細ヘルプ、困りごとからの最適コマンド検索を行います。 + +``` +# コマンド一覧表示 +/tsumiki:help + +# 特定コマンドの詳細 +/tsumiki:help kairo-requirements + +# 困りごとから検索 +/tsumiki:help テストが失敗して原因がわからない +``` + +#### orchestrate + +複雑な依頼を自動的に分析し、必要な作業をステップに分割して、適切なエージェントチームを編成して実行します。各ステップの成功条件を自動判定し、失敗時は最大5回まで自動再試行を行います。 + +``` +/tsumiki:orchestrate ログイン機能のテストを追加してバグを修正 +``` + +**特徴**: +- 依頼内容の自動分析とステップ分割 +- エージェントチームの自動編成 +- 成功条件の自動判定 +- 失敗時の自動再試行(最大5回/ステップ) + +#### refine-plan / refine-execute + +既存コードやドキュメントへの小規模な修正を計画・実行するコマンドペアです。 + +``` +# 修正計画の作成 +/tsumiki:refine-plan テストの期待値を新しいAPI仕様に合わせて更新 + +# 計画の実行 +/tsumiki:refine-execute .dcs/20260224_refine_xxx/plan.md +``` + +**refine-plan**は修正対象の特定、影響範囲の調査、実施内容の定義を行い、planファイルを出力します。 + +**refine-execute**はplanファイルに従い、テストケースの変更、実装修正、ビルド確認、テスト実行、セキュリティチェック、差分レビューを実行します。 + +#### auto-debug系コマンド + +テストやビルドの問題を自動的に診断・修正するコマンド群です。 + +| コマンド | 説明 | +|---------|------| +| `auto-debug` | テストエラーの自動デバッグ。全テストケースの確認→エラー原因の調査→修正を段階的に実行(最大3ラウンド) | +| `build-fix` | コンパイルエラー、型エラー、依存パッケージ未解決などのビルドエラーを自動修正 | +| `env-fix` | パッケージ不足、環境変数未設定、設定ファイル不備、外部サービス未起動などの環境依存問題を自動修正 | +| `flaky-fix` | 不安定なテスト(flaky test)の原因を分析し、テストの安定化を実施 | +| `timeout-fix` | テスト実行のタイムアウト問題を分析し、テストの高速化または適切な分離を実施 | + +``` +# テストエラーの自動デバッグ +/tsumiki:auto-debug [テストファイルパス] + +# ビルドエラーの修正 +/tsumiki:build-fix + +# 環境問題の修正 +/tsumiki:env-fix + +# 不安定テストの修正 +/tsumiki:flaky-fix + +# タイムアウト問題の修正 +/tsumiki:timeout-fix +``` + ## ディレクトリ構造 ``` @@ -316,8 +408,12 @@ Kairoは各タスクに対して内部的にTDDコマンドを使用して以下 │ │ └── {要件名}/ │ ├── design/ # 設計文書 │ │ └── {要件名}/ -│ └── tasks/ # タスク一覧 -│ └── {要件名}/ +│ ├── tasks/ # タスク一覧 +│ │ └── {要件名}/ +│ └── dev/ # Dev Skills出力 +│ ├── context.md # プロジェクトコンテキスト +│ └── plans/ # 実装計画 +├── .dcs/ # DCSコマンド出力 ├── backend/ # バックエンドコード ├── frontend/ # フロントエンドコード └── database/ # データベース関連 @@ -378,4 +474,4 @@ A: 各コマンドファイルを編集することで、プロジェクトに ## サポート -問題や質問がある場合は、プロジェクトのイシュートラッカーに報告してください。 \ No newline at end of file +問題や質問がある場合は、プロジェクトのイシュートラッカーに報告してください。 diff --git a/README.md b/README.md index 95af3a9..8121510 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Tsumikiを使用するには、次のClaude Code Pluginコマンドでインス ```bash /plugin marketplace add https://github.com/classmethod/tsumiki.git -/plugin install tsumiki@tsumiki +/plugin install tsumiki@tsumiki ``` このコマンドを実行すると、TsumikiのClaude Codeスラッシュコマンドとエージェントが自動的にインストールされます。 @@ -19,50 +19,109 @@ Tsumikiを使用するには、次のClaude Code Pluginコマンドでインス ## 概要 -Tsumikiは以下の2つのコマンドで構成されています: +Tsumikiは以下のカテゴリで構成されています: -- **kairo** - 要件定義から実装までの包括的な開発フロー -- **tdd** - テスト駆動開発(TDD)の個別実行 - -### Kairoコマンド - -Kairoは要件定義から実装までの開発プロセスを自動化・支援します。以下の開発フローを支援します: - -1. **要件定義** - 概要から詳細な要件定義書を生成 -2. **設計** - 技術設計文書を自動生成 -3. **タスク分割** - 実装タスクを適切に分割・順序付け -4. **TDD実装** - テスト駆動開発による品質の高い実装 +| カテゴリ | 説明 | +|---------|------| +| **Kairo** | 要件定義から実装までの包括的な開発フロー | +| **TDD** | テスト駆動開発の個別実行 | +| **Dev Skills** | コンテキスト分析・計画・実装・検証・デバッグの統合ワークフロー | +| **DCS** | コードベースの分析・調査・ドキュメント生成 | +| **ユーティリティ** | デバッグ支援・小規模修正・オーケストレーション等 | +| **リバースエンジニアリング** | 既存コードからドキュメントを逆生成 | ## 利用可能なコマンド -- `init-tech-stack` - 技術スタックの特定 - ### Kairoコマンド(包括的開発フロー) -- `kairo-requirements` - 要件定義 -- `kairo-design` - 設計文書生成 -- `kairo-tasks` - タスク分割 -- `kairo-implement` - 実装実行 + +Kairoは要件定義から実装までの開発プロセスを自動化・支援します。 + +| コマンド | 説明 | +|---------|------| +| `init-tech-stack` | 技術スタックの特定 | +| `kairo-requirements` | 要件定義(EARS記法) | +| `kairo-design` | 設計文書生成 | +| `kairo-tasks` | タスク分割 | +| `kairo-implement` | 実装実行(TDD/DIRECTを内部で使用) | +| `kairo-loop` | タスク範囲指定の自動連続実装(compact対応) | ### TDDコマンド(個別実行) -- `tdd-requirements` - TDD要件定義 -- `tdd-testcases` - テストケース作成 -- `tdd-red` - テスト実装(Red) -- `tdd-green` - 最小実装(Green) -- `tdd-refactor` - リファクタリング -- `tdd-verify-complete` - TDD完了確認 + +| コマンド | 説明 | +|---------|------| +| `tdd-requirements` | TDD要件定義 | +| `tdd-testcases` | テストケース作成 | +| `tdd-red` | テスト実装(Red) | +| `tdd-green` | 最小実装(Green) | +| `tdd-refactor` | リファクタリング | +| `tdd-verify-complete` | TDD完了確認 | + +### Dev Skills(統合開発ワークフロー) + +Dev Skillsは、プロジェクト分析から実装・検証・Webテストまでをカバーする統合的な開発スキル群です。 + +| スキル | 説明 | +|-------|------| +| `dev-init` | 新規プロジェクトの技術スタック選定・初期化 | +| `dev-context` | 既存プロジェクトのコンテキスト自動分析 | +| `dev-navigate` | やりたいことから最適なスキルをナビゲーション | +| `dev-plan` | 要件をタスク分解して実装計画を作成 | +| `dev-impl` | テストファースト実装(通常/クイックモード) | +| `dev-run` | タスク範囲の自動連続実装 | +| `dev-verify` | Plan単位のテスト・ビルド・Lint一括検証 | +| `dev-debug` | エラーカテゴリ別の診断・修正 | +| `dev-screen-spec` | ソースコードから画面仕様を自動生成・更新 | +| `dev-webtest-plan` | Playwright用Webテスト計画の生成 | +| `dev-webtest` | Playwrightによる画面テスト実行 | + +詳細は [DEV_README.md](./DEV_README.md) を参照してください。 + +### DCSコマンド(分析・調査) + +DCSはコードベースの分析・調査を支援するコマンドスイートです。 + +| コマンド | 説明 | +|---------|------| +| `dcs:feature-rubber-duck` | アイデア整理とPRD作成 | +| `dcs:sequence-diagram-analysis` | シーケンス図作成 | +| `dcs:state-transition-analysis` | 状態遷移分析 | +| `dcs:impact-analysis` | 影響範囲分析 | +| `dcs:incremental-dev` | 増分開発計画 | +| `dcs:bug-analysis` | バグ原因分析 | +| `dcs:performance-analysis` | 性能問題調査 | +| `dcs:code-question` | ソースコードに関する質問回答 | +| `dcs:edgecase-analysis` | エッジケース・異常系分析 | + +詳細は [DCS_README.md](./DCS_README.md) を参照してください。 + +### ユーティリティコマンド + +| コマンド | 説明 | +|---------|------| +| `help` | コマンド一覧・詳細ヘルプ・困りごと検索 | +| `orchestrate` | 複雑な依頼を自動分析しエージェントチームで実行 | +| `refine-plan` | 既存コード・ドキュメントへの小規模修正計画 | +| `refine-execute` | refine-planで作成した計画の実行 | +| `auto-debug` | テストエラーの自動デバッグ | +| `build-fix` | ビルドエラーの自動修正 | +| `env-fix` | 環境依存問題の自動修正 | +| `flaky-fix` | 不安定テストの安定化 | +| `timeout-fix` | タイムアウト問題の解決 | ### リバースエンジニアリングコマンド -- `rev-tasks` - 既存コードから機能単位でタスク一覧を逆生成 -- `rev-design` - 既存コードから設計文書を逆生成 -- `rev-specs` - 既存コードからテスト仕様書を逆生成 -- `rev-requirements` - 既存コードから要件定義書を逆生成 +| コマンド | 説明 | +|---------|------| +| `rev-tasks` | 既存コードからタスク構造を分析 | +| `rev-design` | 既存コードから設計文書を逆生成 | +| `rev-specs` | 既存コードからテスト仕様書を逆生成 | +| `rev-requirements` | 既存コードから要件定義書を逆生成 | ## クイックスタート **注意**: Claude Code Pluginでインストールした場合は、各コマンドの先頭に `tsumiki:` を付けてください(例:`/tsumiki:kairo-requirements`)。 -### 包括的な開発フロー +### Kairoによる包括的な開発フロー ```bash # 1. 技術スタック初期化 @@ -77,8 +136,24 @@ Kairoは要件定義から実装までの開発プロセスを自動化・支援 # 4. タスク分割 /tsumiki:kairo-tasks -# 5. 実装 -/tsumiki:kairo-implement +# 5. 実装(自動連続実装) +/tsumiki:kairo-loop +``` + +### Dev Skillsによる開発フロー + +```bash +# 1. プロジェクトコンテキスト生成 +/tsumiki:dev-context + +# 2. 実装計画作成 +/tsumiki:dev-plan auth "ユーザー認証機能を実装" + +# 3. 自動連続実装 +/tsumiki:dev-run auth 001 005 + +# 4. 検証 +/tsumiki:dev-verify auth ``` ### 個別TDDプロセス @@ -138,6 +213,10 @@ npx -y rulesync generate \ 詳しくは[rulesync](https://github.com/dyoshikawa/rulesync)のREADMEを参照してください。 -## 詳細なマニュアル +## 詳細ドキュメント -使用方法の詳細、ディレクトリ構造、ワークフロー例、トラブルシューティングについては [MANUAL.md](./MANUAL.md) を参照してください。 +| ドキュメント | 内容 | +|-------------|------| +| [MANUAL.md](./MANUAL.md) | Kairo・TDD・ユーティリティコマンドの詳細マニュアル | +| [DEV_README.md](./DEV_README.md) | Dev Skillsの詳細マニュアル | +| [DCS_README.md](./DCS_README.md) | DCSコマンドの詳細マニュアル | diff --git a/commands/dcs/code-question.md b/commands/dcs/code-question.md new file mode 100644 index 0000000..ad94c1f --- /dev/null +++ b/commands/dcs/code-question.md @@ -0,0 +1,404 @@ +--- +description: ソースコードに関する質問に回答する +allowed-tools: Read, Glob, Grep, Task, Bash, AskUserQuestion +argument-hint: "[質問内容(任意)]" +--- +ユーザーからの質問内容をもとにソースコードを調査し、分かりやすく回答します。必要に応じて追加質問も受け付けます。 + +# context + +出力ディレクトリ=".dcs" +カレントディレクトリ={{プロジェクトルート}} +質問内容="" +質問の種類="" +調査スコープ="" +回答ファイル="" +追加質問回数=0 +最大追加質問回数=3 + +# step + +- $1 がある場合、質問内容として記録する +- $1 がない場合、ユーザーに「どのようなことを知りたいですか?」と尋ねる +- 質問内容を簡潔に確認し、ユーザーに表示する +- AskUserQuestion ツールを使って質問の分類を実施し、context を更新する +- 収集した context の内容をユーザーに宣言する +- step2 を実行する + +## step2: 調査実行 + +- 既存の出力ファイルを確認して、重複しないナンバリングを決定する + - {{出力ディレクトリ}}/{{timestamp}}_* を検索 + - 質問内容を簡単に英語化したもの(例: "auth_flow", "data_model")を作成 + - 同じ timestamp と内容で既存ディレクトリがある場合、末尾の連番を +1 する + - ベースディレクトリを "{{出力ディレクトリ}}/{{timestamp}}_{{内容の英語化}}" とする + - 例: ".dcs/20260203123456_auth_flow" +- 回答ファイルパスを決定する + - 回答ファイル: "{{ベースディレクトリ}}/answer.md" +- の内容を context の情報で埋めて、Task ツールで直接実行する + - subagent_type: "general-purpose" + - description: "コード質問への回答生成" + - prompt: テンプレートの内容を context で埋めた完全なプロンプト +- Task の実行結果を受け取る +- step3 を実行する + +## step3: 回答提示と追加質問 + +- 出力された回答ファイルを Read で確認する +- 回答内容の要点をユーザーに提示する + - 質問に対する直接的な回答 + - 重要なファイルパス(相対パス) + - 関連する情報 +- ユーザーに追加の質問があるか確認する + - 「この回答について、さらに詳しく知りたいことはありますか?」 + - 追加質問がある場合: + - 追加質問回数を +1 する + - 追加質問回数が最大追加質問回数を超えていない場合: + - 新しい質問内容を記録する + - 追加回答ファイルを作成(例: "{{ベースディレクトリ}}/answer_2.md") + - を使って Task で追加調査を実行する + - 再度 step3 を実行する + - 追加質問回数が最大に達した場合: + - 「追加質問の上限に達しました。新しい質問がある場合は、改めてコマンドを実行してください。」と伝える + - step4 を実行する + - 追加質問がない場合: + - step4 を実行する + +## step4: 完了 + +- 全ての回答ファイルのパスを整理して表示する + - 初回回答: "{{ベースディレクトリ}}/answer.md" + - 追加回答(該当する場合): "{{ベースディレクトリ}}/answer_2.md", "{{ベースディレクトリ}}/answer_3.md", ... +- 調査完了をユーザーに報告する + +# rules + +## 質問の分類 + +AskUserQuestion ツールを使って、以下の質問を実施する: + +### 質問: 質問の種類 +- **質問**: どのような観点で知りたいですか? +- **header**: "質問の種類" +- **multiSelect**: false +- **options**: + - "コードの場所" - 特定の機能やクラス、関数がどこにあるか知りたい + - "動作の仕方" - コードがどのように動作するか、フローを知りたい + - "設計の理由" - なぜこのような実装になっているか、設計意図を知りたい + - "使い方" - 特定の機能やAPIの使い方を知りたい + +contextとして以下を保持する: +- 質問内容(具体的なテキスト) +- 質問の種類 +- 調査スコープ(必要に応じて質問内容から推測) + +## ファイル名のルール + +### timestamp の形式 +- yyyyMMddHHmmss 形式(例: 20260203123456) + +### 内容の英語化のルール +- 質問内容を簡潔な英語に変換する +- スネークケース(snake_case)を使用 +- 最大30文字程度に収める +- 例: + - "認証フローについて" → "auth_flow" + - "ユーザーデータモデルの構造" → "user_data_model" + - "APIエンドポイントの一覧" → "api_endpoints" + - "エラーハンドリングの実装" → "error_handling" + +### 回答ファイル名のルール +- 初回回答: `answer.md` +- 追加回答: `answer_2.md`, `answer_3.md`, `answer_4.md`, ... + +### 完全なファイル名の例 +**初回回答**: +- `.dcs/20260203123456_auth_flow/answer.md` (初回回答) + +**追加回答**: +- `.dcs/20260203123456_auth_flow/answer_2.md` (追加質問への回答1) +- `.dcs/20260203123456_auth_flow/answer_3.md` (追加質問への回答2) + +## ファイルパスの記載ルール + +- **カレントディレクトリを基準とした相対パスを使用する** +- フルパス(絶対パス)は記載しない +- 例: + - ❌ `/Users/kuroeda/projects/tsumiki-local/src/main.ts` + - ✅ `src/main.ts` +- カレントディレクトリは調査開始時の作業ディレクトリ +- すべてのファイルパスは相対パスで統一する + +## 調査の指針 + +質問の種類に応じて、以下のアプローチで調査する: + +### "コードの場所" の場合 +- Grep/Glob を使って該当するファイル、クラス、関数を検索する +- ファイルパスと行番号を明記する +- 複数の候補がある場合はすべて列挙する + +### "動作の仕方" の場合 +- 該当するコードを Read で確認する +- 処理フローを順を追って説明する +- 関連する他のファイルや関数も調査する +- 必要に応じてシーケンス図や呼び出し関係を説明する + +### "設計の理由" の場合 +- コードのコメント、コミット履歴(可能であれば)を確認する +- 類似の実装パターンを探す +- アーキテクチャ上の考慮事項を推測して説明する + +### "使い方" の場合 +- 該当する機能やAPIの定義を確認する +- 実際の使用例をコードベースから探す +- パラメータ、戻り値、例外などを明確に説明する + +## 追加質問の扱い + +- 追加質問は初回回答に関連する内容に限定する +- 全く新しい質問の場合は、新しいコマンド実行を推奨する +- 追加質問は最大3回まで受け付ける +- 各追加回答は個別のファイルに保存する + +# info + + +あなたはソースコード分析のエキスパートです。以下の質問に対して、コードベースを調査し、分かりやすく回答してください。 + +# 質問情報 + +質問内容: {{質問内容}} +質問の種類: {{質問の種類}} +ベースディレクトリ: {{ベースディレクトリ}}(例: ".dcs/20260203123456_auth_flow") +カレントディレクトリ: {{カレントディレクトリ}} +回答ファイル: {{回答ファイル}}(例: ".dcs/20260203123456_auth_flow/answer.md") + +# 重要な注意事項 + +**すべてのファイルパスは、カレントディレクトリを基準とした相対パスで記載してください。** +**絶対パス(/Users/... や C:\... など)は使用しないでください。** +**回答は読みやすく、理解しやすい形式で記述してください。** +**コード例を示す場合は、シンタックスハイライト付きのコードブロックを使用してください。** + +例: +- ❌ `/Users/kuroeda/projects/tsumiki-local/src/main.ts` +- ✅ `src/main.ts` + +# 調査手順 + +## 1. 質問の理解 + +- 質問内容を分析し、何を調べるべきか明確にする +- 質問の種類({{質問の種類}})に基づいて適切な調査アプローチを選択する + +## 2. コードベースの調査 + +質問の種類に応じて以下を実施する: + +### "コードの場所" の場合 +1. Grep/Glob を使って関連するファイル、クラス、関数を検索する +2. 検索結果から最も関連性の高いものをリストアップする +3. 各ファイルの役割を簡潔に説明する + +### "動作の仕方" の場合 +1. 該当するコードを Read で確認する +2. コードの処理フローを分析する +3. 関連する他のファイルや関数を追跡する +4. 処理の流れを順を追って説明する + +### "設計の理由" の場合 +1. コード内のコメントやドキュメントを確認する +2. 類似の実装パターンを探す +3. アーキテクチャ上の考慮事項を分析する +4. 推測される設計意図を説明する + +### "使い方" の場合 +1. 該当する機能やAPIの定義を確認する +2. 使用例をコードベースから探す +3. パラメータ、戻り値、例外などを確認する +4. 実際の使い方を具体例とともに説明する + +## 3. 回答の構造化 + +以下の出力形式で {{回答ファイル}} に結果を保存してください。 + +# 回答出力形式 + +```markdown +# コード質問への回答 + +**質問**: {{質問内容}} +**調査日時**: {{調査日時}} +**調査者**: Claude Code + +--- + +## 概要 + +{{質問に対する簡潔な回答(2-3文)}} + +--- + +## 詳細な回答 + +### {{セクション1のタイトル}} + +{{詳細な説明}} + +#### 関連ファイル +- [相対パス:行番号](相対パス#L行番号) - {{ファイルの役割}} +- [相対パス:行番号](相対パス#L行番号) - {{ファイルの役割}} + +#### コード例 +```言語 +{{関連するコード例}} +``` + +### {{セクション2のタイトル}} + +{{詳細な説明}} + +(必要に応じてセクションを追加) + +--- + +## 補足情報 + +### 関連する情報 +- {{補足情報1}} +- {{補足情報2}} + +### 参考リンク +- {{内部ドキュメントや関連ファイルへのリンク}} + +--- + +## まとめ + +{{回答の要点を簡潔にまとめる(箇条書きで3-5項目)}} + +- {{要点1}} +- {{要点2}} +- {{要点3}} + +--- + +*この回答は自動調査により生成されました。さらに詳しい情報が必要な場合は、追加の質問を投げかけてください。* +``` + +# 調査の注意点 + +- 質問に直接関連する情報を優先的に収集する +- コード例を示す場合は、必要最小限の部分を抽出する +- 複雑な処理の場合は、図やフロー説明を含める +- 不明な点や推測の範囲は明確に示す +- **すべてのファイルパスは相対パスで記載する(絶対パスは使用しない)** +- 回答は初心者にも理解できるように平易な言葉で説明する +- 技術用語を使う場合は、必要に応じて説明を加える + +必ず Write ツールを使用して、{{回答ファイル}} に結果を保存してください。 + + + +あなたはソースコード分析のエキスパートです。以下の追加質問に対して、前回の回答を踏まえて追加調査を行い、回答してください。 + +# 追加質問情報 + +初回質問: {{初回質問内容}} +初回回答ファイル: {{初回回答ファイル}} +追加質問: {{追加質問内容}} +追加回答ファイル: {{追加回答ファイル}}(例: ".dcs/20260203123456_auth_flow/answer_2.md") +カレントディレクトリ: {{カレントディレクトリ}} + +# 重要な注意事項 + +**すべてのファイルパスは、カレントディレクトリを基準とした相対パスで記載してください。** +**初回回答の内容を踏まえて、追加質問に焦点を絞った回答を作成してください。** +**前回の調査結果を参照する場合は、初回回答ファイルを Read で確認してください。** + +# 追加調査手順 + +## 1. 前回の回答を確認 + +- {{初回回答ファイル}} を Read で読み込む +- 前回の調査結果を把握する +- 追加質問が前回の回答のどの部分に関連するか分析する + +## 2. 追加調査の実施 + +- 追加質問に必要な新しい情報を調査する +- 前回の調査で見つからなかった詳細を深掘りする +- 必要に応じて新しいファイルやコードを調査する + +## 3. 追加回答の構造化 + +以下の出力形式で {{追加回答ファイル}} に結果を保存してください。 + +# 追加回答出力形式 + +```markdown +# コード質問への追加回答 + +**初回質問**: {{初回質問内容}} +**追加質問**: {{追加質問内容}} +**調査日時**: {{調査日時}} +**調査者**: Claude Code + +[← 初回回答を見る](./answer.md) + +--- + +## 概要 + +{{追加質問に対する簡潔な回答(2-3文)}} + +--- + +## 詳細な回答 + +### {{セクション1のタイトル}} + +{{詳細な説明}} + +#### 関連ファイル +- [相対パス:行番号](相対パス#L行番号) - {{ファイルの役割}} + +#### コード例 +```言語 +{{関連するコード例}} +``` + +(必要に応じてセクションを追加) + +--- + +## 前回の回答との関連 + +{{前回の回答とこの追加回答がどのように関連するか説明}} + +--- + +## まとめ + +{{追加回答の要点を簡潔にまとめる}} + +- {{要点1}} +- {{要点2}} + +--- + +*この回答は追加調査により生成されました。さらに質問がある場合は、引き続き追加質問してください。* +``` + +必ず Write ツールを使用して、{{追加回答ファイル}} に結果を保存してください。 + + +# 注意事項 + +- 質問内容を正確に理解し、的確に回答する +- コードベースの調査は必要十分な範囲にとどめる +- 回答は簡潔かつ分かりやすく構造化する +- ファイルパスは必ず相対パスで記載する +- 追加質問は初回回答に関連する内容に限定する +- 追加質問の上限(3回)を超えた場合は適切に案内する diff --git a/commands/refine-execute.md b/commands/refine-execute.md new file mode 100644 index 0000000..93b4b67 --- /dev/null +++ b/commands/refine-execute.md @@ -0,0 +1,172 @@ +--- +description: refine-planが作成したplanファイルに従い、修正・テスト・確認を実施します。テストケースの変更、実装修正、ビルド確認、テスト実行、セキュリティーチェック、差分レビューを行います。 +allowed-tools: Read, Glob, Grep, Edit, Write, Task, Bash(git:*), Bash(npm:*), Bash(npx:*), Bash(pnpm:*), Bash(yarn:*), Bash(python:*), Bash(pytest:*), Bash(go:*), Bash(cargo:*), Bash(make:*) +argument-hint: "" +--- +refine-planで作成したplanファイルを読み込み、修正・検証・確認を順番に実施します。テストケースの修正・実装修正・ビルド確認・テスト実行・セキュリティーチェック・差分レビューをすべて完了させます。 + +# context + +planファイルパス=$1 +ベースディレクトリ="" +修正種別="" +修正対象ファイルリスト=[] +テストファイルリスト=[] + +# steps + +- $1 が指定されていない場合はエラーメッセージを表示して終了する + - 「planファイルのパスを引数に指定してください。例: `/refine-execute .dcs/20260224_refine_xxx/plan.md`」 +- ベースディレクトリ = $1 のディレクトリ部分(plan.md の親ディレクトリ) +- step1 を実行する + +## step1: planファイルの確認 + +- $1 を Read で読み込む +- 修正概要・修正種別・対象ファイル・影響範囲・確認手順を把握する +- 対象ファイルリストとテストファイルリストを context に設定する +- 修正内容をユーザーに要約して報告し、続行の確認を求める(AskUserQuestion は使わず、テキストで確認を求める) +- ユーザーが承認した場合のみ step2 を実行する + +## step2: テストケースの確認・修正 + +- **修正種別がコードの場合(常に実施)**: + - テストファイルリストの各ファイルを Read で確認する + - 修正内容に合わせてテストケースの変更が必要かを判断する + - 変更が必要な場合: Edit ツールでテストケースを修正する + - 修正内容に対する新規テストケースが必要かを判断し、必要であれば追加する +- **修正種別がドキュメント・設定ファイルのみの場合**: + - 「テストケース確認: 対象なし(ドキュメント・設定ファイルのみの修正)」と報告してスキップする +- step3 を実行する + +## step3: 実装・ドキュメントの修正 + +- planファイルの「修正対象ファイル」セクションの内容に従い、各ファイルを修正する + - Edit ツールを使って修正前→修正後の変更を適用する + - 修正箇所が複数ファイルにわたる場合は順番に処理する + - planの範囲外の変更は行わない(追加変更が必要と気づいた場合はユーザーに報告して確認を求める) +- 修正が完了したら修正ファイルの一覧をユーザーに報告する +- step4 を実行する + +## step4: ビルド確認 + +- **修正種別がコードまたは設定ファイルの場合**: + - planファイルの「確認手順 > ビルド確認」に記載のコマンドを Bash で実行する + - コマンドが記載されていない場合: プロジェクトの構成(package.json, Makefile, go.mod 等)から推測して実行する + - ビルドエラーが発生した場合: エラー内容をユーザーに報告し、修正してから再実行する + - 3回以上同じエラーが続く場合は作業を中断してユーザーに報告する +- **修正種別がドキュメントのみの場合**: + - 「ビルド確認: スキップ(ドキュメントのみの修正)」と報告してスキップする +- step5 を実行する + +## step5: テスト実行 + +- **修正種別がコードの場合(常に実施)**: + - planファイルの「確認手順 > テスト実行」に記載のコマンドを Bash で実行する + - コマンドが記載されていない場合: プロジェクトの構成から推測して実行する + - テストが失敗した場合: 失敗内容をユーザーに報告し、実装またはテストを修正してから再実行する + - 3回以上同じ失敗が続く場合は作業を中断してユーザーに報告する +- **修正種別がドキュメント・設定ファイルのみの場合**: + - 「テスト実行: スキップ(ドキュメント・設定ファイルのみの修正)」と報告してスキップする +- step6 を実行する + +## step6: セキュリティーチェック + +- 修正したファイルの内容を Read で確認し、以下の観点でチェックする: + - **入力バリデーション**: ユーザー入力を受け取る箇所で適切な検証が行われているか + - **認証・認可**: 認証・認可ロジックに変更がある場合、意図しないアクセスが生じないか + - **インジェクション**: SQLインジェクション・XSS・コマンドインジェクション等のリスクがないか + - **機密情報**: シークレット・パスワード・トークン等がハードコードされていないか + - **依存関係**: 新たに追加した外部ライブラリに既知の脆弱性がないか +- 問題が見つかった場合: 内容をユーザーに報告し、修正案を提示して承認を得てから対応する +- 問題がない場合: 「セキュリティーチェック: 問題なし」と報告する +- step7 を実行する + +## step7: 差分レビュー・結果報告 + +- `git diff` を Bash で実行し、変更内容の差分を取得する +- 差分の要約(変更ファイル一覧・変更行数)をユーザーに提示する +- の内容を context の情報で埋めて Write ツールで出力する + - 出力ファイル: "{{ベースディレクトリ}}/execute_result.md" +- 完了をユーザーに報告し、出力ファイルのパスを案内する + +# rules + +## エラー時の対応ルール + +- ビルドエラー・テストエラーが発生した場合は、自動修正を試みる前に内容をユーザーに報告する +- 自動修正で解決できない場合はユーザーに確認を求める +- 3回以上同じエラーが繰り返す場合は作業を中断してユーザーに報告する + +## 修正の安全ルール + +- planファイルに記載されていない範囲の変更は行わない +- 追加で変更が必要と判断した場合は、ユーザーに内容を報告してから実施する +- ファイルの削除が必要な場合は必ずユーザーに確認を求める(自動では実施しない) + +## ファイルパスの記載ルール + +- **プロジェクトルートを基準とした相対パスを使用する** +- フルパス(絶対パス)は記載しない + +# info + + +# 修正実施結果 + +**実施日時**: {{実施日時}} +**planファイル**: {{planファイルパス}} +**修正概要**: {{修正概要}} + +--- + +## 実施サマリー + +| 項目 | 結果 | +|------|------| +| テストケース変更 | {{実施済み(N件修正) / 変更不要 / スキップ(ドキュメント修正)}} | +| 実装修正 | {{実施済み}} | +| ビルド確認 | {{成功 / スキップ(ドキュメント修正)}} | +| テスト実行 | {{成功(全N件) / スキップ(ドキュメント修正)}} | +| セキュリティーチェック | {{問題なし / 要対応(対応済み)}} | + +--- + +## 修正したファイル + +| ファイル | 変更の種類 | +|---------|-----------| +| `{{ファイルパス}}` | {{修正内容の概要}} | + +--- + +## テスト結果 + +``` +{{テスト実行結果の出力(スキップの場合は「対象なし」)}} +``` + +--- + +## セキュリティーチェック結果 + +{{チェック結果の詳細(問題がなければ「全項目問題なし」)}} + +--- + +## 差分サマリー + +``` +{{git diff --stat の出力}} +``` + +--- + +## 残課題・注意事項 + +- {{残っている課題や注意事項(なければ「なし」)}} + +--- + +*このファイルは refine-execute によって自動生成されました* + diff --git a/commands/refine-plan.md b/commands/refine-plan.md new file mode 100644 index 0000000..b3d2ff7 --- /dev/null +++ b/commands/refine-plan.md @@ -0,0 +1,190 @@ +--- +description: 既存コードやドキュメントへの小規模な修正を計画します。修正対象の特定・影響範囲の調査・実施内容の定義を行い、refine-executeで実行可能なplanファイルを出力します。 +allowed-tools: Read, Glob, Grep, Task, Write, AskUserQuestion +argument-hint: "[修正内容の概要(任意)]" +--- +既存の実装・ドキュメントに対する小規模な修正計画を立てます。対象ファイルの調査・影響範囲の確認を行い、refine-executeで参照するplanファイルを出力します。 + +# context + +出力ディレクトリ=".dcs" +カレントディレクトリ={{プロジェクトルート}} +修正概要="" +修正種別="" +対象ファイルリスト=[] +影響ファイルリスト=[] +timestamp="" + +# steps + +- $1 がある場合、その内容を 修正概要 に設定して簡潔に説明する +- step1 を実行する + +## step1: 情報収集 + +- AskUserQuestion ツールを使って以下を確認し、context を更新する: + 1. 修正の種別を確認(コード / ドキュメント / 設定ファイル) + 2. 修正内容の詳細を確認(修正概要が空の場合は必ず確認) + 3. 対象ファイルが判明しているかを確認 +- 収集した内容をまとめてユーザーに宣言する +- step2 を実行する + +## step2: 対象ファイルの調査 + +- 対象ファイルが指定されている場合: Read で内容を確認し、修正箇所・行番号を特定する +- 対象ファイルが不明の場合: Glob と Grep を使ってキーワード検索で候補を特定する + - 複数の候補が見つかった場合は AskUserQuestion でユーザーに絞り込みを確認する +- 対象ファイルリストを確定する +- step3 を実行する + +## step3: 影響範囲の調査 + +- 対象ファイルリストの各ファイルについて以下を調査する: + - そのファイルを import / require / 参照しているファイルを Grep で検索 + - 関連するテストファイルを Glob で検索(例: `*.test.*`, `*.spec.*`, `__tests__/` 等) + - ドキュメントや設定ファイルへの影響を確認 +- 影響ファイルリストを確定する +- step4 を実行する + +## step4: planファイルの作成 + +- 出力先ディレクトリを決定する: + - timestamp を現在時刻(yyyyMMddHHmmss 形式)で生成する + - 修正内容を簡潔な英語に変換する(スネークケース、最大30文字) + - ベースディレクトリ = "{{出力ディレクトリ}}/{{timestamp}}_refine_{{英語化した修正名}}" + - 例: ".dcs/20260224143022_refine_user_auth_fix" + - 同じ timestamp と名前のディレクトリが存在する場合は末尾の連番を +1 する +- の内容を context の情報で埋めて Write ツールでファイルに出力する + - 出力ファイル: "{{ベースディレクトリ}}/plan.md" +- 出力したファイルのパスをユーザーに報告する +- 「`/tsumiki:refine-execute {{ベースディレクトリ}}/plan.md` を実行すると修正を開始します」と案内する + +# rules + +## 情報収集のルール + +### 質問1: 修正種別 +- **質問**: 修正の対象は何ですか? +- **header**: "修正種別" +- **options**: + - "コード" - ソースコードファイルの修正 + - "ドキュメント" - Markdown、設計書等の修正 + - "設定ファイル" - JSON、YAML、TOML等の設定修正 + - "複合(コード+ドキュメント等)" - 複数種別にまたがる修正 + +### 質問2: 修正内容の詳細 +- **質問**: どのような修正を行いたいですか?(具体的に教えてください) +- **header**: "修正内容" +- **options**: + - "バグ修正" - 既存の動作上の問題を修正 + - "リファクタリング" - 動作は変えずにコード品質を改善 + - "誤字・記述修正" - テキストの誤りを修正 + - "仕様変更への対応" - 要件変更に合わせて既存実装を修正 + +### 質問3: 対象ファイルの有無 +- **質問**: 修正対象のファイルはわかっていますか? +- **header**: "対象ファイル" +- **options**: + - "はい(ファイルパスがわかる)" - ユーザーに具体的なパスを入力してもらう + - "いいえ(キーワードから調査する)" - キーワードから自動調査する + +## ファイル名のルール + +### timestamp の形式 +- yyyyMMddHHmmss 形式(例: 20260224143022) + +### 修正内容の英語化 +- 修正内容を簡潔な英語に変換する +- スネークケース(snake_case)を使用 +- 最大30文字程度 +- 例: + - "ユーザー認証のバグ修正" → "user_auth_fix" + - "READMEの誤字修正" → "readme_typo_fix" + - "ログ出力の設定変更" → "log_config_update" + +## ファイルパスの記載ルール + +- **プロジェクトルートを基準とした相対パスを使用する** +- フルパス(絶対パス)は記載しない + +# info + + +# 修正計画 + +**作成日時**: {{timestamp}} +**修正概要**: {{修正概要}} +**修正種別**: {{修正種別}} + +--- + +## 修正対象ファイル + +| ファイル | 該当行 | 内容 | +|---------|--------|------| +| `{{ファイルパス}}` | L{{開始行}}-L{{終了行}} | {{修正箇所の概要}} | + +### 修正前後の詳細 + +#### `{{ファイルパス}}` + +**修正前**: +``` +{{修正前のコード/テキスト}} +``` + +**修正後**: +``` +{{修正後のコード/テキスト}} +``` + +**修正理由**: {{なぜこの修正が必要か}} + +--- + +## 影響範囲 + +### 影響を受けるファイル + +| ファイル | 影響の種類 | 対応要否 | +|---------|-----------|---------| +| `{{ファイルパス}}` | {{import参照 / テスト / ドキュメント}} | {{要 / 不要}} | + +### 関連テストファイル + +| テストファイル | 対応内容 | +|--------------|---------| +| `{{テストファイルパス}}` | {{テストの変更が必要な場合はその内容、不要な場合は「変更不要」}} | + +--- + +## リスク・注意事項 + +- {{リスク1: 例)他のモジュールへの影響}} +- {{リスク2: 例)破壊的変更の有無}} +- {{注意事項1}} + +--- + +## 確認手順 + +### ビルド確認 +``` +{{ビルドコマンド(例: npm run build / make build / go build ./... 等)}} +``` + +### テスト実行 +``` +{{テスト実行コマンド(例: npm test / pytest / go test ./... 等)}} +``` + +### セキュリティ確認観点 +- 入力値のバリデーション変更の有無 +- 認証・認可ロジックの変更の有無 +- 外部入力を扱う箇所の変更の有無 +- SQLインジェクション・XSS等のリスクの有無 + +--- + +*このplanファイルは `/tsumiki:refine-execute {{ベースディレクトリ}}/plan.md` で実行できます* + diff --git a/skills/dev-context/SKILL.md b/skills/dev-context/SKILL.md new file mode 100644 index 0000000..c40239b --- /dev/null +++ b/skills/dev-context/SKILL.md @@ -0,0 +1,109 @@ +--- +name: dev-context +description: This skill should be used when the user asks to "dev-context", "プロジェクトコンテキストを生成", "プロジェクトを分析", "generate project context", "analyze project", "コンテキストを更新". プロジェクトの技術スタック・テストフレームワーク・コーディング規約・アーキテクチャを自動分析し、コンパクトなコンテキストファイルを生成する。 +--- + +# Dev Context + +プロジェクトの技術スタック、テストフレームワーク、コーディング規約、アーキテクチャパターンを自動分析し、後続のdev-plan/dev-impl/dev-verify/dev-debugスキルが参照するコンパクトなコンテキストファイル(Memory Bank)を `docs/dev/context.md` に生成する。 + +## 前提知識 + +### dev-*スキル全体像 + +本スキルは以下のワークフローの最初のステップ: + +``` +dev-context → dev-plan → dev-impl → dev-verify + ↘ dev-debug (必要時) +``` + +### コンテキストファイルの役割 + +`docs/dev/context.md` は後続スキルの共通基盤: +- **dev-plan**: プロジェクトパターンに沿った設計・タスク分解 +- **dev-impl**: テスト規約・命名規則に準拠した実装 +- **dev-verify**: テスト・ビルド・Lintコマンドの取得 +- **dev-debug**: 環境情報・依存関係の把握 + +500行以内のコンパクトなファイルにまとめ、後続スキルのコンテキスト消費を最小化する。 + +## ワークフロー + +### Step 1: 並列探索 + +Explore サブエージェントを複数並列で起動し、プロジェクト情報を収集する。以下の4領域を並列に探索する: + +#### 1a. プロジェクトルート分析 +- パッケージ定義ファイルの検出: `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `build.gradle`, `pom.xml` 等 +- 言語・フレームワーク・ランタイムの特定 +- パッケージマネージャの特定(npm/yarn/pnpm/bun, cargo, pip/uv 等) + +#### 1b. テスト環境分析 +- テストフレームワークの検出: Jest, Vitest, pytest, go test, cargo test, JUnit 等 +- テスト設定ファイルの確認 +- テスト実行コマンドの特定 +- テストディレクトリの構造把握 + +#### 1c. ディレクトリ構造分析 +- 主要ディレクトリの役割マッピング(src/, lib/, tests/, docs/ 等) +- エントリポイントの特定 +- モジュール構成の把握(モノレポ判定含む) + +#### 1d. コード規約サンプリング +- 代表的なソースファイルを3-5個読み込み +- 命名規則の推定(camelCase, snake_case, PascalCase 等) +- エラーハンドリングパターンの抽出 +- ログ方式の特定 +- インポートスタイルの確認 + +**サブエージェント設定**: `subagent_type: Explore`, `model: haiku`(高速・低コスト) + +### Step 2: 情報統合 + +サブエージェントの結果を統合し、追加情報を取り込む。**各ファイルの読み込みには行数上限を設け、コンテキスト消費を制限する**: + +1. **CLAUDE.md の読み込み**(上限: **100行**): プロジェクトルートに CLAUDE.md がある場合: + - 100行以内 → そのまま Read で読み込み統合する + - 100行超過 → Explore サブエージェント(`model: haiku`)で全文を読ませ、コーディング規約・テスト方針・ビルド手順の **要約のみ** 取得する +2. **README.md の読み込み**(上限: **100行**): プロジェクト概要がある場合: + - Read の `limit: 100` で **先頭100行のみ** 読み込む(概要は通常先頭にある) +3. **設定ファイルの確認**(各上限: **50行**): .eslintrc, .prettierrc, tsconfig.json 等: + - 各ファイルを Read の `limit: 50` で読み込み、追加規約を抽出する +4. **リポマップ生成**: 主要モジュールとエントリポイントの一覧を構造化する(Aider的アプローチ) + +### Step 3: コンテキストファイル出力 + +`docs/dev/context.md` を生成する。`references/context-template.md` のテンプレートに従い、500行以内に収める。 + +出力前に `docs/dev/` ディレクトリが存在しない場合は作成する(プロジェクトルートの絶対パスを使用): + +```bash +mkdir -p "$(git rev-parse --show-toplevel)/docs/dev" +``` + +既存の `docs/dev/context.md` がある場合は上書きする。差分がある場合はユーザーに通知する。 + +## 信号機システム + +生成したコンテキストファイルの各セクションに確信度を付与する: + +- 🔵 **前工程指示**: パッケージ定義ファイルや設定ファイルから直接読み取れた情報 +- 🟡 **妥当な推測**: コードサンプリングから推定した規約・パターン +- 🔴 **AI推論補完**: 明確な根拠がなくAIが推測した情報(組織固有のルール等) + +## ルール・制約 + +- context.md は **500行以内** に収める。超える場合は情報を要約・圧縮する +- サブエージェントの結果は要約のみメインコンテキストに返す(トークン節約) +- プロジェクト全体のコードを読まない。代表的なファイル(3-5個)からパターンを推定する +- テスト実行コマンドは必ず含める(後続スキルが依存) +- ビルドコマンドは検出できた場合のみ含める +- 既存の `docs/dev/plans/` 配下のファイルには影響を与えない +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) + +## 追加リソース + +### リファレンスファイル + +- **`references/context-template.md`** — context.md のテンプレートと各セクションの記述ガイド diff --git a/skills/dev-context/references/context-template.md b/skills/dev-context/references/context-template.md new file mode 100644 index 0000000..4b932b6 --- /dev/null +++ b/skills/dev-context/references/context-template.md @@ -0,0 +1,150 @@ +# context.md テンプレート + +## テンプレート + +以下のテンプレートに従って `docs/dev/context.md` を生成する。各セクションは検出できた情報のみ記載し、不明なセクションは省略する。 + +```markdown +# Project Context + +> Generated by dev-context. Last updated: YYYY-MM-DD +> Confidence: 🔵 = from config/source files, 🟡 = inferred from code, 🔴 = AI assumption + +## Tech Stack + +| Category | Value | Confidence | +|----------|-------|-----------| +| Language | [言語名 + バージョン] | 🔵/🟡 | +| Framework | [フレームワーク名 + バージョン] | 🔵/🟡 | +| Runtime | [Node.js/Deno/Bun/etc + バージョン] | 🔵/🟡 | +| Package Manager | [npm/yarn/pnpm/bun/cargo/pip 等] | 🔵 | + +## Test Framework + +| Item | Value | +|------|-------| +| Framework | [Jest/Vitest/pytest/go test 等] | +| Config File | [jest.config.ts, vitest.config.ts 等] | +| Test Command | [npm test, cargo test 等] | +| Test Directory | [tests/, __tests__/, src/**/*.test.* 等] | +| Coverage Command | [npx jest --coverage 等](検出できた場合) | + +## Project Structure + +[主要ディレクトリの役割マップをツリー形式で記載] + +``` +src/ +├── components/ # UIコンポーネント +├── services/ # ビジネスロジック +├── utils/ # ユーティリティ +└── types/ # 型定義 +tests/ +└── ... # テストファイル +``` + +## Coding Conventions + +### Naming + +| Target | Convention | Example | +|--------|-----------|---------| +| Variables | camelCase/snake_case | userName / user_name | +| Functions | camelCase/snake_case | getUserById / get_user_by_id | +| Classes/Types | PascalCase | UserService | +| Files | kebab-case/camelCase | user-service.ts | +| Constants | UPPER_SNAKE | MAX_RETRY_COUNT | + +### Error Handling + +[プロジェクトで使用されているエラーハンドリングパターンを記述] +- 例: try-catch with custom error classes +- 例: Result pattern +- 例: Error middleware pattern + +### Import Style + +[インポートの順序・スタイルを記述] +- 例: External → Internal → Relative +- 例: Named imports preferred + +### Logging + +[ログ方式を記述] +- 例: console.log (development) +- 例: winston/pino structured logging + +## Key Entry Points + +[主要モジュール・ファイルの一覧(リポマップ)] + +| Module | File | Purpose | +|--------|------|---------| +| [モジュール名] | [ファイルパス] | [役割の簡潔な説明] | + +## Build & Run + +| Command | Description | +|---------|------------| +| [ビルドコマンド] | Build the project | +| [テスト実行コマンド] | Run all tests | +| [開発サーバーコマンド] | Start dev server | +| [Lintコマンド] | Run linter | +| [フォーマットコマンド] | Format code | + +## Docker Environment + +| Item | Value | +|------|-------| +| docker-compose | [あり/なし] | +| App Service | [イメージ名:タグ] | +| DB Service | [PostgreSQL/MongoDB/なし] | +| Test Service | [Playwright/なし] | +| Dev Command | [docker compose up -d] | +| Hot-Reload | [対応/非対応] | + +## Additional Notes + +[CLAUDE.md や README.md から取り込んだ追加情報] +[プロジェクト固有のルールや注意点] +``` + +## 各セクションの記述ガイド + +### Tech Stack +- パッケージ定義ファイルから直接読み取った情報は 🔵 +- コードから推定した情報は 🟡 +- バージョンが特定できない場合は「latest」ではなく「unknown」と記載 + +### Test Framework +- テスト実行コマンドは **必ず記載する**(後続スキルが依存する最重要情報) +- 複数のテストフレームワークがある場合はすべて列挙 +- E2Eテストと単体テストは分けて記載 + +### Project Structure +- 深さは2-3階層まで +- 空ディレクトリや設定ファイルのみのディレクトリは省略 +- コメントで各ディレクトリの役割を簡潔に記述 + +### Coding Conventions +- 代表的なファイルから帰納的に推定 +- 確証がない場合は 🟡 を付与 +- プロジェクトで明示的な設定(.eslintrc等)がある場合はそれを優先 + +### Key Entry Points(リポマップ) +- 主要なモジュール・サービス・コンポーネントを10-20個 +- ファイルパスは相対パス +- 役割は1文以内 + +### Build & Run +- scripts/ の内容がある場合はそれを優先 +- 検出できたコマンドのみ記載(推測しない) + +## 行数制限 + +context.md 全体で **500行以内** に収める。以下の優先順位で情報を圧縮する: + +1. Tech Stack / Test Framework / Build & Run: 必須(圧縮不可) +2. Project Structure / Key Entry Points: 重要(ディレクトリ深度やモジュール数で調整) +3. Coding Conventions: 主要なものだけ残す +4. Additional Notes: 最小限に diff --git a/skills/dev-debug/SKILL.md b/skills/dev-debug/SKILL.md new file mode 100644 index 0000000..518246c --- /dev/null +++ b/skills/dev-debug/SKILL.md @@ -0,0 +1,256 @@ +--- +name: dev-debug +description: This skill should be used when the user asks to "dev-debug", "テストが失敗する", "ビルドエラーを直して", "デバッグ", "debug failing tests", "fix build error", "エラーを修正", "コンパイルエラー", "環境の問題を解決". テスト失敗、ビルドエラー、環境問題など様々なエラーパターンをカテゴリ別に診断し、最小コンテキストで修正する。 +argument-hint: '' +--- + +# Dev Debug + +テスト失敗、コンパイルエラー、環境問題など、様々なエラーパターンに対応する集中デバッグスキル。エラーをカテゴリ分類し、それぞれに最適な診断・修正戦略を適用する。最小コンテキストでの高速解決を目指す。 + +## 前提知識 + +### dev-*スキルフロー内の位置 + +``` +dev-context → dev-plan → dev-impl → dev-verify + ↘ [dev-debug] ↗ + ↑ + dev-webtest → [dev-debug webtest] → 「/dev-webtest retest で再テストしてください」 + ↑ │ + └──────── retest ────────────────────────────┘ +``` + +dev-impl で解消できないエラーが発生した場合、dev-verify で問題が検出された場合、または dev-webtest で検出された画面系エラーの修正に使用する。 + +### 引数フォーマット + +``` +/dev-debug # 自動検出モード +/dev-debug "エラーメッセージや状況の説明" # 手動指定モード +/dev-debug webtest # webtest エラー修正モード +``` + +## エラーカテゴリと対応戦略 + +### カテゴリ一覧 + +| カテゴリ | 例 | 診断アプローチ | 典型的な修正 | +|---------|---|-------------|-----------| +| **コンパイル/型エラー** | 型不一致、missing import、構文エラー | エラーメッセージの直接分析 | 型定義修正、import追加 | +| **テスト失敗** | assertion失敗、タイムアウト | 期待値と実際の差分分析 | ロジック修正 or テスト修正 | +| **ランタイムエラー** | null参照、パニック、未処理例外 | スタックトレース分析 | エラーハンドリング追加 | +| **環境・設定** | 依存関係エラー、設定ミス、パス問題 | 設定ファイル・環境変数チェック | 設定修正、依存追加 | +| **Lint/フォーマット** | スタイル違反、未使用変数 | Lint出力分析 | 自動修正 or コード調整 | +| **依存関係** | バージョン競合、パッケージ不足 | lock file/パッケージ分析 | バージョン調整、パッケージ追加 | +| **webtest エラー** | 視覚崩れ、a11y違反、レスポンシブ不備、フォームバリデーション不備、シナリオ失敗 | error.md の検出内容・再現手順を分析 | CSS/HTML修正、バリデーション追加、機能バグ修正 | + +## ワークフロー + +### Step 1: エラー情報の収集と分類 + +#### 自動検出モード(引数なし) + +1. `docs/dev/context.md` からテスト実行コマンドを取得する +2. テストを実行してエラーを収集する +3. ビルドコマンドがある場合はビルドも実行する + +#### 手動指定モード(引数あり、webtest 以外) + +ユーザーが提供したエラー情報を分析する。 + +#### webtest モード(引数が `webtest`) + +1. `docs/dev/webtests/errors/` を Glob で走査し、全 `error.md` を取得する +2. 各 error.md を Read し、frontmatter の `status: open` のものだけ収集する +3. 0件の場合 →「未解決の webtest エラーはありません」と報告して終了 +4. `severity` 順にソートする(critical → major → minor) +5. 各エラーを Step 2 の webtest エラー診断 → Step 3 の修正・検証で順次処理する +6. 全エラー処理後、Step 4 で報告する(`/dev-webtest retest` での再テストを案内) + +#### 分類判定 + +エラーメッセージのパターンマッチでカテゴリを判定する: + +- `TypeError`, `SyntaxError`, `Cannot find module`, `missing import` → コンパイル/型エラー +- `AssertionError`, `expect(`, `assert`, `test failed` → テスト失敗 +- `null`, `undefined`, `panic`, `NullPointerException`, `segfault` → ランタイムエラー +- `ENOENT`, `Permission denied`, `port already in use`, `env` → 環境・設定 +- `eslint`, `prettier`, `clippy`, `unused variable` → Lint/フォーマット +- `ERESOLVE`, `version conflict`, `peer dependency` → 依存関係 + +### Step 2: カテゴリ別診断 + +#### コンパイル/型エラー + +**最小コンテキスト**: エラー箇所のファイルのみ読み込む。 + +1. エラーメッセージから該当ファイルと行番号を特定する +2. 該当ファイルの関連部分を読み込む(Read tool の offset/limit を活用) +3. 型定義・インターフェースが関係する場合はそれも読み込む +4. 修正案を生成する + +#### テスト失敗 + +**最小コンテキスト**: テストファイル + 対象実装ファイル。 + +1. 失敗テストのファイルと名称を特定する +2. テストファイルを読み込み、期待値を確認する +3. 対象の実装ファイルを読み込む +4. 期待値と実際の差分から原因を特定する +5. **判断**: テストが正しいか、実装が正しいかを判断する + - テストが正しい場合 → 実装を修正 + - 実装が正しい場合 → テストを修正(ユーザーに確認を推奨) + +#### ランタイムエラー + +**最小コンテキスト**: スタックトレースに含まれるファイル。 + +1. スタックトレースからコールチェーンを特定する +2. 最も関連性の高いファイルから読み込む +3. null/undefined チェックの漏れ、例外ハンドリングの不足を特定する +4. ガード句やエラーハンドリングを追加する + +#### 環境・設定 + +**最小コンテキスト**: 設定ファイル群。 + +1. Explore サブエージェント(haiku)で設定ファイルを探索する +2. 環境変数、パス設定、ポート設定等を確認する +3. 必要に応じてユーザーに手動操作を依頼する(AskUserQuestion) +4. AI単独で解決できない場合は明確に伝達する + +#### Lint/フォーマット + +**最小コンテキスト**: Lint出力のみ。 + +1. Lint/フォーマッターの自動修正コマンドがあれば実行する +2. 自動修正できない場合は手動で修正する +3. 修正後に再度Lintを実行して確認する + +#### 依存関係 + +**最小コンテキスト**: パッケージ定義ファイル + lock file。 + +1. パッケージマネージャのエラー出力を分析する +2. 依存ツリーの競合を確認する +3. 互換性のあるバージョンを提案する +4. 必要に応じてユーザーに確認する(破壊的変更がある場合) + +#### webtest エラー + +**最小コンテキスト**: error.md + 関連するソースファイル。 + +error.md の `step` フィールドに応じて診断アプローチを切り替える: + +| step | 主な修正対象 | 診断アプローチ | +|------|------------|-------------| +| `3-visual` | CSS、テンプレート | error.md の検出内容からレイアウト崩れの原因を特定し、CSS/テンプレートを修正 | +| `4-a11y` | HTML属性 | 不足している alt、label、aria 属性、heading 階層を特定して追加 | +| `5-responsive` | メディアクエリ、CSS | 問題のビューポートサイズに対応するメディアクエリやレイアウト CSS を修正 | +| `6-form` | バリデーションロジック | サーバー/クライアントのバリデーション処理を特定して修正。XSS/SQLi はサニタイズ処理を追加 | +| `2a-scenario` / `2b-monkey` | 機能実装 | 再現手順と期待される状態から機能バグを特定し、実装を修正 | + +1. error.md の「検出内容」「再現手順」「期待される状態」を読み取る +2. Explore サブエージェント(haiku)で関連ソースファイルを特定する +3. 上記テーブルに従い修正案を生成する +4. 修正を適用する(Step 3 へ進む) + +### Step 3: 修正の適用と検証 + +1. 修正案を適用する +2. カテゴリに応じた検証コマンドを実行する: + - コンパイル/型エラー → ビルド実行 + - テスト失敗 → 失敗していたテストを実行 + - ランタイムエラー → 関連テストを実行 + - 環境・設定 → 環境チェックコマンド + - Lint → Lint再実行 + - 依存関係 → インストール + ビルド +3. 修正が不十分な場合は Step 2 に戻る(**最大3サイクル**) + +### Step 4: 回帰テストと報告 + +1. 修正対象のエラーが解消されたことを確認する +2. 全テストを実行し、回帰がないことを確認する +3. 結果をユーザーに報告する + +**報告フォーマット**(通常モード): +```markdown +## dev-debug 結果 + +### 検出されたエラー +- カテゴリ: [エラーカテゴリ] +- 原因: [根本原因の説明] + +### 適用した修正 +- [ファイル](パス): [修正内容] + +### 検証結果 +- 対象エラー: 解消 +- 回帰テスト: passed / failed + +### 確信度 +- 🔵/🟡/🔴: [修正の確信度と理由] +``` + +**報告フォーマット**(webtest モード): +```markdown +## dev-debug webtest 結果 + +### 修正したエラー +| # | error.md | severity | step | 修正内容 | +|---|----------|----------|------|---------| +| 1 | docs/dev/webtests/errors/.../ | critical | 2a-scenario | [修正内容] | + +### 修正できなかったエラー +| # | error.md | severity | step | 理由 | +|---|----------|----------|------|------| +(なければ「なし」) + +### 次のステップ +`/dev-webtest retest` で再テストし、修正が反映されているか確認してください。 +``` + +## サイクル制限と escalation + +3サイクルで解決できない場合: + +1. これまでの診断結果と試行した修正をユーザーに報告する +2. 考えられる追加の原因仮説を提示する +3. ユーザーに次のアクションを相談する(AskUserQuestion): + - 追加情報の提供 + - 手動での確認依頼 + - アプローチの変更 + +## Intent コメントルール + +コード修正時に、既存の Intent コメント(🔵🟡🔴)を維持し、修正箇所には適切に追加・更新する。 + +### 修正時の対応 + +- **既存の Intent コメントがある関数を修正する場合**: コメント内容が修正後も正確であれば維持する。修正により意図が変わった場合はコメントを更新する +- **新しい関数・メソッドを追加する場合**: dev-impl と同じルールで Intent コメントを付与する(public 関数は必須) +- **デバッグ修正特有の判断がある場合**: 修正理由を Intent コメントに反映する + +```go +// 🟡 Intent: nil チェックを追加。元のコードではリポジトリが nil を返すケースが +// 未考慮だったため、エラーとして返却するガード句を追加。 +func (s *TodoService) GetByID(ctx context.Context, id string) (*model.Todo, error) { +``` + +### 信号機の判定基準 + +- 🔵 **前工程指示**: タスクファイル・plan.md で指示された修正 +- 🟡 **妥当な推測**: エラーパターンから推論した妥当な修正(ガード句追加、型修正等) +- 🔴 **AI推論補完**: 根本原因が不明確なまま適用した暫定修正 + +## ルール・制約 + +- **最小コンテキスト原則**: エラーに関連するファイルだけ読み込む。プロジェクト全体を読まない +- **サイクル制限**: 修正→検証のサイクルは最大3回 +- **回帰防止**: 修正後は必ず全テストを実行する +- **環境問題の限界認識**: AI単独で解決できない環境問題(OS設定、ネットワーク等)はユーザーに明示的に伝達する +- **テスト修正の慎重さ**: テストを修正する場合はユーザーに確認を推奨する(テストが仕様を反映しているため) +- 探索作業は Explore サブエージェント(haiku)に委託し、メインコンテキストを保護する +- 500行ルール: 修正によりファイルが500行を超える場合は分割する +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) diff --git a/skills/dev-impl/SKILL.md b/skills/dev-impl/SKILL.md new file mode 100644 index 0000000..9597ba5 --- /dev/null +++ b/skills/dev-impl/SKILL.md @@ -0,0 +1,242 @@ +--- +name: dev-impl +description: This skill should be used when the user asks to "dev-impl", "タスクを実装", "テストファースト実装", "implement task", "実装を開始", "クイック修正", "quick fix", "dev-impl auth 001". TDDをガードレールとしたテストファースト実装を行う。通常モード(Plan+タスク指定)とクイックモード(直接指示)に対応。 +argument-hint: ' | ""' +--- + +# Dev Impl + +TDDをガードレールとして、テストを先に書いてから実装するコアワークフロー。タスクファイルに基づく通常モードと、Plan不要の軽量クイックモードの2つの実行モードを持つ。 + +## 前提知識 + +### dev-*スキルフロー内の位置 + +``` +dev-context → dev-plan → [dev-impl] → dev-verify + ↘ dev-debug (失敗時) +``` + +### 実行モード + +| モード | 引数 | 用途 | +|-------|------|------| +| 通常モード | ` ` | Planのタスクを1つ実装 | +| クイックモード | `"修正指示"` | 軽量な修正・調整(Plan不要) | + +### 品質優先のプライオリティ + +**品質 > 速度 > トークン消費** の順で判断する。 + +## ワークフロー: 通常モード + +`/dev-impl ` で実行。 + +### Step 1: コンテキスト構築(最小限) + +インターフェースファーストで必要最小限のファイルだけ読み込む: + +``` +優先順位: +1. docs/dev/context.md(プロジェクト全体像) +2. タスクファイル(インターフェース定義・テスト方針) +3. 関連する型定義ファイル ← 必要時のみ +4. 関連する既存テストファイル(パターン参考)← 必要時のみ +5. 実装ファイル(関連関数のみ)← 必要時のみ +``` + +TodoWrite でタスク進捗のトラッキングを開始する。 + +### Step 2: テストケース生成(Red) + +タスクファイルの Test Strategy に基づきテストコードを生成する: + +1. 既存テストファイルのパターン(context.mdの規約)に合わせる +2. タスクのインターフェース定義に基づくテストケースを記述する +3. テスト実行コマンド(context.md から取得)でテストを実行する +4. **失敗を確認する**(Red状態) + +テストが先に通ってしまう場合は、要件やテストの妥当性を再確認する。 + +### Step 3: 実装(Green) + +テストを通す最小限の実装を生成する: + +1. インターフェース定義に準拠したコードを書く +2. **Intent コメントを付与する**(後述の「Intent コメントルール」に従う) +3. テスト実行 → **成功を確認する**(Green状態) +4. 失敗した場合はエラーを分析し修正する(最大3サイクル) +5. 3サイクルで解決しない場合は `/dev-debug` の使用を案内する + +### Step 4: リファクタリング + 品質チェック + +テストがGreenの状態で以下を実行する: + +#### 4a. 500行ルール(厳密適用) +関連するすべてのファイルの行数を Bash で確認する(絶対パスを使用): +```bash +wc -l "$(git rev-parse --show-toplevel)/<ファイルの相対パス>" +``` +500行を超えるファイルがある場合: +- 責務の境界で分割する(Single Responsibility Principle) +- テストファイルも対応して分割する +- インポート/エクスポートの整合性を維持する +- 分割後にテストを再実行する + +#### 4b. セキュリティチェック +実装コードを確認し、以下の問題がないか検証する: +- インジェクション(SQL, コマンド, XSS) +- 認証・認可チェックの漏れ +- 機密情報のログ出力・エラーメッセージでの露出 +- ユーザー入力のバリデーション不足 + +#### 4c. パフォーマンスチェック +- N+1問題(ループ内のDB/APIクエリ) +- メモリリーク(イベントリスナー未解除、クロージャ参照保持) +- 非効率なアルゴリズム(O(n^2)以上で改善可能な箇所) + +#### 4d. コード品質 +- 重複コードの排除 +- 命名の改善 +- 不要なコメントの削除 + +#### 4e. カバレッジチェック + +1. `docs/dev/context.md` の Test Framework セクションから Coverage Threshold を取得する +2. タスクファイルの Files セクションから対象パッケージを特定する +3. パッケージごとにカバレッジを計測する(Coverage Command をパッケージ単位で実行) +4. `[no test files]` は 0% として扱う +5. **閾値未達時**: テストを追加し再計測する(最大3サイクル) +6. **3サイクル後も未達**: 🟡 として報告し続行する(ブロッキングにしない) + +テスト再実行 → 成功維持を確認する。 + +### Step 5: 信号機レポート + 完了処理 + +#### 確信度レポートの出力 + +実装した各ファイルに確信度を付与し、ユーザーに報告する: + +```markdown +## dev-impl 確信度レポート + +### カバレッジ結果 +| パッケージ | カバレッジ | 閾値 | 結果 | +|-----------|----------|------|------| +| internal/handler | 85.2% | 80% | OK | + +### 🔵 前工程指示(レビュー低優先) +- [ファイル名](パス) — 既存パターン準拠 + +### 🟡 妥当な推測(要確認) +- [ファイル名](パス) — [確認すべき点] + +### 🔴 AI推論補完(人間の確認必須) +- [ファイル名](パス) — [判断が必要な理由] +``` + +#### 完了処理 +1. タスクファイルの `status` を `done` に更新する +2. TodoWrite を更新する + +### Step 6: Docker クリーンアップ + +プロジェクトルートに `docker-compose.yml` または `docker-compose.yaml` が存在するか確認する。存在する場合: + +1. `docker compose down` を実行してコンテナを停止する +2. 停止に失敗した場合はユーザーに報告する(ブロッキングにしない) + +## ワークフロー: クイックモード + +`/dev-impl "修正指示"` で実行(Plan名なし)。 + +### 用途 +- テストケースの微修正 + 実装の調整 +- 小さなバグ修正 +- 既存テストへのケース追加 +- 軽量なリファクタリング + +### フロー +1. `docs/dev/context.md` を読み込む(あれば) +2. Explore サブエージェント(haiku)で関連ファイルを探索する +3. テスト修正 → 実装修正(またはその逆) +4. テスト実行で検証する +5. 500行ルールのチェック +6. 信号機レポートを簡潔に出力する +7. Docker クリーンアップ(Step 6 と同様) + +## 複雑度に応じた戦略 + +タスクファイルの `estimated_complexity` に応じて戦略を切り替える。詳細は `references/impl-strategies.md` を参照。 + +| 複雑度 | 戦略 | テスト+実装 | +|-------|------|-----------| +| low | バッチ生成 | テスト+実装を一括生成し、テスト実行で検証 | +| medium | 標準サイクル | テスト→Red確認→実装→Green確認 | +| high | 段階的 | 1テストずつ追加→1つずつGreenにする | + +## サブエージェント戦略 + +| 用途 | サブエージェントタイプ | モデル | +|------|---------------------|--------| +| 関連コード探索 | Explore | haiku | +| テスト雛形生成 | general-purpose | haiku | +| 標準実装 | メインで実行 | sonnet | +| 複雑なロジック | メインで実行 | opus | + +## Intent コメントルール + +生成するソースコードの各関数・メソッドに、設計判断の理由を示す Intent コメントを付与する。 + +### 信号機システム(🔵🟡🔴) + +- 🔵 **前工程指示**: タスクファイル・plan.md・context.md で明示的に指示されている設計判断 +- 🟡 **妥当な推測**: 指示された内容から推論した妥当な設計判断(ベストプラクティス準拠等) +- 🔴 **AI推論補完**: 前工程に根拠がなくAIが推論で補完した設計判断 + +### コメント形式 + +言語のコメント構文に従い、関数・メソッドの直前に記述する: + +```go +// 🔵 Intent: タスクファイルで指定された TodoRepository インターフェースを実装。 +// RETURNING 句で INSERT と ID 取得を1クエリで完結させる。 +func (r *PostgresTodoRepository) Create(ctx context.Context, todo *model.Todo) error { +``` + +```go +// 🟡 Intent: context.md のエラーハンドリング規約に準じて fmt.Errorf でラップ。 +// リポジトリ層のエラーをサービス層で識別可能にするため。 +func (s *TodoService) GetByID(ctx context.Context, id string) (*model.Todo, error) { +``` + +```go +// 🔴 Intent: ページネーションのデフォルト値。前工程に指定なし。 +// 一般的な Web API の慣習に基づき limit=20 を採用。 +const defaultPageSize = 20 +``` + +### 付与ルール + +- **すべての public 関数・メソッド** に Intent コメントを付与する +- private 関数は設計判断がある場合のみ付与する(自明な処理は省略可) +- テストコードには付与しない +- 1コメント = 1-2行で簡潔に。冗長な説明は避ける +- 既存コードに追記する場合、既存の Intent コメントを維持する + +## ルール・制約 + +- テストを先に書く。テストが通る前に次のステップに進まない +- すべてのファイルは **500行以内**。超過時はリファクタリングで分割する +- タスクファイルの dependencies に含まれるタスクがすべて `done` であることを確認してから開始する +- context.md が存在しない場合、先に `/dev-context` を案内する +- 通常モードでタスクファイルが存在しない場合、`/dev-plan` を案内する +- テスト実行コマンドは context.md から取得する +- セキュリティ・パフォーマンス問題の 🔴 は修正してから完了する +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) + +## 追加リソース + +### リファレンスファイル + +- **`references/impl-strategies.md`** — 複雑度別の実装戦略、インターフェースファースト読み込みの詳細、バッチモードの適用基準 diff --git a/skills/dev-impl/references/impl-strategies.md b/skills/dev-impl/references/impl-strategies.md new file mode 100644 index 0000000..be12097 --- /dev/null +++ b/skills/dev-impl/references/impl-strategies.md @@ -0,0 +1,174 @@ +# 実装戦略リファレンス + +## 複雑度別の実装戦略 + +### Low(バッチ生成) + +**適用条件**: +- シンプルなCRUD操作 +- ユーティリティ関数 +- 型変換・マッピング +- 既存パターンの踏襲で実装可能 + +**戦略**: +1. タスクファイルのインターフェース定義とTest Strategyを読む +2. テストコードと実装コードを一括で生成する +3. テスト実行で検証する +4. 失敗した場合のみ個別修正サイクルに移行する + +**メリット**: 最速・最少トークン消費 +**リスク**: AIの推論が外れた場合のリワーク + +### Medium(標準Red-Green-Refactorサイクル) + +**適用条件**: +- 通常のビジネスロジック +- 複数の条件分岐を含む処理 +- 外部サービスとの連携(モック使用) +- 既存パターンを参考にしつつ新しい要素が加わる + +**戦略**: +1. テストコードを生成する +2. テスト実行 → Red確認 +3. 実装コードを生成する +4. テスト実行 → Green確認 +5. リファクタリング + +**メリット**: 品質と速度のバランス +**リスク**: 中程度のトークン消費 + +### High(段階的テスト追加・実装) + +**適用条件**: +- 複雑なアルゴリズム +- 複数の外部依存を持つ処理 +- 状態管理が複雑な処理 +- セキュリティクリティカルな処理 + +**戦略**: +1. テストケースを重要度順にソートする +2. 最初の1-2テストケースだけ書く +3. テスト実行 → Red確認 +4. その分だけ実装する +5. テスト実行 → Green確認 +6. 次の1-2テストケースを追加する +7. 2-6を繰り返す +8. 全テストGreen後にリファクタリング + +**メリット**: 最高の品質保証、問題の早期発見 +**リスク**: 最多のトークン消費 + +## インターフェースファースト読み込み + +### 概念 + +コンテキストウィンドウを節約するため、ファイルの読み込みを段階的に行う。まずインターフェース(型定義)だけを読み、必要に応じて実装コードに展開する。 + +### 漸進的コンテキスト展開 + +``` +Step 1: インターフェース/型定義だけ読む + → 実装に必要な情報が足りるか判断 + → 足りる場合: そのまま実装に進む + +Step 2: 足りなければ関連テストファイルを読む + → 使用パターンを把握 + → 足りる場合: 実装に進む + +Step 3: それでも足りなければ実装コードを読む + → 関連する関数/メソッドだけ(ファイル全体は読まない) + → line offset + limit で必要部分だけ読む +``` + +### 言語別のインターフェース探索パターン + +| 言語 | インターフェースの場所 | +|------|-------------------| +| TypeScript | `*.d.ts`, `types/`, `interfaces/`, `type` / `interface` 宣言 | +| Rust | `trait` 定義、`pub struct` のフィールド、`pub fn` シグネチャ | +| Go | `interface` 定義、`struct` フィールド | +| Python | `Protocol` クラス、`@dataclass`、`TypedDict`、型ヒント | +| Java/Kotlin | `interface` / `abstract class`、DTO定義 | + +### Explore サブエージェントでの探索 + +インターフェース探索は Explore サブエージェント(haiku)に委託する: + +``` +Task prompt: "Find all interface/type definitions related to [feature] in this project. +Return only the interface signatures, not implementation details. +Look in: [likely paths from context.md]" +``` + +## バッチモードの適用基準 + +### バッチ生成が安全な条件 + +以下のすべてを満たす場合、テスト+実装の一括生成が安全: + +1. `estimated_complexity: low` である +2. タスクのインターフェースが完全に定義されている +3. 既存コードに同じパターンの実装が存在する +4. 外部依存が少ない(0-1個) +5. テストケースが5個以下 + +### バッチ生成のフォールバック + +バッチ生成後にテストが失敗した場合: +1. 失敗したテストケースのみを分析 +2. 対応する実装箇所を修正 +3. テスト再実行 +4. 2回修正しても通らない場合、標準サイクル(medium戦略)に切り替え + +## 500行ルール 分割ガイド + +### 分割の判断基準 + +ファイルが500行を超えた場合、以下の基準で分割する: + +1. **クラス/モジュールの責務分離**: 複数の責務を持つ場合、責務ごとに分割 +2. **ヘルパー関数の分離**: 汎用的なヘルパーを別ファイルに +3. **型定義の分離**: 型定義が多い場合、`types.ts` 等に分離 +4. **テスト分割**: テスト対象の分割に合わせてテストも分割 + +### 分割後のチェックリスト + +- [ ] 分割後の各ファイルが500行以内 +- [ ] インポート/エクスポートが正しい +- [ ] テストがすべて通る +- [ ] 循環依存がない + +## セキュリティチェック詳細 + +### チェック項目 + +| カテゴリ | チェック内容 | 対象 | +|---------|-----------|------| +| インジェクション | SQL文字列結合、コマンド文字列結合、HTML直接埋め込み | DB操作、シェル実行、テンプレート | +| 認証・認可 | 認証チェックなしのエンドポイント、権限検証の欠如 | APIハンドラ、ミドルウェア | +| データ漏洩 | 機密情報のログ出力、スタックトレースの公開 | ログ、エラーレスポンス | +| 入力検証 | 未検証のユーザー入力、型チェックの欠如 | リクエストハンドラ | + +### 信号機分類 + +- 🔵: 上記すべてのチェックをパス +- 🟡: 潜在的リスクあり(例: 入力検証はあるが不完全) +- 🔴: 明確な脆弱性あり → **修正してから完了する** + +## パフォーマンスチェック詳細 + +### チェック項目 + +| カテゴリ | チェック内容 | 改善方法 | +|---------|-----------|---------| +| N+1 | ループ内でのDB/APIクエリ | バッチクエリに変更 | +| メモリリーク | リスナー未解除、参照保持 | cleanup処理を追加 | +| 再計算 | 同一計算の繰り返し | メモ化、キャッシュ | +| アルゴリズム | O(n^2)以上 | より効率的なアルゴリズムに変更 | +| 同期ブロック | 並列化可能な直列処理 | Promise.all等で並列化 | + +### 信号機分類 + +- 🔵: パフォーマンス問題なし +- 🟡: 小規模データでは問題ないが、スケール時に問題の可能性 +- 🔴: 明確なパフォーマンス問題 → **修正してから完了する** diff --git a/skills/dev-init/SKILL.md b/skills/dev-init/SKILL.md new file mode 100644 index 0000000..e9ad08d --- /dev/null +++ b/skills/dev-init/SKILL.md @@ -0,0 +1,611 @@ +--- +name: dev-init +description: This skill should be used when the user asks to "dev-init", "技術スタックを選定", "新規プロジェクト初期化", "initialize tech stack", "プロジェクトをセットアップ", "setup project", "scaffold project", "プロジェクト作成", "tech stackを決める". インタラクティブなヒアリングでプロジェクトの技術スタックを決定し、dev-context互換のコンテキストファイルを生成する。承認制でプロジェクトスキャフォールディングも実行可能。 +--- + +# Dev Init + +インタラクティブなヒアリングを通じてプロジェクトの技術スタックを決定し、`docs/dev/context.md` を生成する。新規プロジェクトやまだ構成が固まっていないプロジェクト向け。承認後にプロジェクトの骨格ファイル(package.json、設定ファイル、ディレクトリ構造等)も生成可能。 + +既存プロジェクトの自動分析には `dev-context` を使用する。 + +## 前提知識 + +### dev-context との関係 + +``` +dev-init(新規向け・対話型) → docs/dev/context.md + → プロジェクトファイル群(承認制) + → CLAUDE.md(Phase 6) +dev-context(既存向け・自動型)→ docs/dev/context.md + ↓ +dev-plan → dev-impl → dev-verify + ↘ dev-debug(必要時) +``` + +- 出力フォーマットは `dev-context` と完全互換 +- 後続の dev-plan / dev-impl / dev-verify / dev-debug がそのまま参照可能 + +### 信号機システム + +生成するコンテキストファイル・スキャフォールディング結果の各項目に確信度を付与する: + +- 🔵 **前工程指示**: ユーザーが明示的に選択した情報 +- 🟡 **妥当な推測**: 選択結果から推論した補足情報(パッケージマネージャ、Linter等) +- 🔴 **AI推論補完**: 情報不足でAIが仮置きした情報、テンプレート未対応言語の生成ファイル + +## ワークフロー + +### Phase 1: 既存プロジェクト検出 + +以下のファイルの存在を確認する: + +1. `docs/dev/context.md` — 既存コンテキスト +2. `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `build.gradle`, `pom.xml`, `pubspec.yaml`, `build.gradle.kts` — パッケージ定義 + +> **Note:** `CLAUDE.md` の存在確認は Phase 5d(スキャフォールディング時)または Phase 6a-1(CLAUDE.md のみ生成時)で実施する。 + +**分岐ロジック:** + +- `context.md` が存在する場合 → AskUserQuestion で「上書き更新 / 別名保存 / 中止」を確認。別名保存時のファイル名: `context.md.backup.YYYY-MM-DD` +- 「中止」選択時 → 「dev-init を終了しました。既存の context.md を維持します。」と表示してスキルを終了する +- パッケージ定義が存在する場合 → 「既存プロジェクトを検出。`dev-context`(自動分析)を推奨しますが、対話型で進めますか?」と確認 +- いずれもない場合 → Phase 2 へ進む + +> **同時存在時の優先順位:** `context.md` とパッケージ定義が両方存在する場合は、`context.md` の確認(上書き更新 / 別名保存 / 中止)を先に行う。「中止」が選択された場合はスキル終了。「上書き更新」または「別名保存」が選択された場合は、パッケージ定義の検出に関する確認(dev-context 推奨)を続けて行う。 + +### Phase 2: プロジェクト基本情報ヒアリング + +AskUserQuestion ツールで以下を順次ヒアリングする。各質問は1問ずつ提示し、前の回答を次の質問の選択肢構成に反映する。 + +#### Q1: プロジェクトカテゴリ(大分類) + +| 選択肢 | 説明 | +|--------|------| +| Webアプリケーション | ブラウザ向け/モバイル向けWebアプリ(フロントエンド含む) | +| サーバーサイド | API・バッチ処理・分散処理サービス | +| ツール/スクリプト | CLI・GAS等の単機能ツール | +| ライブラリ/パッケージ | 他プロジェクトから利用されるライブラリ | + +#### Q2: プロジェクトタイプ(詳細分類) + +Q1 の回答に応じて条件分岐する。ライブラリ/パッケージの場合は Q2 をスキップし自動確定する。 + +| Q1 の回答 | Q2 の選択肢 | +|-----------|------------| +| Webアプリケーション | フルスタック(一体型) / 3層アーキテクチャ(TypeScriptフロント+API+DB) / BFFアーキテクチャ(UI+BFF+サービス+DB) | +| サーバーサイド | APIサーバー / バッチ処理 / マイクロサービス / イベント駆動 | +| ツール/スクリプト | CLIツール / GAS(Google Apps Script) | +| ライブラリ/パッケージ | Q2 スキップ(自動確定) | + +> **3層アーキテクチャ選択時の自動通知**: Q2回答直後、Q5に進む前に以下を表示する: +> 「3層アーキテクチャのため、以下が自動設定されます: フロントエンド言語: TypeScript(固定) / プロジェクト構成: モノレポ(packages/frontend + packages/backend + packages/shared)」 + +> **BFFアーキテクチャ選択時の自動通知**: Q2回答直後、Q3に進む前に以下を表示する: +> 「BFFアーキテクチャのため、以下が自動設定されます: プロジェクト構成: モノレポ」 + +#### Q3: UIターゲット(BFF のみ) + +BFFアーキテクチャ選択時のみ質問する。他のタイプではスキップ。 + +| 選択肢 | 説明 | +|--------|------| +| Webのみ | ブラウザ向けWebアプリ | +| モバイルのみ | iOS/Android モバイルアプリ | +| Web + モバイル | 両方に対応(BFFで共通API提供) | + +> モバイル選択時のフレームワークは、Q5a の言語選択に応じた推奨を提示する(Dart → Flutter(Recommended)/Other、TypeScript(RN) → React Native(Recommended)/Expo/Other) + +> BFFアーキテクチャ選択時、Q3の後にQ4(サービス層構成: 単一サービス/複数サービス)を質問する。詳細はQ4セクション参照。 + +#### Q4: タイプ固有質問 + +プロジェクトタイプに応じた追加質問を行う。バッチ処理・マイクロサービス・イベント駆動ではQ6の前(Q5の後)に実施し、BFFではQ3の直後に実施し、GASではQ2の直後(Q5/Q6スキップのため)に実施する。該当タイプ以外ではスキップする。 + +**Q4: サービス層構成(BFF のみ)** + +> BFFでは本質問をQ3の直後(技術選定の前)に実施する。 + +| 選択肢 | 説明 | +|--------|------| +| 単一サービス | BFF + 1サービスで開始。後から分割可能 | +| 複数サービス | 初期から services/service-a, services/service-b 等の構成 | + +**Q4b: 初期サービス構成(BFF 複数サービス選択時のみ)** + +| 選択肢 | 説明 | +|--------|------| +| 2サービス(デフォルト) | service-a, service-b の2サービスで開始 | +| カスタム | サービス名をカンマ区切りで入力(例: user-service, order-service)。kebab-case | + +**Q4: スケジューリング方式(バッチ処理のみ)** + +| 選択肢 | 説明 | +|--------|------| +| cron / OS スケジューラ | システムの cron や systemd timer で定期実行 | +| クラウドスケジューラ | Cloud Scheduler / EventBridge 等で実行 | +| フレームワーク内蔵 | BullMQ / Celery Beat 等ジョブキュー型 | + +**Q4: サービス間通信(マイクロサービスのみ)** + +| 選択肢 | 説明 | +|--------|------| +| REST API | HTTP ベースの同期通信 | +| gRPC | Protocol Buffers ベースの高効率通信 | +| メッセージキュー | 非同期メッセージング(Kafka / RabbitMQ 等) | + +**Q4c: メッセージブローカー(マイクロサービスでメッセージキュー選択時のみ)** + +> マイクロサービスの Q4 で「メッセージキュー」を選択した場合のみ質問する。 + +| 選択肢 | 説明 | +|--------|------| +| Apache Kafka | 高スループット・ストリーム処理 | +| RabbitMQ | 汎用メッセージブローカー | +| AWS SQS + SNS | AWSマネージドキュー | +| Redis Pub/Sub | 軽量・リアルタイム | + +**Q4b: 初期サービス構成(マイクロサービスのみ)** + +> マイクロサービスではQ4(サービス間通信)→ Q4b(初期サービス構成)→ Q6 の順で実施する。アーキテクチャ設計(通信方式+サービス構成)を一括で聞いた後、技術選定(FW)に進む。 + +| 選択肢 | 説明 | +|--------|------| +| 2サービス(デフォルト) | service-a, service-b の2サービスで開始 | +| 単一サービス | 1サービスで開始し、後から追加 | +| カスタム | サービス数・名前を自由入力 | + +**Q4: メッセージブローカー(イベント駆動のみ)** + +| 選択肢 | 説明 | +|--------|------| +| Apache Kafka | 高スループット・ストリーム処理 | +| RabbitMQ | 汎用メッセージブローカー | +| AWS SQS + SNS | AWSマネージドキュー | +| Redis Pub/Sub | 軽量・リアルタイム | + +**Q4: GAS デプロイ形態(GAS のみ)** + +| 選択肢 | 説明 | +|--------|------| +| スタンドアロン | 独立したスクリプトプロジェクト | +| スプレッドシート連携 | Google Sheets のカスタム関数・メニュー | +| Webアプリ | doGet/doPost による HTTP エンドポイント | + +#### Q5: 言語選択 + +プロジェクトタイプに応じて質問構成が変わる。 + +**共通の言語選択肢:** + +| 選択肢 | 説明 | +|--------|------| +| TypeScript | Node.js/Deno/Bun 向け | +| Python | FastAPI/Django/Flask 等 | +| Rust | 高パフォーマンス・システム | +| Go | マイクロサービス・CLI | +| Java | Spring Boot/Quarkus 等 | +| Kotlin | Ktor/Spring Boot(Kotlin) 等 | +| Dart | Flutter/dart_frog 等 | + +**Q5 の条件分岐:** + +- **GAS 選択時**: Q5 をスキップし TypeScript を自動選定 +- **3層アーキテクチャ選択時**: Q5 のみ質問。質問文は「バックエンドの主要言語を選択してください」。UI層は TypeScript 自動選定 +- **BFFアーキテクチャ選択時**: Q5a/Q5b/Q5c の3段階に分割(下記参照) +- **その他のタイプ**: Q5 のみ質問(「主要言語を選択してください」) + +**BFF の Q5 分割:** + +各レイヤーの言語選択(Q5a/Q5b/Q5c)後、対応するフレームワーク(Q6a/Q6b/Q6c)を連続して質問する。UI層(Q5a→Q6a)→ BFF層(Q5b→Q6b)→ サービス層(Q5c→Q6c)の順で進む。 + +- **Q5a(UI層言語)**: Q3(UIターゲット)に応じて分岐 + - Webのみ → TypeScript 自動選定(スキップ) + - モバイルのみ → 質問(Dart / TypeScript(React Native)) + - Web+モバイル → Web は TypeScript 自動選定、モバイル側を質問(Dart / TypeScript(React Native)) +- **Q5b(BFF層言語)**: 全言語から選択。TypeScript に「(Recommended)」ラベル +- **Q5c(サービス層言語)**: 全言語から選択(従来と同等) + +### Phase 3: 技術詳細ヒアリング + +Phase 2 の回答に基づいて動的に質問を構成する。`references/tech-recommendations.md` の推奨マトリクスを参照し、言語×プロジェクトタイプに応じた選択肢を提示する。 + +> BFFアーキテクチャでは、各レイヤーの言語(Q5)とフレームワーク(Q6)をペアで連続して質問する。UI層(Q5a→Q6a)→ BFF層(Q5b→Q6b)→ サービス層(Q5c→Q6c)の順で進む。 + +> 3層アーキテクチャでは、Q5(バックエンド言語)→ Q6(バックエンドFW)を直結させた後、Q6a(フロントエンドFW)を質問する。この順序は「言語選択とFW選択の認知的連続性」を優先するため: バックエンドは言語+FWの2つの決断が必要な一方、フロントエンドはFWのみ(言語はTypeScript固定)のため、決断負荷が重い方を先に片付ける設計。 + +#### Q6: フレームワーク + +言語とプロジェクトタイプの組み合わせに応じて、推奨マトリクスから選択肢を動的構成する。推奨表の「推奨1」を先頭に配置し、ラベルに「(Recommended)」を付与する。 + +- **ライブラリ/パッケージ**: Q6 をビルド/バンドラツールとして質問する。言語に応じた選択肢を提示: + - TypeScript: tsup(Recommended)/ unbuild / rollup / tsc のみ + - Python: hatchling(Recommended)/ setuptools / flit + - Rust: スキップ(cargo 標準) + - Go: スキップ(go build 標準) + - Java: Gradle(Recommended)/ Maven + - Kotlin: Gradle(Recommended) + - Dart: スキップ(pub 標準) + +**Q6 の条件分岐:** + +- **3層アーキテクチャ**: Q6(バックエンドFW: Q5言語の直後に質問)+ Q6a(フロントエンドFW: TypeScript Webアプリの推奨マトリクスから)に分割 +- **BFFアーキテクチャ**: Q6a/Q6b/Q6c の3段階に分割(下記参照) +- **GAS**: Q6 スキップ(clasp + esbuild を自動選定) +- **バッチ処理**: Q4(スケジューリング方式)の回答を考慮し、該当タイプの推奨マトリクスから構成 +- **マイクロサービス**: Q4(サービス間通信)の回答を考慮し、該当タイプの推奨マトリクスから構成。gRPC選択時はgRPC対応FWを優先推奨する +- **イベント駆動**: Q4(メッセージブローカー)の回答に基づき、選択したブローカーに対応するクライアントライブラリ付きFWを推奨マトリクスから構成。推奨マトリクスの「イベント駆動」行から、Q4で選択したブローカーに対応するFW+ライブラリの組み合わせを提示する + +**BFF の Q6 分割:** + +各Q6はQ5と対になるレイヤーの言語選択直後に質問する(Q5a→Q6a→Q5b→Q6b→Q5c→Q6cの順)。 + +- **Q6a(UI FW)**: Q3(UIターゲット)× Q5a言語に応じた推奨マトリクスから + - Webのみ → TypeScript Webアプリの推奨マトリクスから選択 + - モバイルのみ → Q5a言語に応じたモバイルFW推奨から選択(Q5a=Dart: Flutter(Recommended)/Other、Q5a=TypeScript(RN): React Native(Recommended)/Expo/Other) + - Web+モバイル → Q6a を2問に分割: Q6a-mobile(Q5a言語のモバイルFW推奨から。Q5a の直後にペアで質問)+ Q6a-web(TypeScript WebアプリFW推奨マトリクスから) +- **Q6b(BFF FW)**: Q5b言語の BFF(BFF層)推奨マトリクスから +- **Q6c(サービス層FW)**: Q5c言語の BFF(サービス層)推奨マトリクスから + +#### Q7: チーム規模・開発フェーズ + +| 選択肢 | 説明 | +|--------|------| +| 個人・プロトタイプ | 迅速な立ち上げ優先 | +| 小規模チーム(2-5人) | バランス重視 | +| 中〜大規模チーム(6人以上) | 堅牢性・標準化重視 | + +#### Q8: データベース + +CLIツール・GAS・ライブラリ/パッケージ以外の場合に質問する。 + +| 選択肢 | 説明 | +|--------|------| +| PostgreSQL(Recommended) | 汎用RDBMS | +| SQLite | 軽量・組み込み | +| MongoDB | ドキュメントDB | +| なし | DB不要 | + +#### Q9: テストフレームワーク + +言語に応じて推奨表から選択肢を構成する。推奨デフォルトを先頭に配置する。 + +**Q9 の条件分岐:** + +- **単一言語プロジェクト**(フルスタック / APIサーバー / バッチ処理 / マイクロサービス / イベント駆動 / CLIツール / GAS / ライブラリ): Q5 言語の推奨テストFWから選択肢を構成(従来通り) +- **3層アーキテクチャ(Q5 = TypeScript の場合)**: 全層 TypeScript のため、Vitest を推奨デフォルトとして1問で質問(従来通り) +- **3層アーキテクチャ(Q5 ≠ TypeScript の場合)**: 各層の言語からテストFW推奨表を自動引き当てし、一覧を提示して確認を求める。質問文: 「テストフレームワーク(自動選定): フロントエンド (TypeScript): Vitest / バックエンド ([Q5言語]): [推奨FW]。この構成でよろしいですか?」選択肢: 「この構成で進める(Recommended)」/「変更する」。「変更する」選択時は各層のテストFWを個別に質問する +- **BFF(全層同一言語の場合)**: 1問で質問(従来通り)。同一言語判定: Q3=Webのみの場合は TypeScript(自動) + Q5b + Q5c が全てTypeScriptかで判定。Q3=モバイルのみの場合は Q5a + Q5b + Q5c で判定。Q3=Web+モバイルの場合は TypeScript(Web自動) + Q5a + Q5b + Q5c が全て同一かで判定(Web側がTypeScript固定のため、全層同一はQ5a=TypeScript(RN) かつ Q5b=TypeScript かつ Q5c=TypeScript の場合のみ成立) +- **BFF(混合言語の場合)**: 各層の言語からテストFW推奨表を自動引き当てし、一覧を提示して確認を求める。質問文はQ3の回答に応じて構成する: + - Q3=Webのみ/モバイルのみ: 「テストフレームワーク(自動選定): UI層 ([Q5a言語]): [推奨FW] / BFF層 ([Q5b言語]): [推奨FW] / サービス層 ([Q5c言語]): [推奨FW]。この構成でよろしいですか?」 + - Q3=Web+モバイル: 「テストフレームワーク(自動選定): UI層-Web (TypeScript): Vitest / UI層-Mobile ([Q5a言語]): [推奨FW] / BFF層 ([Q5b言語]): [推奨FW] / サービス層 ([Q5c言語]): [推奨FW]。この構成でよろしいですか?」 + - 選択肢: 「この構成で進める(Recommended)」/「変更する」 + +**Q9「変更する」選択時のサブフロー:** + +- **3層アーキテクチャ**: 以下の2問を順次質問する + 1. Q9-front: フロントエンドのテストFW(TypeScript推奨表から選択肢構成。変更前のデフォルト値に「(現在の選定)」ラベル付与) + 2. Q9-back: バックエンドのテストFW(Q5言語推奨表から選択肢構成) +- **BFF(Q3=Webのみ/モバイルのみ)**: 以下の3問を順次質問する + 1. Q9-ui: UI層のテストFW(Q5a言語推奨表から) + 2. Q9-bff: BFF層のテストFW(Q5b言語推奨表から) + 3. Q9-service: サービス層のテストFW(Q5c言語推奨表から) +- **BFF(Q3=Web+モバイル)**: 以下の4問を順次質問する + 1. Q9-ui-web: UI層-WebのテストFW(TypeScript推奨表から) + 2. Q9-ui-mobile: UI層-MobileのテストFW(Q5a言語推奨表から) + 3. Q9-bff: BFF層のテストFW(Q5b言語推奨表から) + 4. Q9-service: サービス層のテストFW(Q5c言語推奨表から) + +#### Q10: 開発環境のDocker化 + +CLIツール・GAS・ライブラリ/パッケージ以外の場合に質問する。 + +| 選択肢 | 説明 | +|--------|------| +| Docker開発環境(Recommended) | 全サービスをdocker-composeで管理。DB・テストツール含む | +| Dockerなし | ローカルにランタイムをインストールして開発 | + +- Docker選択時、Q8でDB選択済みなら自動でDBサービスを含める +- Webアプリ + Docker選択時、playwrightサービスも自動追加 +- マイクロサービス・イベント駆動・BFFの場合、Docker 選択肢の説明を「Strongly Recommended」に変更 + +#### Q11: 追加ツール・要件(複数選択) + +| 選択肢 | 説明 | +|--------|------| +| CI/CD(GitHub Actions) | 自動テスト・デプロイ | +| モノレポ構成 | 複数パッケージの統合管理 | + +**Q11 の条件分岐:** + +- **3層アーキテクチャ**: 「モノレポ構成」を自動選択(構造上必須のため質問不要)。Q11 の質問文に「※ モノレポ構成は3層アーキテクチャのため自動適用されます」と明記する +- **BFFアーキテクチャ**: 「モノレポ構成」を自動選択(構造上必須のため質問不要)。Q11 の質問文に「※ モノレポ構成はBFFアーキテクチャのため自動適用されます」と明記する +- **マイクロサービス**: 「モノレポ構成」に「(Recommended)」ラベル付与 +- **ライブラリ/パッケージ**: 「モノレポ構成」に加え、「パッケージ公開設定(npm publish / cargo publish / PyPI upload 等)」を選択肢に追加する +- **CLIツール**: 「モノレポ構成」を除外し、「CI/CD(GitHub Actions)」のみ提示する +- **GAS**: CLIツールと同様、「モノレポ構成」を除外し、「CI/CD(GitHub Actions)」のみ提示する + +> **Note:** Linter/Formatter および PM(パッケージマネージャ)は Q5(言語)の選択に基づき常に自動選定される(`references/tech-recommendations.md` の Linter/Formatter 推奨表・PM 推奨表参照)。Q5 回答後、次の質問に進む前に「言語選択に基づく自動設定: Linter: [値] / Formatter: [値] / PM: [値]」を通知する。GAS の場合は Q2 直後のまとめ通知に含まれるため個別通知は不要。 + +> **Note:** 混合言語 BFF では pnpm ワークスペースではなく Makefile + Docker Compose ベースのモノレポ構成になる場合がある。Q5a・Q5b・Q5c が全て同一言語(TypeScript)の場合のみ pnpm ワークスペースを使用する。 + +### 質問フロー一覧(全体像) + +``` +フルスタック: Q1→Q2→Q5→Q6→Q7→Q8→Q9→Q10→Q11 +3層Web: Q1→Q2→Q5→Q6→Q6a→Q7→Q8→Q9→Q10→Q11 +BFF: Q1→Q2→Q3→Q4→Q5a→Q6a→Q5b→Q6b→Q5c→Q6c→Q7→Q8→Q9→Q10→Q11 +APIサーバー: Q1→Q2→Q5→Q6→Q7→Q8→Q9→Q10→Q11 +バッチ処理: Q1→Q2→Q5→Q4→Q6→Q7→Q8→Q9→Q10→Q11 +マイクロサービス: Q1→Q2→Q5→Q4→Q4b→Q6→Q7→Q8→Q9→Q10→Q11 +イベント駆動: Q1→Q2→Q5→Q4→Q6→Q7→Q8→Q9→Q10→Q11 +CLIツール: Q1→Q2→Q5→Q6→Q7→Q9→Q11 +GAS: Q1→Q2→Q4→Q7→Q9→Q11 +ライブラリ: Q1→Q5→Q6→Q7→Q9→Q11 +``` +> マイクロサービスでメッセージキュー選択時、Q4の後にQ4cでブローカーを指定 +> BFF複数サービス選択時、Q4の後にQ4bでサービス構成を指定 +> BFF Web+モバイル時、Q6a は Q6a-mobile + Q6a-web の2問に分割 + +> 非BFFタイプの Q5 は「主要言語」として1問のみ質問。3層アーキテクチャでは「バックエンドの主要言語」として質問する。BFFでは Q5a/Q5b/Q5c の3段階に分割される。 + +> 非BFF・非3層タイプの Q6 は「フレームワーク」として1問のみ質問。推奨マトリクスの該当タイプ×Q5言語の行から選択肢を構成する。3層アーキテクチャでは Q6(バックエンドFW)+ Q6a(フロントエンドFW)に分割される。BFFでは Q6a/Q6b/Q6c の3段階に分割される。ライブラリ/パッケージではビルド/バンドラツールとして質問する。 + +### Phase 4: コンテキスト生成 + +全ヒアリング結果を統合し、`docs/dev/context.md` を生成する。 + +#### 4a. ディレクトリ準備 + +```bash +mkdir -p "$(git rev-parse --show-toplevel)/docs/dev" +``` + +#### 4b. context.md 生成 + +`dev-context` の `references/context-template.md`(`.claude/skills/dev-context/references/context-template.md`)と同じフォーマットで生成する。テンプレートの各セクションを以下のように埋める: + +- **Tech Stack**: Q5(言語)、Q6(フレームワーク)、PM は推奨表からデフォルト選定。3層の場合はフロントエンド・バックエンド各層の言語・FW情報を記載。BFFの場合はUI層(Q5a/Q6a)、BFF層(Q5b/Q6b)、サービス層(Q5c/Q6c)の各層情報を記載。PM は各層の言語に応じた推奨 PM をそれぞれ選定 +- **Test Framework**: Q9 の選択結果、テストコマンドは推奨表から自動設定 +- **Project Structure**: 言語×タイプに応じた推奨ディレクトリ構造を `references/tech-recommendations.md` から取得(3層/BFF/バッチ/マイクロサービス/イベント駆動/GAS の新テンプレートを含む) +- **Coding Conventions**: 言語のデフォルト規約を推奨表から設定(🟡マーク) +- **Key Entry Points**: ディレクトリ構造テンプレートに基づく想定エントリポイント(🟡マーク) +- **Build & Run**: 推奨表からデフォルトコマンドを設定 +- **Docker Environment**: Q10 で Docker 開発環境を選択した場合、`references/docker-dev-templates.md` を参照して Docker Environment セクションを生成。Docker 選択時は Build & Run セクションのコマンドを `docker compose exec app ` 形式に変更 +- **Additional Notes**: Q11 の追加ツール情報、チーム規模に応じた注意点、タイプ固有質問(Q3/Q4)の回答内容を反映。混合言語 BFF では shared の型定義を言語中立な形式(OpenAPI / Protocol Buffers)で管理することを推奨する旨を追記 + +ヘッダーは以下のように記載する: + +```markdown +> Generated by dev-init. Last updated: YYYY-MM-DD +> Confidence: 🔵 = user selected, 🟡 = inferred from selection, 🔴 = AI assumption +``` + +#### 4c. 結果サマリーと次のステップ + +生成完了後、以下を表示する: + +1. 選択した技術スタックのサマリー(表形式) +2. 推奨ディレクトリ構造(`references/tech-recommendations.md` から該当テンプレート) +3. 次のステップの案内(以下の3択を提示): + - Phase 5(スキャフォールディング + CLAUDE.md 生成)へ進む + - Phase 5 をスキップして Phase 6(CLAUDE.md のみ生成)へ進む + - Phase 5・6 をスキップ(context.md のみで終了) + +### Phase 5: プロジェクトスキャフォールディング(承認制) + +#### 5a. スキャフォールディング実行確認 + +Phase 4 完了後、AskUserQuestion で確認する: +- 「プロジェクトの骨格ファイル(設定ファイル、エントリポイント、CLAUDE.md 等)を生成しますか?」 +- 選択肢: 「生成する」/「スキップして CLAUDE.md のみ生成(Phase 6)」/「スキップ(context.md のみで終了)」 +- 「スキップして CLAUDE.md のみ生成」の場合 → Phase 6 へ進む +- 「スキップ」の場合 → `dev-plan` での要件定義・タスク分解を案内して終了(従来動作) + +#### 5b. 生成方式の決定 + +選択した言語の scaffolding ファイル(`references/-scaffolding.md`)を参照: + +- CLI ツールがある FW の場合 → AskUserQuestion で「CLI 利用 / 直接生成」を提示 +- CLI がない場合 → 直接生成 +- scaffolding ファイルが存在しない言語 → 直接生成(全ファイルに 🔴 マーク + 「テンプレート未対応」警告表示) + +#### 5c. ファイル一覧の構築と承認 + +scaffolding ファイルを参照し、生成予定ファイルのツリーを構築する。 + +**常に生成するファイル:** +- `.gitignore`, `README.md` +- パッケージ定義ファイル(package.json / Cargo.toml / go.mod / pyproject.toml / build.gradle.kts / pubspec.yaml) +- コンパイラ/ランタイム設定ファイル +- エントリポイントファイル +- テストファイル(スモークテスト) +- Linter/Formatter 設定ファイル(Q5 の言語選択に基づき自動選定。`references/tech-recommendations.md` の推奨表に従う) +- `CLAUDE.md` — プロジェクトルールと開発コマンドの指示書(`references/claudemd-template.md` に基づく) + +**モノレポ構成時(3層Web / BFF / マイクロサービス)に追加生成:** +- サブパッケージ `CLAUDE.md` — 各パッケージルートに配置(`references/claudemd-template.md` の「サブパッケージ CLAUDE.md テンプレート構造」に基づく)。生成対象は後述の 5d のパッケージ判定ロジックに従う + +**Q10 Docker開発環境選択時のみ生成:** +- `docker-compose.yml` — 開発環境全体定義(`references/docker-dev-templates.md` を参照して構成) +- `Dockerfile.dev` — 開発用Dockerfile(hot-reload対応、volume mount前提) +- `Dockerfile` — デプロイ用(従来通り) +- `.dockerignore` + +**Q11 選択時のみ生成:** +- CI/CD 選択時: `.github/workflows/ci.yml` + +AskUserQuestion でファイルツリーを提示 → 「生成する / ファイルを修正する / 中止する」 + +#### 5d. ファイル生成実行 + +- **CLI 選択時**: scaffolding ファイルに記載された非対話フラグ付きで CLI 実行 → 不足ファイルを補完生成 +- **直接生成時**: ディレクトリ作成 → パッケージ定義 → 設定ファイル → エントリポイント → テストファイル → Docker/CI → .gitignore/README の順で生成 +- 各ファイル生成時に scaffolding ファイルの決定ガイド(依存パッケージ表、設定項目等)を参照 +- **CLAUDE.md 生成**: `references/claudemd-template.md` と Q1-Q11 の回答に基づき、スキャフォールディングの最後に CLAUDE.md を生成する。既存の CLAUDE.md がある場合は Phase 1 で検出済みのため、上書き/バックアップ/スキップの判断に従う。生成ルールは Phase 6 の 6b に準拠する +- **サブパッケージ CLAUDE.md 生成**: モノレポ構成時、ルート CLAUDE.md 生成後に各サブパッケージの CLAUDE.md を生成する。生成ルールは Phase 6 の 6b-2 に準拠する。パッケージ判定ロジック: + +| アーキテクチャ | Q3の回答 | 生成対象パッケージ | 生成しない | +|--------------|---------|-----------------|-----------| +| 3層Web | — | `packages/frontend/`, `packages/backend/` | `packages/shared/` | +| BFF(単一) | Webのみ | `packages/web-ui/`, `packages/bff/`, `packages/service/` | `packages/shared/` | +| BFF(単一) | モバイルのみ | `packages/mobile-ui/`, `packages/bff/`, `packages/service/` | `packages/shared/` | +| BFF(単一) | Web+モバイル | `packages/web-ui/`, `packages/mobile-ui/`, `packages/bff/`, `packages/service/` | `packages/shared/` | +| BFF(複数) | Webのみ | `packages/web-ui/`, `packages/bff/`, 各 `services//` | `packages/shared/` | +| BFF(複数) | モバイルのみ | `packages/mobile-ui/`, `packages/bff/`, 各 `services//` | `packages/shared/` | +| BFF(複数) | Web+モバイル | `packages/web-ui/`, `packages/mobile-ui/`, `packages/bff/`, 各 `services//` | `packages/shared/` | +| マイクロサービス | — | 各 `services//` | `packages/shared/` | + +> **Note:** マイクロサービスで Q11 モノレポ未選択の場合、サブパッケージ生成は発動しない + +#### 5e. 依存インストールと検証 + +scaffolding ファイルの「検証コマンド」セクションに従い: + +**Q10 で Docker 開発環境を選択した場合:** +- `docker compose up -d` でコンテナを起動(未起動の場合) +- 以下の検証コマンドはすべて `docker compose exec app ` 形式で実行 + +**検証手順:** +1. パッケージマネージャで依存インストール +2. テスト実行 +3. ビルド確認 +4. Lint 確認 +5. 失敗時 → エラー分析 → 修正 → 再実行(最大3リトライ) +6. 3回失敗 → 残存問題を 🔴 でレポートに報告 + +#### 5f. スキャフォールディングレポート + +生成完了後、以下を表示する: + +1. 生成ファイル一覧 + 確信度(🔵🟡🔴)— CLAUDE.md・サブパッケージ CLAUDE.md を含む +2. 検証結果(依存インストール / ビルド / テスト / Lint) +3. ルート CLAUDE.md の生成結果(行数、含まれるセクション一覧) +4. サブパッケージ CLAUDE.md の生成結果(各パッケージのパス・行数)。`packages/shared/` は「手動追加可能」と案内 +5. 「必要に応じて CLAUDE.md を手動編集し、プロジェクト固有のルールを追加してください」の案内 +6. 次のステップ: `dev-plan` での要件定義・タスク分解の案内 + +### Phase 6: CLAUDE.md 生成(スキャフォールディングをスキップした場合) + +Phase 5 でスキャフォールディングを実行した場合、CLAUDE.md は Phase 5d で自動生成されるため、このフェーズはスキップする。Phase 5 をスキップした場合(context.md のみ生成した場合)にのみ、このフェーズを実行する。 + +#### 6a-1. ルート CLAUDE.md 存在確認 + +プロジェクトルートの `CLAUDE.md` の有無を確認する。 + +- `CLAUDE.md` が存在しない場合 → 6b へ進む +- `CLAUDE.md` が存在する場合 → AskUserQuestion で以下を確認: + - 「上書き」— 既存ファイルを新しい内容で置き換え + - 「バックアップ保存して新規作成」— `CLAUDE.md.backup.YYYY-MM-DD` にリネーム後、新規作成 + - 「スキップ」— CLAUDE.md 生成をスキップし、6d の最終サマリーへ + +#### 6a-2. サブパッケージ CLAUDE.md 存在確認 + +モノレポ構成(3層Web / BFF / マイクロサービス)の場合、5d のパッケージ判定ロジックに基づき各サブパッケージの `CLAUDE.md` の有無を確認する。 + +- サブパッケージ `CLAUDE.md` が1つも存在しない場合 → 6b-2 へ進む +- 一部または全部が存在する場合 → AskUserQuestion で以下を確認: + - 「全て上書き」— 既存ファイルを新しい内容で置き換え + - 「未作成のみ生成」— 既存のサブパッケージ CLAUDE.md はスキップし、未作成のもののみ生成 + - 「スキップ」— サブパッケージ CLAUDE.md 生成をスキップ + +#### 6b-1. ルート CLAUDE.md 生成 + +`references/claudemd-template.md` と Q1-Q11 の回答から CLAUDE.md を生成する。各セクションの構成: + +- **Project Overview**: Q1/Q2(プロジェクトタイプ)+ Q5(言語)+ Q6(フレームワーク)から1-2行で構成 +- **Development Commands**: `references/claudemd-template.md` のコマンド導出テーブル + scaffolding ファイルからコマンドを導出。Q10 で Docker 選択時は `docker compose exec app` プレフィクスを付与し、Docker 操作コマンド(up/down/logs)も追加 +- **Code Style**: `references/claudemd-template.md` の言語別デフォルト + Q7(チーム規模)で記載量・厳格度を調整 +- **Project Rules**: Q6 フレームワーク固有ルール(ディレクトリ配置等)+ Q9 テスト規約 + Q10 Docker 規約 + Q11 追加ツール規約 +- **Language**: 「日本語でコミュニケーションする。」 + +生成時の制約: +- **80行以内** に収める(`references/claudemd-template.md` の圧縮優先順位に従う) +- **指示的な言語** を使用する(「〜を使う」「〜しない」) +- **context.md の内容を重複させない**(詳細は context.md に委ね、コマンドとルールに集中) +- **信号機システムは使わない**(CLAUDE.md は指示書であり検出結果ではない) +- コマンドは **コピペ可能な正確なコマンド** を記載する + +#### 6b-2. サブパッケージ CLAUDE.md 生成 + +モノレポ構成時、ルート CLAUDE.md 生成後に各サブパッケージの CLAUDE.md を生成する。`references/claudemd-template.md` の「サブパッケージ CLAUDE.md テンプレート構造」「サブパッケージ Development Commands 導出テーブル」「サブパッケージ Package Rules テンプレート」に基づく。 + +**生成対象パッケージの判定:** +- 5d のパッケージ判定ロジックに従い、アーキテクチャに応じた対象パッケージを特定する +- `packages/shared/` は生成しない(レポートに「手動追加可能」と案内) +- マイクロサービスで Q11 モノレポ未選択の場合は生成しない + +**各サブパッケージ CLAUDE.md の構成:** +- **パッケージ名と役割**: パッケージ名(ディレクトリ名)+ 使用フレームワーク + 1行の役割説明 +- **Development Commands**: `references/claudemd-template.md` の「サブパッケージ Development Commands 導出テーブル」からパッケージローカルコマンドを導出。Q10 Docker 選択時は `docker compose exec app` プレフィクスを付与 +- **Code Style**(混合言語時のみ): ルートと異なる言語のパッケージにのみ記載。同一言語判定: BFF の同一言語判定は Q3 の回答に応じて行う。Q3=Webのみの場合は TypeScript(自動) + Q5b + Q5c が全てTypeScriptかで判定。Q3=モバイルのみの場合は Q5a + Q5b + Q5c で判定。Q3=Web+モバイルの場合は TypeScript(Web自動) + Q5a + Q5b + Q5c が全て同一かで判定(Web側がTypeScript固定のため、全層同一はQ5a=TypeScript(RN) かつ Q5b=TypeScript かつ Q5c=TypeScript の場合のみ成立)。3層で Q5 が TypeScript なら同一言語、それ以外なら混合言語(Code Style 追加) +- **Package Rules**: `references/claudemd-template.md` の「サブパッケージ Package Rules テンプレート」からパッケージ役割に応じたルールを記載 + +**生成時の制約:** +- **30行以内** に収める(`references/claudemd-template.md` の「30行制限の圧縮ガイド」に従う) +- ルート CLAUDE.md と内容を **重複させない**(ルートに記載済みの共通ルールは省略) +- Language セクションは **記載しない**(ルートで定義済み) + +#### 6c. 結果表示 + +生成完了後、以下を表示する: + +1. ルート CLAUDE.md の行数と含まれるセクション一覧 +2. サブパッケージ CLAUDE.md の生成結果(モノレポ構成時のみ): + - 各パッケージのパスと行数(例: `packages/frontend/CLAUDE.md` — 12行) + - `packages/shared/` は「必要に応じて手動で CLAUDE.md を追加してください」と案内 +3. 「必要に応じて CLAUDE.md を手動編集し、プロジェクト固有のルールを追加してください」の案内 + +#### 6d. 最終サマリー + +全 Phase の統合サマリーを表示する: + +1. 技術スタック概要(Q1-Q11 の結果要約) +2. 生成ファイル一覧(context.md、CLAUDE.md、スキャフォールディングファイル) +3. 次のステップ: `dev-plan` での要件定義・タスク分解の案内 + +## ルール・制約 + +- 全ての質問は **AskUserQuestion** ツールで提示する +- 質問は **1問ずつ順次** 提示し、前の回答を次の選択肢に反映する +- 出力フォーマットは `dev-context` の `context-template.md` と **完全互換** +- `context.md` は **500行以内** に収める +- Phase 4 までは `context.md` と `docs/dev/` のみ生成する +- Phase 5 はユーザーの **明示的な承認後にのみ** 実行する +- CLI 使用時は **非対話モード**(フラグ指定)のみ使用する +- 検証(5e)は **最大3リトライ** で打ち切る +- scaffolding ファイルが存在しない言語は全ファイルに **🔴 マーク必須** +- 生成する全ファイルは **500行以内** に収める +- 「Other」による自由入力を常に許容する(AskUserQuestion の標準機能) +- 既存の `docs/dev/plans/` 配下のファイルには影響を与えない +- 推奨マトリクスに該当しない言語・FWの組み合わせでも、ユーザー入力を尊重して context.md を生成する +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- CLAUDE.md は **80行以内** に収める(`references/claudemd-template.md` の圧縮優先順位に従う) +- CLAUDE.md では **指示的な言語** を使用する(「Xを使う」「Xしない」)— 記述的ではなく命令的 +- CLAUDE.md に **context.md の内容を重複させない**(詳細は context.md に委ねる) +- CLAUDE.md に **信号機システムは使わない**(CLAUDE.md は指示書であり検出結果ではない) +- CLAUDE.md のコマンドは **コピペ可能な正確なコマンド** を記載する +- サブパッケージ CLAUDE.md は **30行以内** に収める(`references/claudemd-template.md` の「30行制限の圧縮ガイド」に従う) +- サブパッケージ CLAUDE.md はルート CLAUDE.md と **内容を重複させない**(共通ルールはルートで定義) +- サブパッケージ CLAUDE.md に **Language セクションは記載しない**(ルートで定義済み) +- `packages/shared/` には CLAUDE.md を **生成しない**(レポートに「手動追加可能」と案内) +- サブパッケージ CLAUDE.md の **Code Style はルートと異なる言語のパッケージにのみ** 記載する +- 質問をスキップして自動選定する場合、次の質問に進む前に自動選定の結果を表示する。形式: 「[項目名] は [選定値] に自動設定されました(理由: [理由])」 +- 同一トリガー(Q1/Q2の回答)に起因する複数のスキップはまとめて通知する。例: GAS選択時は Q2 回答直後(Q4 の前)に「GAS プロジェクトのため、以下が自動設定されました: 言語: TypeScript / ビルド: clasp + esbuild / Linter: Biome / PM: pnpm」と通知する +- 3層/BFFアーキテクチャでモノレポ構成が自動選択される場合も同様に通知する + +## 追加リソース + +### リファレンスファイル + +- **`references/claudemd-template.md`** — CLAUDE.md のテンプレート構造、コマンド導出テーブル、コードスタイルデフォルト、80行制限ガイド +- **`references/tech-recommendations.md`** — 言語×タイプの推奨マトリクス、PM・テスト・Linter推奨表、ディレクトリ構造テンプレート、Docker開発環境推奨表 +- **`references/docker-dev-templates.md`** — 言語別docker-compose開発環境テンプレート、DBサービス、Playwright連携 +- **`.claude/skills/dev-context/references/context-template.md`** — context.md のテンプレートと記述ガイド(dev-context と共有) +- **`references/ts-scaffolding.md`** — TypeScript スキャフォールディングガイド +- **`references/python-scaffolding.md`** — Python スキャフォールディングガイド +- **`references/rust-scaffolding.md`** — Rust スキャフォールディングガイド +- **`references/go-scaffolding.md`** — Go スキャフォールディングガイド +- **`references/java-scaffolding.md`** — Java スキャフォールディングガイド +- **`references/kotlin-scaffolding.md`** — Kotlin スキャフォールディングガイド +- **`references/dart-scaffolding.md`** — Dart (Flutter) スキャフォールディングガイド diff --git a/skills/dev-init/references/claudemd-template.md b/skills/dev-init/references/claudemd-template.md new file mode 100644 index 0000000..ac626f5 --- /dev/null +++ b/skills/dev-init/references/claudemd-template.md @@ -0,0 +1,611 @@ +# CLAUDE.md テンプレートガイド + +dev-init Phase 6 で CLAUDE.md を生成する際のテンプレート構造、コマンド導出ロジック、スタイルガイドを定義する。 + +## 基本方針 + +- **80行以内** に収める(Claude Code が毎セッション読み込むため、簡潔さが最重要) +- **指示的な言語** を使う(「TypeScriptを使う」「pnpmで管理する」)— 記述的ではなく命令的 +- **コピペ可能なコマンド** を記載する — 説明ではなく実行可能な形式 +- **信号機システムは使わない** — CLAUDE.md は検出結果ではなく指示書 +- **context.md と重複させない** — 詳細は context.md に委ね、CLAUDE.md はルールとコマンドに集中 + +## context.md との棲み分け + +| 項目 | CLAUDE.md | context.md | +|------|-----------|------------| +| 目的 | Claude への行動指示 | プロジェクト情報の記録 | +| 読者 | Claude Code(毎セッション自動読み込み) | dev-* スキル群 | +| 内容 | コマンド、コードスタイル、プロジェクトルール | 技術スタック詳細、ディレクトリ構造、信号機付き情報 | +| トーン | 命令文(「〜を使う」「〜しない」) | 記述文(「〜を使用している」) | +| 行数 | 80行以内 | 500行以内 | + +## ルート CLAUDE.md vs サブパッケージ CLAUDE.md の棲み分け + +モノレポ構成(3層Web / BFF / マイクロサービス)では、ルートとサブパッケージの両方に CLAUDE.md を配置する。 + +| 項目 | ルート CLAUDE.md | サブパッケージ CLAUDE.md | +|------|-----------------|----------------------| +| 配置場所 | プロジェクトルート | `packages//` または `services//` | +| 行数制限 | 80行以内 | 30行以内 | +| コマンド | ワークスペースコマンド (`pnpm -r build` 等) | パッケージローカルコマンド (`pnpm build` 等) | +| Code Style | 共通コードスタイル(全パッケージ共通) | 混合言語時のみ記載(パッケージ固有の言語スタイル) | +| Project Rules | アーキテクチャルール(依存方向等) | パッケージ固有ルール(役割・責務) | +| Language | 記載する | 記載しない(ルートで定義済み) | +| 生成対象外 | — | `packages/shared/`(型定義パッケージ) | + +## テンプレート構造 + +```markdown +# Project Overview + +{Q1/Q2 プロジェクトタイプ} + {Q4 言語} + {Q6 フレームワーク} の1-2行要約。 + +## Development Commands + +{言語×PM別のコマンド一覧} + +## Code Style + +{言語別のコーディング規約} + +## Project Rules + +{フレームワーク固有ルール + テスト規約 + Docker + 追加ツール} + +## Language + +日本語でコミュニケーションする。 +``` + +## サブパッケージ CLAUDE.md テンプレート構造 + +モノレポのサブパッケージ(`packages/frontend/`, `packages/bff/`, `services//` 等)に配置する CLAUDE.md のテンプレート。30行以内に収める。 + +```markdown +# {package-name} + +{パッケージの役割を1行で記述} + +## Development Commands + +{パッケージローカルのコマンド一覧} + +## Code Style + +{混合言語時のみ記載 — ルートと異なる言語の場合にパッケージ固有のスタイルを記載} + +## Package Rules + +{パッケージ固有のルール — 役割・責務・制約} +``` + +> **Note:** 同一言語のモノレポでは Code Style セクションを省略する(ルート CLAUDE.md に記載済みのため)。混合言語(例: TS frontend + Go backend)の場合のみ、ルートと異なる言語のパッケージに Code Style を追加する。 + +## Development Commands 導出テーブル + +### TypeScript + +| PM | ビルド | テスト | Lint | フォーマット | 開発サーバー | +|----|--------|--------|------|------------|------------| +| pnpm | `pnpm build` | `pnpm test` | `pnpm lint` | `pnpm format` | `pnpm dev` | +| bun | `bun run build` | `bun test` | `bun run lint` | `bun run format` | `bun dev` | +| yarn | `yarn build` | `yarn test` | `yarn lint` | `yarn format` | `yarn dev` | +| npm | `npm run build` | `npm test` | `npm run lint` | `npm run format` | `npm run dev` | + +Linter/Formatter: +- Biome: `{pm} biome check --write .` +- ESLint + Prettier: `{pm} eslint . && {pm} prettier --write .` + +### Python + +| PM | ビルド | テスト | Lint | フォーマット | 開発サーバー | +|----|--------|--------|------|------------|------------| +| uv | — | `uv run pytest` | `uv run ruff check .` | `uv run ruff format .` | `uv run uvicorn app.main:app --reload` | +| pip | — | `pytest` | `ruff check .` | `ruff format .` | `uvicorn app.main:app --reload` | +| poetry | — | `poetry run pytest` | `poetry run ruff check .` | `poetry run ruff format .` | `poetry run uvicorn app.main:app --reload` | + +Django の場合: 開発サーバーは `{pm-run} python manage.py runserver` + +### Rust + +| コマンド | 実行 | +|---------|------| +| ビルド | `cargo build` | +| テスト | `cargo test` | +| Lint | `cargo clippy -- -D warnings` | +| フォーマット | `cargo fmt` | +| 開発実行 | `cargo run` | +| Watch | `cargo watch -x run` | + +### Go + +| コマンド | 実行 | +|---------|------| +| ビルド | `go build ./...` | +| テスト | `go test ./...` | +| Lint | `golangci-lint run` | +| フォーマット | `gofmt -w .` | +| 開発サーバー | `air`(要 air インストール) | + +### Java (Gradle) + +| コマンド | 実行 | +|---------|------| +| ビルド | `./gradlew build` | +| テスト | `./gradlew test` | +| Lint | `./gradlew checkstyleMain` | +| フォーマット | `./gradlew spotlessApply` | +| 開発サーバー | `./gradlew bootRun` | + +Maven の場合: `./gradlew` → `./mvnw` に置換 + +### Kotlin (Gradle) + +| コマンド | 実行 | +|---------|------| +| ビルド | `./gradlew build` | +| テスト | `./gradlew test` | +| Lint | `./gradlew ktlintCheck` | +| フォーマット | `./gradlew ktlintFormat` | +| 開発サーバー | `./gradlew run` | + +### Dart + +| コマンド | 実行 | +|---------|------| +| ビルド | `dart compile exe` / `flutter build` | +| テスト | `dart test` / `flutter test` | +| Lint | `dart analyze` | +| フォーマット | `dart format .` | +| 開発サーバー | `flutter run` / `dart run` | + +## Docker 時のコマンドプレフィクス + +Q10 で Docker 開発環境を選択した場合、Development Commands のコマンドに `docker compose exec app` プレフィクスを付与する。 + +**適用ルール:** +- ビルド、テスト、Lint、フォーマットコマンド → プレフィクス付与 +- 開発サーバー → `docker compose up` に置換(docker-compose.yml で定義済みのため) +- Docker 自体の操作コマンドは別セクションに記載: + +``` +docker compose up -d # 開発環境起動 +docker compose down # 停止 +docker compose logs -f # ログ確認 +``` + +## Code Style デフォルト + +### TypeScript +- 命名: camelCase(変数・関数)、PascalCase(クラス・型・コンポーネント) +- エラーハンドリング: try-catch、カスタムエラークラス +- ファイル命名: kebab-case.ts(コンポーネントは PascalCase.tsx) + +### Python +- 命名: snake_case(変数・関数)、PascalCase(クラス) +- エラーハンドリング: 例外、カスタム例外クラス +- ファイル命名: snake_case.py + +### Rust +- 命名: snake_case(変数・関数)、PascalCase(型・トレイト)、SCREAMING_SNAKE_CASE(定数) +- エラーハンドリング: Result/Option、thiserror/anyhow +- ファイル命名: snake_case.rs + +### Go +- 命名: camelCase(非公開)、PascalCase(公開) +- エラーハンドリング: error 返却、errors.New/fmt.Errorf +- ファイル命名: snake_case.go + +### Java +- 命名: camelCase(変数・メソッド)、PascalCase(クラス) +- エラーハンドリング: チェック例外/非チェック例外 +- ファイル命名: PascalCase.java + +### Kotlin +- 命名: camelCase(変数・関数)、PascalCase(クラス) +- エラーハンドリング: runCatching、sealed class Result +- ファイル命名: PascalCase.kt + +### Dart +- 命名: camelCase(変数・関数)、PascalCase(クラス)、snake_case(ライブラリ) +- エラーハンドリング: try-catch、カスタム例外 +- ファイル命名: snake_case.dart + +## チーム規模による調整(Q5) + +| 項目 | 個人・プロトタイプ | 小規模(2-5人) | 中〜大規模(6人+) | +|------|------------------|----------------|-------------------| +| Code Style の記載量 | 最小限(3-5行) | 標準(5-8行) | 詳細(8-12行) | +| Project Rules | 基本のみ | + コードレビュー指針 | + 命名規約詳細・ドキュメント義務 | +| テスト規約 | 「テストを書く」 | 「単体+結合テストを書く」 | 「単体+結合+E2E、カバレッジ80%以上」 | +| Lint 厳格度 | warn レベル | error レベル | error + カスタムルール | + +## 80行制限の圧縮優先順位 + +80行を超える場合、以下の優先順位で圧縮する(上ほど残す): + +1. **Development Commands** — 最重要。コマンドがないと開発できない +2. **Code Style** — 一貫性に直結。最低限の命名規則は残す +3. **Project Rules** — 圧縮可能。フレームワーク固有ルールを要約 +4. **Project Overview** — 1行に短縮可能 +5. **Language** — 1行のため圧縮不要 + +圧縮テクニック: +- コマンドをインラインで記載: `ビルド: \`pnpm build\` | テスト: \`pnpm test\` | Lint: \`pnpm lint\`` +- ルールをリスト化して1行1ルール +- 自明なデフォルト(言語標準の命名規則等)は省略 + +## タイプ別 Project Rules テンプレート + +### 3層Webアプリ + +- packages/frontend, packages/backend, packages/shared に配置する +- 共有型定義は packages/shared に集約し、各パッケージから参照する +- 各パッケージは独立ビルド可能に保つ +- フロントエンドからバックエンドへの直接 import は禁止(shared 経由) +- API通信は型安全なクライアントを shared で定義する + +### BFF + +- UI層は表示ロジックのみ、BFF層はAPI集約とデータ整形のみ、サービス層がビジネスロジック担当 +- UI→BFF→サービスの方向でのみ依存する(逆方向禁止) +- BFFはサービス層のAPIを集約・整形してUI向けに最適化したレスポンスを返す +- BFFにビジネスロジックを置かない +- **全層同一言語の場合**: サービス層のAPI契約は packages/shared で型定義する +- **混合言語の場合**: API契約は OpenAPI スキーマ or Protocol Buffers で定義し、packages/shared に配置する。各層は生成された型定義を使用する + +### バッチ処理 + +- 全ジョブは冪等に実装する(再実行で同一結果) +- リトライ回数とタイムアウトを各ジョブに明示する +- 構造化ロギングを使用し、ジョブID・開始/終了時刻を必ず記録する +- 長時間ジョブは進捗ログを定期出力する + +### マイクロサービス + +- 各サービスは独立デプロイ可能に保つ +- サービス間のAPI契約は packages/shared で定義し、破壊的変更時はバージョニングする +- 共有コードは最小限にする(型定義・プロトコル定義のみ) +- サービス固有のデータストアは他サービスから直接アクセスしない + +### イベント駆動 + +- イベントスキーマは src/events/ に集約し、バージョン管理する +- プロデューサーとコンシューマーは明確に分離する +- デッドレターキューを設定し、処理失敗イベントを捕捉する +- コンシューマーは冪等に実装する + +### GAS + +- clasp でデプロイする。手動でスクリプトエディタを編集しない +- TypeScript で記述し、esbuild でビルドする +- GAS の実行制限(6分/実行、30分/日等)を考慮して設計する +- グローバル関数のみが GAS から呼び出し可能。エクスポートは global オブジェクトに代入する +- テストは Vitest でローカル実行する(GAS API のモックが必要) + +## GAS 用 Development Commands テーブル + +| コマンド | 実行 | +|---------|------| +| ビルド | `pnpm build` | +| テスト | `pnpm test` | +| Lint | `pnpm lint` | +| デプロイ | `pnpm run push` (clasp push) | +| ログ確認 | `clasp logs` | +| ブラウザで開く | `clasp open` | + +## 3層Web 用モノレポ Development Commands テーブル + +| コマンド | 実行 | +|---------|------| +| 全体ビルド | `pnpm -r build` | +| 全体テスト | `pnpm -r test` | +| フロント開発 | `pnpm --filter frontend dev` | +| バックエンド開発 | `pnpm --filter backend dev` | +| Lint | `pnpm -r lint` | + +## BFF 用モノレポ Development Commands テーブル + +### 全層 TypeScript の場合 + +| コマンド | 実行 | +|---------|------| +| 全体ビルド | `pnpm -r build` | +| 全体テスト | `pnpm -r test` | +| UI開発 | `pnpm --filter web-ui dev` | +| BFF開発 | `pnpm --filter bff dev` | +| サービス開発 | `pnpm --filter service dev` / `pnpm --filter service-a dev` | +| Lint | `pnpm -r lint` | + +### 混合言語の場合 + +全層が同一言語でない場合は、ワークスペース一括コマンド(`pnpm -r`)は使用せず、各パッケージのコマンドを個別に列挙する。各層の言語に対応するコマンドテーブル(TypeScript / Python / Go / Rust / Java / Kotlin / Dart)から導出する。 + +``` +# UI層(例: TypeScript) +cd packages/web-ui && pnpm build / pnpm test / pnpm dev + +# BFF層(例: Go) +cd packages/bff && go build ./... / go test ./... + +# サービス層(例: Python) +cd packages/service && uv run pytest / uv run uvicorn ... +``` + +> Makefile + Docker Compose ベースのモノレポでは `make build-all`, `make test-all` 等のターゲットを定義してルート CLAUDE.md に記載する。 + +## サブパッケージ Development Commands 導出テーブル + +サブパッケージの CLAUDE.md に記載するローカルコマンドは、ルートのワークスペースコマンドではなくパッケージ内で直接実行するコマンドを記載する。 + +### TypeScript パッケージ + +| PM | ビルド | テスト | Lint | 開発サーバー | +|----|--------|--------|------|------------| +| pnpm | `pnpm build` | `pnpm test` | `pnpm lint` | `pnpm dev` | +| bun | `bun run build` | `bun test` | `bun run lint` | `bun dev` | +| yarn | `yarn build` | `yarn test` | `yarn lint` | `yarn dev` | +| npm | `npm run build` | `npm test` | `npm run lint` | `npm run dev` | + +### 非 TypeScript パッケージ(混合言語時) + +ルートの言語別コマンドテーブル(Python / Rust / Go / Java / Kotlin)をそのまま適用する。Docker 選択時は `docker compose exec app` プレフィクスを付与する。 + +## サブパッケージ Package Rules テンプレート + +パッケージの役割に応じたルールテンプレート。各パッケージに該当するものを1-3行で記載する。 + +### frontend / web-ui + +- UIコンポーネントと表示ロジックのみ配置する +- ビジネスロジックは配置しない +- API通信は shared の型定義を使用する + +### mobile-ui + +- モバイルアプリのUIとナビゲーションロジックのみ配置する +- BFF の API を呼び出してデータを取得する +- BFF の URL は環境変数で管理する + +### bff + +- API集約とデータ整形のみ行う +- ビジネスロジックは配置しない +- サービス層の API を集約して UI 向けに最適化する + +### backend / service + +- ビジネスロジックとデータアクセスを配置する +- API契約は shared の型定義に従う +- 他パッケージの内部実装に依存しない + +### microservice(各 services/) + +- 独立デプロイ可能に保つ +- 他サービスのデータストアに直接アクセスしない +- API契約は shared で定義する + +## 30行制限の圧縮ガイド + +サブパッケージ CLAUDE.md が30行を超える場合の圧縮優先順位(上ほど残す): + +1. **Development Commands** — パッケージ内で実行するコマンドは必須 +2. **Package Rules** — パッケージの役割・制約は必須(1-3行に圧縮) +3. **Code Style** — 混合言語時のみ。同一言語なら省略 +4. **パッケージ説明** — 1行で十分 + +圧縮テクニック: +- コマンドをインラインで記載: `ビルド: \`pnpm build\` | テスト: \`pnpm test\` | Lint: \`pnpm lint\`` +- ルートと重複するルールは省略(ルート CLAUDE.md で定義済み) +- Code Style はルートと異なる部分のみ記載 + +## 生成例: TypeScript + Hono + Docker(個人プロジェクト) + +```markdown +# Project Overview + +TypeScript + Hono の API サーバー。Docker 開発環境で PostgreSQL を使用。 + +## Development Commands + +docker compose up -d # 開発環境起動 +docker compose down # 停止 +docker compose logs -f # ログ確認 + +docker compose exec app pnpm build # ビルド +docker compose exec app pnpm test # テスト +docker compose exec app pnpm lint # Lint +docker compose exec app pnpm format # フォーマット + +## Code Style + +- 命名: camelCase(変数・関数)、PascalCase(型・クラス) +- ファイル命名: kebab-case.ts +- Biome でフォーマット・Lint を統合管理 + +## Project Rules + +- ルーティングは src/routes/ に配置 +- ビジネスロジックは src/services/ に分離 +- テストは Vitest で tests/ 配下に配置 +- 環境変数は .env を使用、.env はコミットしない + +## Language + +日本語でコミュニケーションする。 +``` + +上記例: 約25行(80行制限内) + +## 生成例: GAS(スプレッドシート連携・個人プロジェクト) + +```markdown +# Project Overview + +Google Apps Script(TypeScript)のスプレッドシート連携スクリプト。clasp + esbuild でビルド・デプロイ。 + +## Development Commands + +pnpm build # esbuild でビルド +pnpm test # Vitest テスト実行 +pnpm lint # Biome lint +pnpm run push # clasp push(GASへデプロイ) +clasp logs # 実行ログ確認 +clasp open # ブラウザで開く + +## Code Style + +- 命名: camelCase(変数・関数)、PascalCase(型・クラス) +- ファイル命名: kebab-case.ts +- Biome でフォーマット・Lint を統合管理 + +## Project Rules + +- GAS から呼び出す関数は global オブジェクトに代入する +- GAS の実行制限(6分/実行)を考慮し、大量データは分割処理する +- GAS API のモックを使ってローカルテストする +- clasp でデプロイする。手動でスクリプトエディタを編集しない + +## Language + +日本語でコミュニケーションする。 +``` + +上記例: 約25行(80行制限内) + +## 生成例: BFF(TypeScript + Next.js + Hono + Docker・小規模チーム) + +```markdown +# Project Overview + +BFFアーキテクチャの Webアプリ。Next.js(UI)+ Hono(BFF)+ Hono(サービス)+ PostgreSQL。Docker 開発環境。 + +## Development Commands + +docker compose up -d # 開発環境起動 +docker compose down # 停止 +docker compose logs -f # ログ確認 + +pnpm -r build # 全体ビルド +pnpm -r test # 全体テスト +pnpm --filter web-ui dev # UI開発 +pnpm --filter bff dev # BFF開発 +pnpm --filter service dev # サービス開発 +pnpm -r lint # Lint + +## Code Style + +- 命名: camelCase(変数・関数)、PascalCase(型・クラス・コンポーネント) +- ファイル命名: kebab-case.ts(コンポーネントは PascalCase.tsx) +- Biome でフォーマット・Lint を統合管理 +- 共有型定義は packages/shared に配置 + +## Project Rules + +- UI層は表示ロジックのみ、BFF層はAPI集約・整形のみ、サービス層がビジネスロジック担当 +- UI→BFF→サービスの方向でのみ依存する(逆方向禁止) +- サービス層のAPI契約は packages/shared で型定義する +- テストは Vitest で各パッケージに配置 +- 環境変数は .env を使用、.env はコミットしない + +## Language + +日本語でコミュニケーションする。 +``` + +上記例: 約35行(80行制限内) + +## サブパッケージ生成例: 同一言語 BFF(TypeScript + Hono) + +### packages/web-ui/CLAUDE.md (~12行) + +```markdown +# web-ui + +Next.js App Router のフロントエンド UI パッケージ。 + +## Development Commands + +pnpm build # ビルド +pnpm test # テスト +pnpm dev # 開発サーバー +pnpm lint # Lint + +## Package Rules + +- UIコンポーネントと表示ロジックのみ配置する +- ビジネスロジックは配置しない +- API通信は shared の型定義を使用する +``` + +### packages/bff/CLAUDE.md (~12行) + +```markdown +# bff + +Hono の BFF(Backend for Frontend)パッケージ。サービス層の API を集約・整形する。 + +## Development Commands + +pnpm build # ビルド +pnpm test # テスト +pnpm dev # 開発サーバー +pnpm lint # Lint + +## Package Rules + +- API集約とデータ整形のみ行う +- ビジネスロジックは配置しない +- サービス層の API を集約して UI 向けに最適化する +``` + +## サブパッケージ生成例: 混合言語 3層Web(TypeScript + Go) + +### packages/frontend/CLAUDE.md (~10行) + +```markdown +# frontend + +Next.js App Router のフロントエンドパッケージ。 + +## Development Commands + +pnpm build # ビルド +pnpm test # テスト +pnpm dev # 開発サーバー +pnpm lint # Lint + +## Package Rules + +- UIコンポーネントと表示ロジックのみ配置する +- API通信は shared の型定義を使用する +``` + +### packages/backend/CLAUDE.md (~22行, Code Style 付き) + +```markdown +# backend + +Go + Echo のバックエンド API パッケージ。 + +## Development Commands + +go build ./... # ビルド +go test ./... # テスト +golangci-lint run # Lint +gofmt -w . # フォーマット +air # 開発サーバー + +## Code Style + +- 命名: camelCase(非公開)、PascalCase(公開) +- エラーハンドリング: error 返却、errors.New/fmt.Errorf +- ファイル命名: snake_case.go + +## Package Rules + +- ビジネスロジックとデータアクセスを配置する +- API契約は shared の型定義に従う +- 他パッケージの内部実装に依存しない +``` diff --git a/skills/dev-init/references/dart-scaffolding.md b/skills/dev-init/references/dart-scaffolding.md new file mode 100644 index 0000000..436e5ec --- /dev/null +++ b/skills/dev-init/references/dart-scaffolding.md @@ -0,0 +1,117 @@ +# Dart (Flutter) スキャフォールディングガイド + +## CLI ツール + +| 用途 | コマンド | オプション | +|------|---------|-----------| +| Flutter アプリ | `flutter create ` | `--org --platforms web,ios,android` | +| Flutter パッケージ | `flutter create --template=package ` | — | +| Flutter プラグイン | `flutter create --template=plugin ` | `--platforms` | +| Pure Dart パッケージ | `dart create -t package ` | — | +| Pure Dart CLI | `dart create -t console ` | — | +| dart_frog API | `dart_frog create ` | `dart pub global activate dart_frog_cli` が必要 | + +### Flutter vs Pure Dart の分岐 + +- UI あり(モバイル/Web/デスクトップ)→ `flutter create` +- API サーバー → `dart create` + dart_frog / shelf +- CLI → `dart create -t console` +- ライブラリ(Flutter 依存あり)→ `flutter create --template=package` +- ライブラリ(Pure Dart)→ `dart create -t package` + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | dev_dependencies | +|--------|-----|-------------|-----------------| +| モバイル/Web | Flutter | `flutter(sdk)` | `flutter_test(sdk) flutter_lints` | +| API | dart_frog | `dart_frog` | `test dart_frog_test mocktail` | +| API | shelf | `shelf shelf_router` | `test http` | +| CLI | dcli | `dcli args` | `test` | +| ライブラリ | — | — | `test flutter_lints` | + +### pubspec.yaml 重要フィールド + +- `environment.sdk`: `">=3.4.0 <4.0.0"` +- `environment.flutter`(Flutter のみ): `">=3.22.0"` +- `publish_to`: `"none"`(公開しない場合) +- `flutter.uses-material-design`: `true`(Flutter) + +## 設定ファイル + +### analysis_options.yaml + +Flutter プロジェクト: +```yaml +include: package:flutter_lints/flutter.yaml +linter: + rules: + prefer_const_constructors: true + avoid_print: true +analyzer: + errors: + missing_return: error +``` + +Pure Dart プロジェクト: +```yaml +include: package:lints/recommended.yaml +``` + +### チーム規模別調整 + +- 個人: `package:lints/recommended.yaml` のみ +- 小規模: `package:flutter_lints/flutter.yaml` + カスタムルール数個 +- 大規模: `strict: true` 相当 + `avoid_dynamic_calls`, `prefer_final_locals` 等を追加 + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| Flutter アプリ | `lib/main.dart` | `runApp(MyApp())` | +| dart_frog API | `routes/index.dart` | `Response onRequest(RequestContext context)` | +| shelf API | `bin/server.dart` | `shelf.serve(handler, host, port)` | +| CLI (dcli) | `bin/.dart` | `main(List args)` | +| ライブラリ | `lib/.dart` | パブリック API エクスポート | + +## テスト雛形 + +- Flutter: `test/widget/` に `*_test.dart`、`testWidgets()` でウィジェットテスト +- dart_frog: `test/routes/` に `*_test.dart`、`RequestContext` モック +- 最小構成: Flutter → `MaterialApp` レンダリングテスト、API → エンドポイント応答テスト +- 統合テスト (Flutter): `integration_test/` ディレクトリ + +## Docker ガイド + +- Flutter Web: `ghcr.io/cirruslabs/flutter:latest` → Nginx で静的配信 +- dart_frog / shelf: `dart:stable` → マルチステージ(`dart compile exe`)→ `scratch` or `gcr.io/distroless/cc` +- `.dockerignore`: `.dart_tool`, `build`, `.git`, `.env*`, `.packages` +- AOT コンパイル: `dart compile exe bin/server.dart -o server` で単一バイナリ + +### 開発用 Docker + +- 開発用ベースイメージ: `dart:stable` +- Volume mount: `- .:/app` でソースコードをマウント、`pub-cache` は named volume で分離 +- Hot-reload: `dart run --enable-vm-service`(dart_frog の場合は `dart_frog dev`)で自動再起動 +- Dockerfile.dev: マルチステージ不要、dart pub get + dev server コマンド + +## CI (GitHub Actions) ガイド + +- Flutter セットアップ: `subosito/flutter-action@v2` + `flutter-version: '3.22'` +- Pure Dart: `dart-lang/setup-dart@v1` +- キャッシュ: `~/.pub-cache` をキャッシュ +- ステップ(Flutter): `flutter pub get` → `dart analyze` → `dart format --set-exit-if-changed .` → `flutter test` +- ステップ(Dart): `dart pub get` → `dart analyze` → `dart format --set-exit-if-changed .` → `dart test` + +## 検証コマンド + +| 操作 | Flutter | Pure Dart | +|------|---------|-----------| +| 依存インストール | `flutter pub get` | `dart pub get` | +| ビルド (Web) | `flutter build web` | — | +| ビルド (AOT) | — | `dart compile exe bin/main.dart` | +| テスト | `flutter test` | `dart test` | +| Lint | `dart analyze` | `dart analyze` | +| フォーマット確認 | `dart format --set-exit-if-changed .` | `dart format --set-exit-if-changed .` | +| 開発実行 | `flutter run` | `dart run bin/server.dart` | diff --git a/skills/dev-init/references/docker-dev-templates.md b/skills/dev-init/references/docker-dev-templates.md new file mode 100644 index 0000000..0ac0b5c --- /dev/null +++ b/skills/dev-init/references/docker-dev-templates.md @@ -0,0 +1,712 @@ +# Docker 開発環境テンプレート + +dev-init スキルが Docker 開発環境を構築する際に参照するテンプレート集。Q10 で「Docker開発環境」を選択した場合に使用する。 + +**注意:** ビルド成果物ディレクトリ(`.next`, `dist`, `build`, `target`, `__pycache__` 等)はホストとバインドマウントしないこと。コンテナ内で完結させる。named volume で分離するか、マウント対象外にする。 + +## 1. 言語別 app サービステンプレート + +### TypeScript (Node.js) + +```yaml + app: + image: node:20-slim + working_dir: /app + volumes: + - .:/app + - node_modules:/app/node_modules + ports: + - "3000:3000" + command: ["pnpm", "dev"] + environment: + - NODE_ENV=development +``` + +**Dockerfile.dev:** +```dockerfile +FROM node:20-slim +RUN corepack enable && corepack prepare pnpm@latest --activate +WORKDIR /app +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile +COPY . . +CMD ["pnpm", "dev"] +``` + +Bun の場合: イメージを `oven/bun:1` に変更、`pnpm` を `bun` に置換。 + +### Python + +```yaml + app: + image: python:3.12-slim + working_dir: /app + volumes: + - .:/app + ports: + - "8000:8000" + command: ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--reload"] + environment: + - PYTHONDONTWRITEBYTECODE=1 + - PYTHONUNBUFFERED=1 +``` + +**Dockerfile.dev:** +```dockerfile +FROM python:3.12-slim +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv +WORKDIR /app +COPY pyproject.toml uv.lock ./ +RUN uv sync +COPY . . +CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--reload"] +``` + +Django の場合: コマンドを `uv run python manage.py runserver 0.0.0.0:8000` に変更。 + +### Rust + +```yaml + app: + image: rust:1.82 + working_dir: /app + volumes: + - .:/app + - cargo-cache:/usr/local/cargo/registry + - target-cache:/app/target + ports: + - "8080:8080" + command: ["cargo", "watch", "-w", "src", "-w", "Cargo.toml", "-x", "run"] + environment: + - CARGO_HOME=/usr/local/cargo +``` + +**Dockerfile.dev:** +```dockerfile +FROM rust:1.82 +RUN cargo install cargo-watch +WORKDIR /app +COPY Cargo.toml Cargo.lock ./ +RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build && rm -rf src +COPY . . +CMD ["cargo", "watch", "-w", "src", "-w", "Cargo.toml", "-x", "run"] +``` + +### Go + +```yaml + app: + image: golang:1.22 + working_dir: /app + volumes: + - .:/app + - go-mod-cache:/go/pkg/mod + ports: + - "8080:8080" + command: ["air"] + environment: + - CGO_ENABLED=0 +``` + +**Dockerfile.dev:** +```dockerfile +FROM golang:1.22 +RUN go install github.com/air-verse/air@latest && \ + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +CMD ["air"] +``` + +### Java (Spring Boot / Quarkus) + +```yaml + app: + image: eclipse-temurin:21 + working_dir: /app + volumes: + - .:/app + - gradle-cache:/root/.gradle + ports: + - "8080:8080" + command: ["./gradlew", "bootRun"] + environment: + - JAVA_TOOL_OPTIONS=-Dspring.devtools.restart.enabled=true +``` + +**Dockerfile.dev:** +```dockerfile +FROM eclipse-temurin:21 +WORKDIR /app +COPY gradlew gradlew.bat ./ +COPY gradle/ gradle/ +COPY build.gradle.kts settings.gradle.kts ./ +RUN ./gradlew dependencies --no-daemon +COPY . . +CMD ["./gradlew", "bootRun"] +``` + +Quarkus の場合: コマンドを `./gradlew quarkusDev` に変更。 + +### Kotlin (Ktor / Spring Boot) + +```yaml + app: + image: eclipse-temurin:21 + working_dir: /app + volumes: + - .:/app + - gradle-cache:/root/.gradle + ports: + - "8080:8080" + command: ["./gradlew", "run", "--continuous"] + environment: + - JAVA_TOOL_OPTIONS=-XX:+UseContainerSupport +``` + +**Dockerfile.dev:** +```dockerfile +FROM eclipse-temurin:21 +WORKDIR /app +COPY gradlew gradlew.bat ./ +COPY gradle/ gradle/ +COPY build.gradle.kts settings.gradle.kts ./ +RUN ./gradlew dependencies --no-daemon +COPY . . +CMD ["./gradlew", "run", "--continuous"] +``` + +Spring Boot (Kotlin) の場合: コマンドを `./gradlew bootRun` に変更。 + +### Dart (dart_frog / shelf) + +```yaml + app: + image: dart:stable + working_dir: /app + volumes: + - .:/app + - pub-cache:/root/.pub-cache + ports: + - "8080:8080" + command: ["dart", "run", "--enable-vm-service", "bin/server.dart"] + environment: + - DART_VM_OPTIONS=--enable-asserts +``` + +**Dockerfile.dev:** +```dockerfile +FROM dart:stable +WORKDIR /app +COPY pubspec.yaml pubspec.lock ./ +RUN dart pub get +COPY . . +CMD ["dart", "run", "--enable-vm-service", "bin/server.dart"] +``` + +dart_frog の場合: `dart pub global activate dart_frog_cli` を追加し、コマンドを `dart_frog dev` に変更。 + +## 2. DB サービステンプレート + +### PostgreSQL + +```yaml + db: + image: postgres:16-alpine + environment: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev + POSTGRES_DB: app_dev + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data +``` + +app サービスに追加する環境変数: +```yaml + environment: + - DATABASE_URL=postgresql://dev:dev@db:5432/app_dev +``` + +### SQLite + +SQLite はファイルベースのため、DB サービス不要。app サービスの volume mount で対応。 + +```yaml + environment: + - DATABASE_URL=sqlite:///app/data/app.db + volumes: + - ./data:/app/data +``` + +### MongoDB + +```yaml + db: + image: mongo:7 + ports: + - "27017:27017" + volumes: + - db-data:/data/db +``` + +app サービスに追加する環境変数: +```yaml + environment: + - MONGODB_URL=mongodb://db:27017/app_dev +``` + +## 3. Playwright サービス(Webアプリ用) + +Webアプリ選択時、dev-webtest スキルの Playwright サービスを docker-compose.yml に追加する。 + +設定の詳細は `.claude/skills/dev-webtest/references/docker-setup.md` を参照すること。 + +基本構成: +```yaml + playwright: + image: mcr.microsoft.com/playwright:v1.50.0-noble + profiles: [test] + working_dir: /work + volumes: + - .:/work + depends_on: + - app + command: ["tail", "-f", "/dev/null"] + environment: + - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright +``` + +- `profiles: [test]` により通常の `docker compose up -d` では起動しない。テスト時は `docker compose --profile test up playwright` で起動する +- `depends_on: [app]` でアプリ起動後に Playwright コンテナが起動する +- volume mount でスクリーンショット共有(`tmp/webtest/screenshots/`) +- `@playwright/cli` のインストールが必要(詳細は dev-webtest 参照) + +## 4. 追加サービステンプレート + +### Redis(キャッシュ・セッション) + +```yaml + redis: + image: redis:7-alpine + ports: + - "6379:6379" + volumes: + - redis-data:/data +``` + +app サービスに追加する環境変数: +```yaml + environment: + - REDIS_URL=redis://redis:6379 +``` + +## 5. マルチサービス構成テンプレート + +### 3層Webアプリ + +```yaml +services: + frontend: + build: + context: ./packages/frontend + dockerfile: Dockerfile.dev + ports: + - "3000:3000" + volumes: + - ./packages/frontend:/app + - frontend_node_modules:/app/node_modules + depends_on: + - backend + command: ["pnpm", "dev"] + environment: + - API_URL=http://backend:8080 + + backend: + # Q4c言語テンプレートを使用 + build: + context: ./packages/backend + dockerfile: Dockerfile.dev + ports: + - "8080:8080" + volumes: + - ./packages/backend:/app + depends_on: + - db + environment: + - DATABASE_URL=postgresql://dev:dev@db:5432/app_dev + + db: + # Q8 DB テンプレートを使用 + image: postgres:16-alpine + environment: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev + POSTGRES_DB: app_dev + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data + +volumes: + frontend_node_modules: + db-data: +``` + +### BFF(Webのみ・単一サービス) + +Q3(UIターゲット)が「Webのみ」の場合。各層の言語が異なる場合は、bff と service のテンプレートをそれぞれ Q4b/Q4c 言語に対応するセクション1の言語別テンプレートに差し替える。 + +```yaml +services: + web-ui: + # Q4a言語テンプレートを使用(Webのみ: TypeScript自動選定) + build: + context: ./packages/web-ui + dockerfile: Dockerfile.dev + ports: + - "3000:3000" + volumes: + - ./packages/web-ui:/app + - webui_node_modules:/app/node_modules + depends_on: + - bff + command: ["pnpm", "dev"] + environment: + - BFF_URL=http://bff:4000 + + bff: + # Q4b言語テンプレートを使用 + build: + context: ./packages/bff + dockerfile: Dockerfile.dev + ports: + - "4000:4000" + volumes: + - ./packages/bff:/app + - bff_node_modules:/app/node_modules + depends_on: + - service + command: ["pnpm", "dev"] + environment: + - SERVICE_URL=http://service:8080 + + service: + # Q4c言語テンプレートを使用 + build: + context: ./packages/service + dockerfile: Dockerfile.dev + ports: + - "8080:8080" + volumes: + - ./packages/service:/app + depends_on: + - db + environment: + - DATABASE_URL=postgresql://dev:dev@db:5432/app_dev + + db: + # Q8 DB テンプレートを使用 + image: postgres:16-alpine + environment: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev + POSTGRES_DB: app_dev + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data + +volumes: + webui_node_modules: + bff_node_modules: + db-data: +``` + +### BFF(モバイルのみ・単一サービス) + +Q3(UIターゲット)が「モバイルのみ」の場合。モバイル UI は Docker 外で実行するため web-ui サービスを省略する。bff + service + db の3サービス構成。 + +```yaml +services: + # モバイル UI は Docker 外で実行(Flutter/React Native 等のネイティブ開発環境を使用) + + bff: + # Q4b言語テンプレートを使用 + build: + context: ./packages/bff + dockerfile: Dockerfile.dev + ports: + - "4000:4000" + volumes: + - ./packages/bff:/app + - bff_node_modules:/app/node_modules + depends_on: + - service + command: ["pnpm", "dev"] + environment: + - SERVICE_URL=http://service:8080 + + service: + # Q4c言語テンプレートを使用 + build: + context: ./packages/service + dockerfile: Dockerfile.dev + ports: + - "8080:8080" + volumes: + - ./packages/service:/app + depends_on: + - db + environment: + - DATABASE_URL=postgresql://dev:dev@db:5432/app_dev + + db: + # Q8 DB テンプレートを使用 + image: postgres:16-alpine + environment: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev + POSTGRES_DB: app_dev + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data + +volumes: + bff_node_modules: + db-data: +``` + +> **Note:** モバイルアプリからの BFF 接続は `http://localhost:4000`(エミュレータ)または実機のネットワーク IP を使用する。 + +### BFF(複数サービス) + +```yaml +services: + web-ui: + build: + context: ./packages/web-ui + dockerfile: Dockerfile.dev + ports: + - "3000:3000" + volumes: + - ./packages/web-ui:/app + - webui_node_modules:/app/node_modules + depends_on: + - bff + command: ["pnpm", "dev"] + + bff: + build: + context: ./packages/bff + dockerfile: Dockerfile.dev + ports: + - "4000:4000" + volumes: + - ./packages/bff:/app + - bff_node_modules:/app/node_modules + depends_on: + - service-a + - service-b + command: ["pnpm", "dev"] + + service-a: + build: + context: ./services/service-a + dockerfile: Dockerfile.dev + ports: + - "8081:8080" + volumes: + - ./services/service-a:/app + depends_on: + - db + + service-b: + build: + context: ./services/service-b + dockerfile: Dockerfile.dev + ports: + - "8082:8080" + volumes: + - ./services/service-b:/app + depends_on: + - db + + db: + image: postgres:16-alpine + environment: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev + POSTGRES_DB: app_dev + ports: + - "5432:5432" + volumes: + - db-data:/var/lib/postgresql/data + +volumes: + webui_node_modules: + bff_node_modules: + db-data: +``` + +### マイクロサービス + +```yaml +services: + service-a: + build: + context: ./services/service-a + dockerfile: Dockerfile.dev + ports: + - "8081:8080" + volumes: + - ./services/service-a:/app + + service-b: + build: + context: ./services/service-b + dockerfile: Dockerfile.dev + ports: + - "8082:8080" + volumes: + - ./services/service-b:/app + + # Q8 で DB 選択時のみ追加 + # db: + # ... +``` + +## 6. メッセージブローカーサービステンプレート + +### Apache Kafka + +```yaml + zookeeper: + image: confluentinc/cp-zookeeper:7.6.0 + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ports: + - "2181:2181" + + kafka: + image: confluentinc/cp-kafka:7.6.0 + depends_on: + - zookeeper + ports: + - "9092:9092" + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 +``` + +app サービスに追加する環境変数: +```yaml + environment: + - KAFKA_BROKERS=kafka:29092 +``` + +### RabbitMQ + +```yaml + rabbitmq: + image: rabbitmq:3-management + ports: + - "5672:5672" + - "15672:15672" + environment: + RABBITMQ_DEFAULT_USER: dev + RABBITMQ_DEFAULT_PASS: dev + volumes: + - rabbitmq-data:/var/lib/rabbitmq +``` + +app サービスに追加する環境変数: +```yaml + environment: + - AMQP_URL=amqp://dev:dev@rabbitmq:5672 +``` + +管理UI: `http://localhost:15672`(dev/dev) + +### Redis Pub/Sub + +Redis Pub/Sub の場合はセクション4の Redis テンプレートを再利用する。 + +## 7. docker-compose.yml 組み立てガイド + +### 基本構造 + +```yaml +version: "3.8" + +services: + # 1. app サービス(言語別テンプレートから選択) + app: + # ... + + # 2. DB サービス(Q8 の選択に応じて追加、「なし」の場合は省略) + db: + # ... + + # 3. Playwright サービス(Webアプリの場合のみ追加) + playwright: + # ... + +volumes: + # 言語・DB に応じた named volumes + # ... +``` + +### 組み立てルール + +1. **app サービス**(フルスタック/APIサーバー/バッチ/CLIの場合): Q4c(言語)に対応するテンプレートを選択 +2. **DB サービス**: Q8(データベース)の選択に応じて追加。「なし」の場合は DB サービスと関連 volume を省略 +3. **Playwright サービス**: Q2 が「フルスタック」「3層Web」「BFF(Q3がWebのみ/Web+モバイル)」の場合のみ追加。dev-webtest の docker-setup.md を参照 +4. **app → DB 接続**: DB サービス追加時、app サービスに `depends_on: [db]` と `DATABASE_URL` 環境変数を追加 +5. **volumes**: 各サービスが必要とする named volume を `volumes:` セクションにまとめる +6. **3層Web**: セクション5の3層テンプレートを使用(frontend + backend + db の3サービス構成) +7. **BFF**: セクション5のBFFテンプレートを使用。Q3(UIターゲット)の回答でサービス構成が変わる: Webのみ → web-ui + bff + service(s) + db、モバイルのみ → bff + service(s) + db(web-ui なし、モバイルは Docker 外)、Web+モバイル → web-ui + bff + service(s) + db(mobile-ui は Docker 外)。Q7(サービス層構成)の回答で単一/複数を選択 +8. **マイクロサービス**: セクション5のマイクロサービステンプレートを使用。各サービスは個別ビルド +9. **イベント駆動**: app サービス + セクション6のブローカーテンプレート(Q7 の回答に応じて選択)を組み合わせる +10. **メッセージブローカー**: Q7(イベント駆動のメッセージブローカー / マイクロサービスのメッセージキュー選択時)に応じてセクション6から選択して追加 + +### named volumes 一覧 + +| 言語 | volumes | +|------|---------| +| TypeScript | `node_modules` | +| Python | (不要) | +| Rust | `cargo-cache`, `target-cache` | +| Go | `go-mod-cache` | +| Java | `gradle-cache` | +| Kotlin | `gradle-cache` | +| Dart | `pub-cache` | +| 共通(PostgreSQL) | `db-data` | +| 共通(MongoDB) | `db-data` | +| 共通(Redis) | `redis-data` | +| 共通(RabbitMQ) | `rabbitmq-data` | +| 3層Web/BFF(フロント) | `frontend_node_modules` / `webui_node_modules` | +| BFF(BFF層・TS) | `bff_node_modules` | +| BFF(BFF層・Go) | `bff_go_mod_cache` | +| BFF(BFF層・Rust) | `bff_cargo_cache`, `bff_target_cache` | +| BFF(BFF層・Java/Kotlin) | `bff_gradle_cache` | +| BFF(BFF層・Python) | (不要) | + +### .dockerignore テンプレート + +``` +.git +.env* +*.log +tmp/ +``` + +言語固有の除外は各 scaffolding ファイルの Docker ガイドを参照。 diff --git a/skills/dev-init/references/go-scaffolding.md b/skills/dev-init/references/go-scaffolding.md new file mode 100644 index 0000000..b057455 --- /dev/null +++ b/skills/dev-init/references/go-scaffolding.md @@ -0,0 +1,133 @@ +# Go スキャフォールディングガイド + +## CLI ツール + +| コマンド | 用途 | +|---------|------| +| `go mod init ` | go.mod 初期化(例: `github.com/user/project`) | +| `go mod tidy` | 依存の整理・不要依存の削除 | +| `go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest` | Linter インストール | + +Go は CLI スキャフォールドツールを持たない。ディレクトリ構造を手動で構築する。 + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | +|--------|-----|-------------| +| Web/API | Echo | `github.com/labstack/echo/v4` | +| Web/API | Gin | `github.com/gin-gonic/gin` | +| Web/API | Chi | `github.com/go-chi/chi/v5` | +| CLI | cobra | `github.com/spf13/cobra` | +| テスト補助 | testify | `github.com/stretchr/testify`(dev のみ) | + +### go.mod 重要フィールド + +- `go`: Go バージョン指定(`go 1.22`) +- `module`: モジュールパス + +### ディレクトリ構造ガイド + +Go はディレクトリ構造が特に重要(慣習ベース)。`project-root/` = `$(git rev-parse --show-toplevel)` で取得するプロジェクトルートディレクトリ。 + +``` +project-root/ +├── cmd//main.go # エントリポイント +├── internal/ # プライベートパッケージ(外部非公開) +│ ├── handler/ # HTTP ハンドラ +│ ├── service/ # ビジネスロジック +│ ├── repository/ # データアクセス +│ └── model/ # データモデル +├── pkg/ # 外部公開パッケージ(ライブラリの場合) +├── go.mod +└── go.sum +``` + +CLI の場合: +``` +project-root/ +├── cmd//main.go +├── internal/ +│ └── cmd/ # サブコマンド定義 +├── go.mod +└── go.sum +``` + +## 設定ファイル + +### golangci-lint 設定(.golangci.yml) + +```yaml +linters: + enable: + - errcheck + - govet + - staticcheck + - unused + - gosimple + - ineffassign +``` + +チーム規模別: +- 個人: `go vet` のみ +- 小規模: 上記基本セット +- 大規模: `+ gocyclo, dupl, goconst, misspell, revive` + +### テスト設定 + +Go はテスト設定ファイル不要。`*_test.go` を同パッケージに配置するだけ。 + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| API (Echo) | `cmd/server/main.go` | Echo インスタンス作成・ルート登録・Start | +| API (Gin) | `cmd/server/main.go` | Gin Engine 作成・ルート登録・Run | +| CLI (cobra) | `cmd//main.go` | rootCmd.Execute() | +| ライブラリ | `.go` | パッケージルート | + +## テスト雛形 + +- ファイル配置: 対象ファイルと同ディレクトリに `_test.go` +- テーブルドリブンテスト推奨 +- API テスト: `net/http/httptest` パッケージ +- 最小構成: ハンドラの HTTP テスト or パッケージのインポート確認 + +## Docker ガイド + +- ベースイメージ: `golang:1.22` → 本番: `gcr.io/distroless/static-debian12` +- マルチステージ: `builder`(`CGO_ENABLED=0 go build`)→ `runner`(バイナリのみ) +- `.dockerignore`: `.git`, `.env*`, `*.test` + +### 開発用 Docker + +- 開発用ベースイメージ: `golang:1.22` +- Volume mount: `- .:/app` でソースコードをマウント、`go-mod-cache` は named volume で分離 +- Hot-reload: `air`(air のインストールが必要)で自動再起動 +- Linter: `golangci-lint`(Dockerfile.dev でインストール) +- Dockerfile.dev: マルチステージ不要、air + golangci-lint インストール + go mod download + air コマンド +- `.air.toml` を生成し、監視対象を制限する: + - `root` = `"."` + - `watch_dir` = `["cmd", "internal"]`(`pkg` がある場合は追加) + - `exclude_dir` = `["tmp", "vendor", ".git", "node_modules"]` + - `include_ext` = `["go", "toml", "yaml"]` + +## CI (GitHub Actions) ガイド + +- Go セットアップ: `actions/setup-go@v5` + `go-version-file: 'go.mod'` +- キャッシュ: `actions/setup-go` が自動キャッシュ +- Lint: `golangci/golangci-lint-action@v6` +- ステップ: lint → `go test ./...` → `go build ./...` + +## 検証コマンド + +| 操作 | コマンド | +|------|---------| +| 依存解決 | `go mod tidy` | +| ビルド | `go build ./...` | +| テスト | `go test ./...` | +| テスト(カバレッジ) | `go test -cover ./...` | +| Lint | `golangci-lint run` | +| フォーマット確認 | `gofmt -l .` | +| Vet | `go vet ./...` | diff --git a/skills/dev-init/references/java-scaffolding.md b/skills/dev-init/references/java-scaffolding.md new file mode 100644 index 0000000..04cc3b9 --- /dev/null +++ b/skills/dev-init/references/java-scaffolding.md @@ -0,0 +1,102 @@ +# Java スキャフォールディングガイド + +## CLI ツール + +| FW | コマンド | 備考 | +|----|---------|------| +| Spring Boot | `spring init --type=gradle-project --language=java --boot-version=3.3 --java-version=21 --dependencies= ` | Spring CLI 必要 | +| Spring Boot (curl) | `curl https://start.spring.io/starter.zip -d type=gradle-project -d language=java -d dependencies= -o .zip` | CLI 不要 | +| Quarkus | `quarkus create app : --extensions=` | Quarkus CLI 必要 | +| Micronaut | `mn create-app --features= --build=gradle_kotlin --lang=java` | Micronaut CLI 必要 | +| 汎用 | `gradle init --type java-application --dsl kotlin` | Gradle のみ | + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | testDependencies | +|--------|-----|-------------|-----------------| +| API | Spring Boot | `spring-boot-starter-web` | `spring-boot-starter-test` | +| API | Quarkus | `quarkus-rest` | `quarkus-junit5 rest-assured` | +| API | Micronaut | `micronaut-http-server-netty` | `micronaut-test-junit5` | +| CLI | picocli | `info.picocli:picocli` | `junit-jupiter` | + +### build.gradle.kts 重要フィールド + +- `java.toolchain.languageVersion`: `JavaLanguageVersion.of(21)` +- `plugins`: `java`, `application`(CLI), `org.springframework.boot`(Spring) +- `group` / `version`: プロジェクト識別子 +- `repositories`: `mavenCentral()` + +## 設定ファイル + +### application.yml(Spring Boot) + +- `server.port`: `8080` +- `spring.application.name`: プロジェクト名 +- `logging.level.root`: `INFO` + +### application.properties / application.yml 共通 + +- プロファイル: `application-dev.yml`, `application-prod.yml` +- テスト用: `src/test/resources/application-test.yml` + +### Checkstyle 設定 + +- Google Java Style ベース: `google_checks.xml` +- チーム規模大: カスタムルール追加 +- `build.gradle.kts`: `checkstyle { configFile = file("config/checkstyle/checkstyle.xml") }` + +### チーム規模別調整 + +- 個人: Checkstyle なし、IDE フォーマッタのみ +- 小規模: google-java-format + 基本 Checkstyle +- 大規模: Checkstyle 厳格 + SpotBugs + PMD + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| API (Spring) | `src/main/java/.../Application.java` | `@SpringBootApplication` + `main()` | +| API (Quarkus) | `src/main/java/.../GreetingResource.java` | `@Path` リソースクラス | +| CLI (picocli) | `src/main/java/.../App.java` | `@Command` + `Callable` | +| ライブラリ | `src/main/java/.../.java` | パブリック API クラス | + +## テスト雛形 + +- ファイル配置: `src/test/java//` に `*Test.java` +- Spring Boot: `@SpringBootTest` + `MockMvc` +- Quarkus: `@QuarkusTest` + RestAssured +- 最小構成: コンテキスト読み込みテスト + ヘルスチェックテスト + +## Docker ガイド + +- ベースイメージ: `eclipse-temurin:21-jre-jammy`(本番)/ `eclipse-temurin:21-jdk-jammy`(ビルド) +- マルチステージ: `builder`(Gradle ビルド)→ `runner`(JAR 実行) +- Gradle キャッシュ: `build.gradle.kts` と `settings.gradle.kts` を先にコピー +- `.dockerignore`: `.gradle`, `build`, `.git`, `.env*` + +### 開発用 Docker + +- 開発用ベースイメージ: `eclipse-temurin:21`(JDK フル) +- Volume mount: `- .:/app` でソースコードをマウント、`gradle-cache` は named volume で分離 +- Hot-reload: `./gradlew bootRun`(Spring DevTools による自動再起動) +- Dockerfile.dev: マルチステージ不要、Gradle Wrapper + 依存解決 + bootRun コマンド + +## CI (GitHub Actions) ガイド + +- Java セットアップ: `actions/setup-java@v4` + `distribution: 'temurin'` + `java-version: '21'` +- Gradle キャッシュ: `actions/setup-java` の `cache: 'gradle'` +- ステップ: `./gradlew check` → `./gradlew test` → `./gradlew build` +- Gradle Wrapper コミット: `gradlew`, `gradlew.bat`, `gradle/wrapper/` を VCS に含める + +## 検証コマンド + +| 操作 | コマンド | +|------|---------| +| 依存解決 | `./gradlew dependencies` | +| ビルド | `./gradlew build` | +| テスト | `./gradlew test` | +| Lint | `./gradlew checkstyleMain` | +| 実行 | `./gradlew bootRun`(Spring)/ `./gradlew run`(汎用) | +| クリーン | `./gradlew clean` | diff --git a/skills/dev-init/references/kotlin-scaffolding.md b/skills/dev-init/references/kotlin-scaffolding.md new file mode 100644 index 0000000..9d7354c --- /dev/null +++ b/skills/dev-init/references/kotlin-scaffolding.md @@ -0,0 +1,103 @@ +# Kotlin スキャフォールディングガイド + +## CLI ツール + +| FW | コマンド | 備考 | +|----|---------|------| +| Ktor | `ktor generate --project-name= --features=` | Ktor CLI または start.ktor.io からダウンロード | +| Ktor (curl) | `curl 'https://start.ktor.io/project/generate?...' -o .zip` | CLI 不要 | +| Spring Boot (Kotlin) | `spring init --type=gradle-project --language=kotlin --java-version=21 --dependencies= ` | Spring CLI | +| 汎用 | `gradle init --type kotlin-application --dsl kotlin` | Gradle のみ | + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | testDependencies | +|--------|-----|-------------|-----------------| +| API | Ktor | `ktor-server-core ktor-server-netty ktor-server-content-negotiation ktor-serialization-kotlinx-json` | `ktor-server-test-host kotlin-test-junit5` | +| API | Spring Boot | `spring-boot-starter-web` | `spring-boot-starter-test` | +| CLI | clikt | `com.github.ajalt.clikt:clikt` | `kotlin-test-junit5` | +| ライブラリ | — | `kotlin-stdlib` | `kotlin-test-junit5` | + +### build.gradle.kts 重要フィールド(Java との差分) + +- `plugins`: `kotlin("jvm")`, `kotlin("plugin.serialization")`(Ktor) +- `kotlin.jvmToolchain(21)` +- Ktor: `application { mainClass.set("com.example.ApplicationKt") }` +- Spring: `kotlin("plugin.spring")` プラグイン追加 + +## 設定ファイル + +### Kotlin コンパイラ設定(build.gradle.kts) + +- `kotlin.compilerOptions.jvmTarget`: `JvmTarget.JVM_21` +- `kotlin.compilerOptions.allWarningsAsErrors`: `true`(チーム規模大) +- `kotlin.compilerOptions.freeCompilerArgs`: `["-Xjsr305=strict"]`(Spring) + +### テスト設定 + +- JUnit 5: `tasks.test { useJUnitPlatform() }` +- Kover(カバレッジ): `plugins { id("org.jetbrains.kotlinx.kover") }` + +### ktlint + detekt 設定 + +ktlint(フォーマッタ): +- Gradle プラグイン: `org.jlleitschuh.gradle.ktlint` +- デフォルトルールセットで十分 + +detekt(静的解析): +- Gradle プラグイン: `io.gitlab.arturbosch.detekt` +- 設定ファイル: `detekt.yml` +- チーム規模別: 個人=デフォルト、大規模=`complexity` ルール厳格化 + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| API (Ktor) | `src/main/kotlin/.../Application.kt` | `embeddedServer(Netty)` + モジュール設定 | +| API (Ktor) | `src/main/kotlin/.../plugins/Routing.kt` | ルーティング定義 | +| API (Spring) | `src/main/kotlin/.../Application.kt` | `@SpringBootApplication` + `runApplication<>()` | +| CLI (clikt) | `src/main/kotlin/.../Main.kt` | `CliktCommand` サブクラス | +| ライブラリ | `src/main/kotlin/.../.kt` | パブリック API | + +## テスト雛形 + +- ファイル配置: `src/test/kotlin//` に `*Test.kt` +- Ktor: `testApplication { }` DSL でサーバーテスト +- Spring: `@SpringBootTest` + `MockMvc`(Java と共通) +- 最小構成: アプリケーション起動テスト + ルーティングテスト + +## Docker ガイド + +- ベースイメージ: Java と共通(`eclipse-temurin:21-jre-jammy`) +- マルチステージ: `builder`(Gradle ビルド)→ `runner`(JAR / fat JAR 実行) +- Ktor: `ktor-server-cio` で軽量 fat JAR 生成(`id("io.ktor.plugin")` + `ktor { fatJar {} }`) +- `.dockerignore`: `.gradle`, `build`, `.git`, `.env*` + +### 開発用 Docker + +- 開発用ベースイメージ: `eclipse-temurin:21`(JDK フル、Java と共通) +- Volume mount: `- .:/app` でソースコードをマウント、`gradle-cache` は named volume で分離 +- Hot-reload: `./gradlew run --continuous`(Ktor)/ `./gradlew bootRun`(Spring Boot Kotlin)で自動再起動 +- Dockerfile.dev: マルチステージ不要、Gradle Wrapper + 依存解決 + run コマンド + +## CI (GitHub Actions) ガイド + +- Java セットアップ: Java と共通(`actions/setup-java@v4`) +- Gradle キャッシュ: `cache: 'gradle'` +- ステップ: `./gradlew ktlintCheck` → `./gradlew detekt` → `./gradlew test` → `./gradlew build` +- Kover レポート: `./gradlew koverXmlReport` + +## 検証コマンド + +| 操作 | コマンド | +|------|---------| +| 依存解決 | `./gradlew dependencies` | +| ビルド | `./gradlew build` | +| テスト | `./gradlew test` | +| Lint(ktlint) | `./gradlew ktlintCheck` | +| 静的解析(detekt) | `./gradlew detekt` | +| カバレッジ | `./gradlew koverXmlReport` | +| 実行 (Ktor) | `./gradlew run` | +| 実行 (Spring) | `./gradlew bootRun` | diff --git a/skills/dev-init/references/python-scaffolding.md b/skills/dev-init/references/python-scaffolding.md new file mode 100644 index 0000000..2ebfd0a --- /dev/null +++ b/skills/dev-init/references/python-scaffolding.md @@ -0,0 +1,104 @@ +# Python スキャフォールディングガイド + +## CLI ツール + +| FW | コマンド | 備考 | +|----|---------|------| +| 汎用 | `uv init ` | pyproject.toml + src レイアウト生成 | +| Django | `uv run django-admin startproject ` | Django の標準スキャフォールド | +| FastAPI | なし | 直接生成 | +| Flask | なし | 直接生成 | + +### 環境構築手順 + +``` +uv init +cd +uv add +uv sync +``` + +`uv` がない環境のフォールバック: `python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]"` + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | dev-dependencies | +|--------|-----|-------------|-----------------| +| Web | Django | `django` | `pytest pytest-django ruff` | +| API | FastAPI | `fastapi uvicorn[standard]` | `pytest httpx ruff` | +| API | Flask | `flask` | `pytest ruff` | +| CLI | Typer | `typer` | `pytest ruff` | +| ライブラリ | — | — | `pytest ruff` | + +### pyproject.toml 重要フィールド + +- `project.requires-python`: `">=3.12"` +- `project.scripts`: CLI エントリポイント +- `build-system`: `hatchling` / `setuptools` +- `tool.uv.dev-dependencies`: 開発用依存 + +## 設定ファイル + +### pyproject.toml(ツール設定統合) + +- `tool.ruff.line-length`: `88`(デフォルト)/ `120`(チーム規模大) +- `tool.ruff.lint.select`: `["E", "F", "I", "UP"]`(推奨最小セット) +- `tool.ruff.format.quote-style`: `"double"` +- `tool.pytest.ini_options.testpaths`: `["tests"]` +- `tool.pytest.ini_options.addopts`: `"-v --tb=short"` + +### チーム規模別 ruff 設定 + +- 個人: `select = ["E", "F"]` +- 小規模: `select = ["E", "F", "I", "UP", "B"]` +- 大規模: `select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]` + `lint.isort.known-first-party` + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| API (FastAPI) | `src/app/main.py` | FastAPI app 作成・ルーター登録 | +| API (Django) | `/wsgi.py` | WSGI アプリケーション | +| CLI (Typer) | `src//cli.py` | Typer app 定義・コマンド登録 | +| ライブラリ | `src//__init__.py` | パブリック API | + +## テスト雛形 + +- ファイル配置: `tests/test_.py` +- FastAPI: `httpx.AsyncClient` + `app` で非同期テスト +- Django: `django.test.TestCase` or `pytest-django` +- 最小構成: インポート確認テスト + ヘルスチェックテスト(API の場合) + +## Docker ガイド + +- ベースイメージ: `python:3.12-slim` +- マルチステージ: `builder`(uv + 依存インストール)→ `runner`(コピー) +- uv in Docker: `COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv` +- `.dockerignore`: `.venv`, `__pycache__`, `.git`, `.env*`, `*.pyc` + +### 開発用 Docker + +- 開発用ベースイメージ: `python:3.12-slim` + uv +- Volume mount: `- .:/app` でソースコードをマウント +- Hot-reload: `uv run uvicorn --reload`(FastAPI)/ `uv run python manage.py runserver`(Django)で自動再起動 +- Dockerfile.dev: マルチステージ不要、uv インストール + 依存 sync + dev server コマンド + +## CI (GitHub Actions) ガイド + +- Python セットアップ: `actions/setup-python@v5` + `python-version: '3.12'` +- uv セットアップ: `astral-sh/setup-uv@v3` +- キャッシュ: uv が自動キャッシュ管理 +- ステップ: `uv sync` → `uv run ruff check` → `uv run ruff format --check` → `uv run pytest` + +## 検証コマンド + +| 操作 | コマンド | +|------|---------| +| 依存インストール | `uv sync` | +| テスト | `uv run pytest` | +| Lint | `uv run ruff check .` | +| フォーマット確認 | `uv run ruff format --check .` | +| 開発サーバー (FastAPI) | `uv run uvicorn app.main:app --reload` | +| 開発サーバー (Django) | `uv run python manage.py runserver` | diff --git a/skills/dev-init/references/rust-scaffolding.md b/skills/dev-init/references/rust-scaffolding.md new file mode 100644 index 0000000..e05b209 --- /dev/null +++ b/skills/dev-init/references/rust-scaffolding.md @@ -0,0 +1,99 @@ +# Rust スキャフォールディングガイド + +## CLI ツール + +| コマンド | 用途 | オプション | +|---------|------|-----------| +| `cargo init ` | 既存ディレクトリに初期化 | `--lib`(ライブラリ)、デフォルトはバイナリ | +| `cargo new ` | 新規ディレクトリ作成 | `--lib`(ライブラリ) | + +cargo がプロジェクト構造・ビルド・テスト・依存管理を統合的に担う。追加ツールは不要。 + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | dev-dependencies | +|--------|-----|-------------|-----------------| +| Web | Axum + Leptos | `axum leptos tokio` | — | +| API | Axum | `axum tokio serde serde_json` | — | +| API | Actix Web | `actix-web serde serde_json tokio` | — | +| CLI | clap | `clap` (features: `["derive"]`) | — | +| ライブラリ | — | — | — | + +Rust は `[dev-dependencies]` に直接テスト用クレートを記載: +- `tokio` (features: `["test-util"]`)、API テスト用: `reqwest` or `axum::test` + +### Cargo.toml 重要フィールド + +- `edition`: `"2024"` +- `rust-version`: MSRV 指定(`"1.80"` 等) +- `[profile.release]`: `lto = true`, `strip = true`(バイナリサイズ最適化) + +## 設定ファイル + +### clippy 設定(clippy.toml / Cargo.toml) + +- Cargo.toml 内: `[lints.clippy]` セクションで lint レベル制御 +- 推奨: `pedantic = "warn"`(チーム規模大) +- 個人: デフォルト lint のみ + +### rustfmt 設定(rustfmt.toml) + +- `edition`: `"2024"` +- `max_width`: `100` +- `use_field_init_shorthand`: `true` + +### チーム規模別調整 + +- 個人: clippy デフォルト、`#[deny(warnings)]` なし +- 小規模: `clippy::all` を warn +- 大規模: `clippy::pedantic` を warn + `#![deny(missing_docs)]` + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| API (Axum) | `src/main.rs` | Router 構築・`tokio::main` でサーバー起動 | +| API (Actix) | `src/main.rs` | `HttpServer::new` + `actix_web::main` | +| CLI (clap) | `src/main.rs` | `#[derive(Parser)]` 構造体 + `main()` | +| ライブラリ | `src/lib.rs` | パブリック API モジュール宣言 | + +## テスト雛形 + +- 単体テスト: 同ファイル内 `#[cfg(test)] mod tests` +- 結合テスト: `tests/` ディレクトリ +- API テスト: `axum::test::TestClient` or `actix_web::test` +- 最小構成: `#[test] fn it_works()` + API の場合ヘルスチェックテスト + +## Docker ガイド + +- ベースイメージ: `rust:1.80-slim` → 本番: `debian:bookworm-slim` +- マルチステージ: `builder`(cargo build --release)→ `runner`(バイナリのみコピー) +- cargo キャッシュ最適化: `Cargo.toml` と `Cargo.lock` を先にコピーし `cargo build` でキャッシュ層作成 +- `.dockerignore`: `target`, `.git`, `.env*` + +### 開発用 Docker + +- 開発用ベースイメージ: `rust:1.82` +- Volume mount: `- .:/app` でソースコードをマウント、`target` と `cargo-cache` は named volume で分離 +- Hot-reload: `cargo watch -w src -w Cargo.toml -x run`(cargo-watch のインストールが必要)で自動再起動。`-w` で監視対象を `src/` と `Cargo.toml` に限定し、不要な再ビルドを防ぐ +- Dockerfile.dev: マルチステージ不要、cargo-watch インストール + 依存プリフェッチ + watch コマンド + +## CI (GitHub Actions) ガイド + +- Rust セットアップ: `dtolnay/rust-toolchain@stable` +- キャッシュ: `Swatinem/rust-cache@v2` +- ステップ: `cargo fmt --check` → `cargo clippy -- -D warnings` → `cargo test` → `cargo build --release` +- マトリクス: stable + MSRV + +## 検証コマンド + +| 操作 | コマンド | +|------|---------| +| 依存解決 | `cargo fetch` | +| ビルド | `cargo build` | +| テスト | `cargo test` | +| Lint | `cargo clippy -- -D warnings` | +| フォーマット確認 | `cargo fmt --check` | +| リリースビルド | `cargo build --release` | diff --git a/skills/dev-init/references/tech-recommendations.md b/skills/dev-init/references/tech-recommendations.md new file mode 100644 index 0000000..473cbad --- /dev/null +++ b/skills/dev-init/references/tech-recommendations.md @@ -0,0 +1,700 @@ +# 技術スタック推奨表 + +dev-init スキルがヒアリング結果に基づいて技術スタックを推奨する際のロジックとデフォルト値を定義する。 + +## フレームワーク推奨マトリクス + +### TypeScript + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | 推奨4 | +|------------------|-------|-------|-------|-------| +| Webアプリ(フルスタック) | Next.js(App Router) | Remix | Hono + htmx | Astro | +| 3層Web(フロント) | Next.js(App Router) | Remix | Vite + React | Astro | +| 3層Web(バックエンド) | Hono | Fastify | Express | NestJS | +| BFF(UI) | Next.js(App Router) | Remix | Vite + React | — | +| BFF(モバイルUI) | React Native | Expo | — | — | +| BFF(BFF層) | Hono | Fastify | Express | NestJS | +| BFF(サービス層) | Hono | Fastify | NestJS | — | +| APIサーバー | Hono | Fastify | Express | NestJS | +| バッチ処理(cron/OS) | tsx(スクリプト実行) | node-cron | — | — | +| バッチ処理(クラウド) | tsx(スクリプト実行) | Hono(Webhook受信) | — | — | +| バッチ処理(FW内蔵) | BullMQ | node-cron | Agenda | — | +| マイクロサービス(REST) | Hono | Fastify | NestJS | — | +| マイクロサービス(gRPC) | NestJS | grpc-js + Fastify | Hono + nice-grpc | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | — | +| イベント駆動(Kafka) | Hono + KafkaJS | Fastify + KafkaJS | — | — | +| イベント駆動(RabbitMQ) | Hono + amqplib | Fastify + amqplib | — | — | +| イベント駆動(SQS/SNS) | Hono + @aws-sdk | Fastify + @aws-sdk | — | — | +| イベント駆動(Redis) | Hono + ioredis | Fastify + ioredis | — | — | +| GAS | clasp + esbuild | clasp + rollup | — | — | +| CLIツール | Commander.js | oclif | — | — | +| ライブラリ/パッケージ | (FW不要) | — | — | — | + +### Python + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | +|------------------|-------|-------|-------| +| Webアプリ(フルスタック) | Django | FastAPI + Jinja2 | Flask | +| 3層Web(バックエンド) | FastAPI | Django REST Framework | Flask | +| BFF(BFF層) | FastAPI | Flask | Litestar | +| BFF(サービス層) | FastAPI | Django REST Framework | Flask | +| APIサーバー | FastAPI | Django REST Framework | Flask | +| バッチ処理(cron/OS) | スクリプト実行 | APScheduler | — | +| バッチ処理(クラウド) | FastAPI(Webhook受信) | Flask | — | +| バッチ処理(FW内蔵) | Celery | APScheduler | Dramatiq | +| マイクロサービス(REST) | FastAPI | Flask | Litestar | +| マイクロサービス(gRPC) | grpcio + FastAPI | grpcio | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | +| イベント駆動(Kafka) | FastAPI + aiokafka | Faust | — | +| イベント駆動(RabbitMQ) | FastAPI + aio-pika | Celery | — | +| イベント駆動(SQS/SNS) | FastAPI + boto3 | — | — | +| イベント駆動(Redis) | FastAPI + redis-py | — | — | +| CLIツール | Typer | Click | argparse | +| ライブラリ/パッケージ | (FW不要) | — | — | + +### Rust + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | +|------------------|-------|-------|-------| +| Webアプリ(フルスタック) | Axum + Leptos | Actix Web | — | +| 3層Web(バックエンド) | Axum | Actix Web | Rocket | +| BFF(BFF層) | Axum | Actix Web | Rocket | +| BFF(サービス層) | Axum | Actix Web | Rocket | +| APIサーバー | Axum | Actix Web | Rocket | +| バッチ処理(cron/OS) | tokio(スクリプト実行) | clap + tokio | — | +| バッチ処理(クラウド) | Axum(Webhook受信) | clap + tokio | — | +| バッチ処理(FW内蔵) | tokio-cron-scheduler | clap + tokio | — | +| マイクロサービス(REST) | Axum | Actix Web | Rocket | +| マイクロサービス(gRPC) | Tonic | Axum + tonic | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | +| イベント駆動(Kafka) | Axum + rdkafka | Actix Web + rdkafka | — | +| イベント駆動(RabbitMQ) | Axum + lapin | Actix Web + lapin | — | +| イベント駆動(SQS/SNS) | Axum + aws-sdk-rust | — | — | +| イベント駆動(Redis) | Axum + redis-rs | — | — | +| CLIツール | clap | — | — | +| ライブラリ/パッケージ | (FW不要) | — | — | + +### Go + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | +|------------------|-------|-------|-------| +| Webアプリ(フルスタック) | Echo + templ | Gin | Chi | +| 3層Web(バックエンド) | Echo | Gin | Chi | +| BFF(BFF層) | Echo | Gin | Chi | +| BFF(サービス層) | Echo | Gin | Chi | +| APIサーバー | Echo | Gin | Chi | +| バッチ処理(cron/OS) | cobra + cron | スクリプト実行 | — | +| バッチ処理(クラウド) | Echo(Webhook受信) | cobra | — | +| バッチ処理(FW内蔵) | go-co-op/gocron | robfig/cron | — | +| マイクロサービス(REST) | Echo | Gin | Chi | +| マイクロサービス(gRPC) | grpc-go | go-micro | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | +| イベント駆動(Kafka) | Echo + sarama | Gin + sarama | — | +| イベント駆動(RabbitMQ) | Echo + amqp091-go | Gin + amqp091-go | — | +| イベント駆動(SQS/SNS) | Echo + aws-sdk-go-v2 | Gin + aws-sdk-go-v2 | — | +| イベント駆動(Redis) | Echo + go-redis | Gin + go-redis | — | +| CLIツール | cobra | urfave/cli | — | +| ライブラリ/パッケージ | (FW不要) | — | — | + +### Java + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | 推奨4 | +|------------------|-------|-------|-------|-------| +| Webアプリ(フルスタック) | Spring Boot | Quarkus | Micronaut | — | +| 3層Web(バックエンド) | Spring Boot | Quarkus | Micronaut | — | +| BFF(BFF層) | Spring Boot | Quarkus | Micronaut | — | +| BFF(サービス層) | Spring Boot | Quarkus | Micronaut | — | +| APIサーバー | Spring Boot | Quarkus | Micronaut | — | +| バッチ処理(cron/OS) | Spring Batch | Quarkus | — | — | +| バッチ処理(クラウド) | Spring Boot(Webhook受信) | Quarkus | — | — | +| バッチ処理(FW内蔵) | Spring Batch + Spring Scheduler | Quarkus Scheduler | — | — | +| マイクロサービス(REST) | Spring Boot | Quarkus | Micronaut | — | +| マイクロサービス(gRPC) | Spring Boot + grpc-spring-boot-starter | Quarkus gRPC | Micronaut gRPC | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | — | +| イベント駆動(Kafka) | Spring Boot + Spring Kafka | Quarkus + SmallRye Reactive | — | — | +| イベント駆動(RabbitMQ) | Spring Boot + Spring AMQP | Quarkus + SmallRye Reactive | — | — | +| イベント駆動(SQS/SNS) | Spring Boot + Spring Cloud AWS | — | — | — | +| イベント駆動(Redis) | Spring Boot + Spring Data Redis | — | — | — | +| CLIツール | picocli | Spring Shell | — | — | +| ライブラリ/パッケージ | (FW不要) | — | — | — | + +### Kotlin + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | +|------------------|-------|-------|-------| +| Webアプリ(フルスタック) | Spring Boot (Kotlin) | Ktor | — | +| 3層Web(バックエンド) | Ktor | Spring Boot (Kotlin) | — | +| BFF(BFF層) | Ktor | Spring Boot (Kotlin) | — | +| BFF(サービス層) | Ktor | Spring Boot (Kotlin) | — | +| APIサーバー | Ktor | Spring Boot (Kotlin) | — | +| バッチ処理(cron/OS) | Spring Batch (Kotlin) | Ktor | — | +| バッチ処理(クラウド) | Ktor(Webhook受信) | Spring Boot (Kotlin) | — | +| バッチ処理(FW内蔵) | Spring Batch (Kotlin) + Spring Scheduler | Quarkus Scheduler | — | +| マイクロサービス(REST) | Ktor | Spring Boot (Kotlin) | — | +| マイクロサービス(gRPC) | grpc-kotlin + Ktor | Spring Boot (Kotlin) + grpc-spring-boot-starter | — | +| マイクロサービス(メッセージキュー) | (イベント駆動の該当ブローカー行を参照) | — | — | +| イベント駆動(Kafka) | Ktor + kotlin-kafka | Spring Boot (Kotlin) + Spring Kafka | — | +| イベント駆動(RabbitMQ) | Ktor + rabbitmq-kotlin | Spring Boot (Kotlin) + Spring AMQP | — | +| イベント駆動(SQS/SNS) | Ktor + aws-sdk-kotlin | Spring Boot (Kotlin) + Spring Cloud AWS | — | +| イベント駆動(Redis) | Ktor + kreds | Spring Boot (Kotlin) + Spring Data Redis | — | +| CLIツール | clikt | picocli | — | +| ライブラリ/パッケージ | (FW不要) | — | — | + +### Dart + +| プロジェクトタイプ | 推奨1 | 推奨2 | 推奨3 | +|------------------|-------|-------|-------| +| Webアプリ(モバイル含む) | Flutter | — | — | +| BFF(UI) | Flutter | — | — | +| APIサーバー | dart_frog | shelf | — | +| CLIツール | dcli | args | — | +| ライブラリ/パッケージ | (FW不要) | — | — | + +## パッケージマネージャ推奨表 + +| 言語 | 推奨(デフォルト) | 代替 | 備考 | +|------|------------------|------|------| +| TypeScript | pnpm | bun, yarn, npm | pnpm: ディスク効率・厳格な依存管理 | +| Python | uv | pip, poetry, rye | uv: 高速・Rust製 | +| Rust | cargo | — | 標準 | +| Go | go mod | — | 標準 | +| Java | Gradle (Kotlin DSL) | Maven | — | +| Kotlin | Gradle (Kotlin DSL) | — | — | +| Dart | pub | — | Flutter プロジェクトでも pub を使用 | + +## テストフレームワーク推奨表 + +| 言語 | 単体テスト(推奨) | E2Eテスト | カバレッジ | +|------|------------------|----------|-----------| +| TypeScript | Vitest | Playwright | vitest --coverage | +| Python | pytest | Playwright | pytest --cov | +| Rust | cargo test(標準) | — | cargo tarpaulin | +| Go | go test + testify | — | go test -cover | +| Java | JUnit 5 | — | JaCoCo | +| Kotlin | JUnit 5 + kotlin-test | — | Kover | +| Dart | package:test | integration_test | dart test --coverage | + +## Linter / Formatter 推奨表 + +| 言語 | Linter + Formatter(推奨) | 代替 | +|------|--------------------------|------| +| TypeScript | Biome | ESLint + Prettier | +| Python | Ruff | flake8 + black | +| Rust | clippy + rustfmt | — | +| Go | golangci-lint + gofmt | — | +| Java | Checkstyle + google-java-format | — | +| Kotlin | ktlint + detekt | — | +| Dart | dart analyze + dart format | — | + +## データベース推奨ロジック + +| 条件 | 推奨 | 理由 | +|------|------|------| +| 汎用・デフォルト | PostgreSQL | 拡張性・エコシステム・信頼性 | +| 組み込み・軽量・開発用 | SQLite | ゼロ設定・ファイルベース | +| ドキュメント指向・スキーマレス | MongoDB | 柔軟なスキーマ | +| KV・キャッシュ | Redis | 高速・インメモリ | + +## ディレクトリ構造テンプレート + +> `project-root/` = `$(git rev-parse --show-toplevel)` で取得するプロジェクトルートディレクトリ + +### TypeScript Webアプリ(Next.js) + +``` +project-root/ +├── src/ +│ ├── app/ # App Router pages & layouts +│ ├── components/ # UIコンポーネント +│ ├── lib/ # ビジネスロジック・ユーティリティ +│ └── types/ # 型定義 +├── tests/ +│ ├── unit/ # 単体テスト +│ └── e2e/ # E2Eテスト +├── public/ # 静的ファイル +├── package.json +├── tsconfig.json +├── biome.json +└── vitest.config.ts +``` + +### TypeScript APIサーバー(Hono) + +``` +project-root/ +├── src/ +│ ├── routes/ # ルートハンドラ +│ ├── services/ # ビジネスロジック +│ ├── repositories/ # データアクセス +│ ├── middleware/ # ミドルウェア +│ ├── types/ # 型定義 +│ └── index.ts # エントリポイント +├── tests/ +│ ├── unit/ +│ └── integration/ +├── package.json +├── tsconfig.json +├── biome.json +└── vitest.config.ts +``` + +### Python APIサーバー(FastAPI) + +``` +project-root/ +├── src/ +│ └── app/ +│ ├── routers/ # ルーター +│ ├── services/ # ビジネスロジック +│ ├── repositories/ # データアクセス +│ ├── models/ # データモデル +│ ├── schemas/ # Pydanticスキーマ +│ └── main.py # エントリポイント +├── tests/ +│ ├── unit/ +│ └── integration/ +├── pyproject.toml +└── ruff.toml +``` + +### Rust CLIツール + +``` +project-root/ +├── src/ +│ ├── commands/ # サブコマンド +│ ├── config/ # 設定 +│ ├── lib.rs # ライブラリルート +│ └── main.rs # エントリポイント +├── tests/ +│ └── integration/ +├── Cargo.toml +└── clippy.toml +``` + +### Go APIサーバー + +``` +project-root/ +├── cmd/ +│ └── server/ +│ └── main.go # エントリポイント +├── internal/ +│ ├── handler/ # HTTPハンドラ +│ ├── service/ # ビジネスロジック +│ ├── repository/ # データアクセス +│ └── model/ # データモデル +├── pkg/ # 外部公開パッケージ +├── go.mod +└── go.sum +``` + +### Java APIサーバー(Spring Boot) + +``` +project-root/ +├── src/ +│ ├── main/ +│ │ ├── java/com/example/app/ +│ │ │ ├── controller/ # RESTコントローラ +│ │ │ ├── service/ # ビジネスロジック +│ │ │ ├── repository/ # データアクセス +│ │ │ ├── model/ # エンティティ +│ │ │ ├── dto/ # データ転送オブジェクト +│ │ │ └── Application.java +│ │ └── resources/ +│ │ └── application.yml +│ └── test/java/com/example/app/ +├── build.gradle.kts +└── settings.gradle.kts +``` + +### Kotlin APIサーバー(Ktor) + +``` +project-root/ +├── src/ +│ ├── main/kotlin/com/example/app/ +│ │ ├── plugins/ # Ktor プラグイン設定 +│ │ ├── routes/ # ルーティング +│ │ ├── service/ # ビジネスロジック +│ │ ├── repository/ # データアクセス +│ │ ├── model/ # データモデル +│ │ └── Application.kt +│ └── test/kotlin/com/example/app/ +├── build.gradle.kts +└── settings.gradle.kts +``` + +### Dart Webアプリ(Flutter) + +``` +project-root/ +├── lib/ +│ ├── src/ +│ │ ├── features/ # 機能別モジュール +│ │ ├── core/ # 共通ロジック +│ │ └── widgets/ # 共通ウィジェット +│ └── main.dart # エントリポイント +├── test/ +│ ├── unit/ +│ └── widget/ +├── integration_test/ +├── pubspec.yaml +└── analysis_options.yaml +``` + +### 3層Webアプリ(モノレポ) + +``` +project-root/ +├── packages/ +│ ├── frontend/ # TypeScript フロントエンド +│ │ ├── src/ +│ │ │ ├── app/ # App Router pages & layouts +│ │ │ ├── components/ # UIコンポーネント +│ │ │ └── lib/ # フロント用ユーティリティ +│ │ ├── CLAUDE.md # フロントエンド固有の指示 +│ │ ├── package.json +│ │ └── tsconfig.json +│ ├── backend/ # Q2言語 バックエンド +│ │ ├── src/ +│ │ │ ├── routes/ # ルートハンドラ +│ │ │ ├── services/ # ビジネスロジック +│ │ │ └── repositories/ # データアクセス +│ │ ├── CLAUDE.md # バックエンド固有の指示 +│ │ └── package.json # or Cargo.toml / go.mod 等 +│ └── shared/ # 共有型定義・ユーティリティ +│ ├── src/ +│ │ └── types/ +│ └── package.json +├── tests/ +│ ├── unit/ +│ └── e2e/ +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json # ワークスペースルート +├── pnpm-workspace.yaml +└── biome.json +``` + +### BFF(Webのみ・単一サービス・モノレポ) + +``` +project-root/ +├── packages/ +│ ├── web-ui/ # Q4a言語 フロントエンド +│ │ ├── src/ +│ │ │ ├── app/ +│ │ │ └── components/ +│ │ ├── CLAUDE.md # UI固有の指示 +│ │ └── package.json +│ ├── bff/ # Q4b言語 BFF層 +│ │ ├── src/ +│ │ │ ├── routes/ # API集約ルート +│ │ │ ├── aggregators/ # データ集約・整形 +│ │ │ └── middleware/ +│ │ ├── CLAUDE.md # BFF固有の指示 +│ │ └── package.json +│ ├── service/ # Q4c言語 サービス層 +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── services/ # ビジネスロジック +│ │ │ └── repositories/ +│ │ ├── CLAUDE.md # サービス固有の指示 +│ │ └── package.json +│ └── shared/ # 共有型定義(同一言語: TS型、混合言語: OpenAPI/protobuf) +│ └── package.json +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json +├── pnpm-workspace.yaml # 全層TS時。混合言語時は Makefile + Docker Compose ベース +└── biome.json +``` + +### BFF(モバイルのみ・単一サービス・モノレポ) + +``` +project-root/ +├── packages/ +│ ├── mobile-ui/ # Q4a言語 モバイルUI(Docker外で実行) +│ │ ├── lib/ # or src/(言語依存) +│ │ ├── CLAUDE.md # モバイルUI固有の指示 +│ │ └── pubspec.yaml # or package.json(言語依存) +│ ├── bff/ # Q4b言語 BFF層 +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── aggregators/ +│ │ │ └── middleware/ +│ │ ├── CLAUDE.md # BFF固有の指示 +│ │ └── package.json +│ ├── service/ # Q4c言語 サービス層 +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── services/ +│ │ │ └── repositories/ +│ │ ├── CLAUDE.md # サービス固有の指示 +│ │ └── package.json +│ └── shared/ # 共有型定義(OpenAPI/protobuf 推奨) +│ └── package.json +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json +└── Makefile # 混合言語ビルドオーケストレーション +``` + +### BFF(Web+モバイル・単一サービス・モノレポ) + +``` +project-root/ +├── packages/ +│ ├── web-ui/ # TypeScript フロントエンド +│ │ ├── src/ +│ │ │ ├── app/ +│ │ │ └── components/ +│ │ ├── CLAUDE.md # WebUI固有の指示 +│ │ └── package.json +│ ├── mobile-ui/ # Q4a言語 モバイルUI(Docker外で実行) +│ │ ├── lib/ +│ │ ├── CLAUDE.md # モバイルUI固有の指示 +│ │ └── pubspec.yaml +│ ├── bff/ # Q4b言語 BFF層 +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── aggregators/ +│ │ │ └── middleware/ +│ │ ├── CLAUDE.md # BFF固有の指示 +│ │ └── package.json +│ ├── service/ # Q4c言語 サービス層 +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── services/ +│ │ │ └── repositories/ +│ │ ├── CLAUDE.md # サービス固有の指示 +│ │ └── package.json +│ └── shared/ # 共有型定義(OpenAPI/protobuf 推奨) +│ └── package.json +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json +└── Makefile # 混合言語ビルドオーケストレーション +``` + +### BFF(複数サービス・モノレポ) + +``` +project-root/ +├── packages/ +│ ├── web-ui/ # Q4a言語 フロントエンド +│ │ ├── CLAUDE.md # UI固有の指示 +│ │ └── ... +│ ├── bff/ # Q4b言語 BFF層 +│ │ ├── CLAUDE.md # BFF固有の指示 +│ │ └── ... +│ └── shared/ # 共有型定義 +│ └── ... +├── services/ +│ ├── service-a/ # サービスA +│ │ ├── src/ +│ │ ├── CLAUDE.md # サービスA固有の指示 +│ │ └── package.json +│ └── service-b/ # サービスB +│ ├── src/ +│ ├── CLAUDE.md # サービスB固有の指示 +│ └── package.json +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json +├── pnpm-workspace.yaml # 全層TS時。混合言語時は Makefile + Docker Compose ベース +└── biome.json +``` + +### バッチ処理 + +``` +project-root/ +├── src/ +│ ├── jobs/ # ジョブ定義 +│ ├── processors/ # 処理ロジック +│ ├── config/ # 設定・スケジュール定義 +│ ├── utils/ # ユーティリティ +│ └── index.ts # エントリポイント +├── tests/ +│ ├── unit/ +│ └── integration/ +├── package.json +└── biome.json +``` + +### マイクロサービス(モノレポ) + +``` +project-root/ +├── services/ +│ ├── service-a/ +│ │ ├── src/ +│ │ │ ├── routes/ +│ │ │ ├── services/ +│ │ │ └── index.ts +│ │ ├── tests/ +│ │ ├── CLAUDE.md # サービスA固有の指示 +│ │ ├── Dockerfile +│ │ └── package.json +│ └── service-b/ +│ ├── src/ +│ ├── tests/ +│ ├── CLAUDE.md # サービスB固有の指示 +│ ├── Dockerfile +│ └── package.json +├── packages/ +│ └── shared/ # 共有型定義・プロトコル定義 +│ └── package.json +├── CLAUDE.md # ワークスペース共通の指示 +├── package.json +├── pnpm-workspace.yaml +└── biome.json +``` + +### イベント駆動 + +``` +project-root/ +├── src/ +│ ├── events/ # イベントスキーマ定義 +│ ├── producers/ # イベント発行 +│ ├── consumers/ # イベント消費 +│ ├── services/ # ビジネスロジック +│ ├── config/ # ブローカー接続設定 +│ └── index.ts # エントリポイント +├── tests/ +│ ├── unit/ +│ └── integration/ +├── package.json +└── biome.json +``` + +### GAS(スタンドアロン) + +``` +project-root/ +├── src/ +│ ├── main.ts # エントリポイント +│ ├── functions/ # メイン機能 +│ ├── triggers/ # トリガー定義 +│ └── utils/ # ユーティリティ +├── tests/ +│ └── unit/ +├── dist/ # ビルド成果物(.gitignore対象) +├── .clasp.json # clasp プロジェクト設定 +├── appsscript.json # GAS マニフェスト +├── package.json +├── tsconfig.json +├── biome.json +└── vitest.config.ts +``` + +### GAS(スプレッドシート連携) + +``` +project-root/ +├── src/ +│ ├── main.ts # エントリポイント(onOpen メニュー登録) +│ ├── menu/ # カスタムメニュー定義 +│ ├── functions/ # カスタム関数(CUSTOM_FUNC 等) +│ ├── sheets/ # シート操作ロジック +│ ├── triggers/ # トリガー定義 +│ └── utils/ # ユーティリティ +├── tests/ +│ └── unit/ +├── dist/ +├── .clasp.json +├── appsscript.json # oauthScopes にスプレッドシート権限を含む +├── package.json +├── tsconfig.json +├── biome.json +└── vitest.config.ts +``` + +### GAS(Webアプリ) + +``` +project-root/ +├── src/ +│ ├── main.ts # エントリポイント +│ ├── webapp/ # doGet/doPost ハンドラ +│ │ ├── router.ts # リクエストルーティング +│ │ └── handlers/ # 各エンドポイントハンドラ +│ ├── templates/ # HTMLテンプレート +│ ├── functions/ # 共通機能 +│ ├── triggers/ # トリガー定義 +│ └── utils/ # ユーティリティ +├── tests/ +│ └── unit/ +├── dist/ +├── .clasp.json +├── appsscript.json # webapp セクション含む(executeAs, access) +├── package.json +├── tsconfig.json +├── biome.json +└── vitest.config.ts +``` + +## GAS 固有設定 + +| 項目 | 推奨 | 代替 | +|------|------|------| +| 言語 | TypeScript(固定) | — | +| デプロイツール | clasp | — | +| バンドラ | esbuild | rollup, webpack | +| 型定義 | @types/google-apps-script | — | +| テスト | Vitest | Jest | +| Linter/Formatter | Biome | ESLint + Prettier | +| パッケージマネージャ | pnpm | npm | + +## チーム規模による調整 + +| 項目 | 個人・プロトタイプ | 小規模(2-5人) | 中〜大規模(6人+) | +|------|------------------|----------------|-------------------| +| 型安全性 | 緩め可 | 標準 | 厳格(strict mode) | +| Linter設定 | 最小 | 標準 | 厳格・カスタムルール | +| テスト | 主要パスのみ | 単体+結合 | 単体+結合+E2E | +| CI/CD | なし〜簡易 | GitHub Actions | 本格CI/CD | +| ドキュメント | 最小 | README + API docs | 包括的ドキュメント | +| コードレビュー | なし | 任意 | 必須 | + +## Docker 開発環境 + +### 言語別ランタイムイメージ表 + +| 言語 | 開発用イメージ | デプロイ用イメージ | 備考 | +|------|-------------|----------------|------| +| TypeScript (Node) | `node:20-slim` | `node:20-slim`(マルチステージ) | Bun: `oven/bun:1` | +| Python | `python:3.12-slim` | `python:3.12-slim`(マルチステージ) | uv を COPY --from で追加 | +| Rust | `rust:1.82` | `debian:bookworm-slim` | 開発用は cargo-watch 必要 | +| Go | `golang:1.22` | `gcr.io/distroless/static-debian12` | 開発用は air 必要 | +| Java | `eclipse-temurin:21` | `eclipse-temurin:21-jre-jammy` | 開発時は JDK、本番は JRE | +| Kotlin | `eclipse-temurin:21` | `eclipse-temurin:21-jre-jammy` | Java と共通 | +| Dart | `dart:stable` | `scratch` / `gcr.io/distroless/cc` | AOT コンパイルで単一バイナリ | + +### Hot-Reload ツール推奨表 + +| 言語 | ツール | インストール | コマンド | +|------|-------|------------|---------| +| TypeScript | tsx --watch | devDependencies に含む | `pnpm dev` | +| Python | uvicorn --reload | uvicorn に内蔵 | `uv run uvicorn --reload` | +| Rust | cargo-watch | `cargo install cargo-watch` | `cargo watch -x run` | +| Go | air | `go install github.com/air-verse/air@latest` | `air` | +| Java | Spring DevTools | dependencies に含む | `./gradlew bootRun` | +| Kotlin | Gradle continuous | Gradle に内蔵 | `./gradlew run --continuous` | +| Dart | VM service | Dart に内蔵 | `dart run --enable-vm-service` | + +### Volume Mount パフォーマンス注意(macOS) + +macOS の Docker Desktop では volume mount のパフォーマンスが Linux より低下する場合がある: + +- **依存ディレクトリは named volume を使用**: `node_modules`, `target`, `.gradle` 等を named volume にマウントすることで I/O を高速化 +- **VirtioFS を有効化**: Docker Desktop の設定で VirtioFS ファイル共有を選択(デフォルトで有効) +- **不要なファイルの除外**: `.dockerignore` でビルド成果物・ログを除外 + +## 推奨ロジックの優先順位 + +1. **ユーザーの明示的な選択** を最優先する +2. **チーム規模** に応じて堅牢性のレベルを調整する +3. **エコシステムの成熟度** を考慮する(枯れた技術 > 最新技術) +4. **dev-*スキルとの相性** を考慮する(テスト容易性が高いFWを優先) +5. 迷った場合は **「推奨」列の最初の選択肢** をデフォルトとする diff --git a/skills/dev-init/references/ts-scaffolding.md b/skills/dev-init/references/ts-scaffolding.md new file mode 100644 index 0000000..b642d27 --- /dev/null +++ b/skills/dev-init/references/ts-scaffolding.md @@ -0,0 +1,106 @@ +# TypeScript スキャフォールディングガイド + +## CLI ツール + +| FW | コマンド | 非対話フラグ | +|----|---------|-------------| +| Next.js | `npx create-next-app@latest ` | `--ts --app --src-dir --tailwind --eslint --import-alias "@/*" --use-pnpm` | +| Remix | `npx create-remix@latest ` | `--template remix-run/remix/templates/basic` | +| Hono | `npm create hono@latest ` | テンプレート選択が必要 → 直接生成推奨 | +| Astro | `npm create astro@latest ` | `--template minimal --install --no-git --typescript strict` | +| NestJS | `npx @nestjs/cli new ` | `--package-manager pnpm --strict` | +| oclif | `npx oclif generate ` | 対話式のみ → 直接生成推奨 | +| (汎用) | `npm init -y` | — | + +ランタイム選択: Node.js(デフォルト)/ Deno / Bun。Bun の場合は `bunx` に置換。 + +## パッケージ定義 + +### 必須依存パッケージ + +| タイプ | FW | dependencies | devDependencies | +|--------|-----|-------------|-----------------| +| Web (Next.js) | Next.js | `next react react-dom` | `typescript @types/react @types/node @biomejs/biome` | +| API | Hono | `hono` | `typescript @types/node tsx @biomejs/biome` | +| API | Fastify | `fastify` | `typescript @types/node tsx @biomejs/biome` | +| API | Express | `express` | `typescript @types/express @types/node tsx @biomejs/biome` | +| CLI | Commander | `commander` | `typescript @types/node tsx @biomejs/biome` | +| ライブラリ | — | — | `typescript @biomejs/biome` | + +### package.json 重要フィールド + +- `type`: `"module"`(ESM推奨) +- `engines`: Node.js バージョン指定(`">=20"`) +- `scripts`: `dev`, `build`, `test`, `lint`, `start` + +## 設定ファイル + +### tsconfig.json 主要項目 + +- `target`: `"ES2022"` 以上 +- `module`: `"NodeNext"` / `"ESNext"` +- `moduleResolution`: `"NodeNext"` / `"Bundler"` +- `strict`: `true` +- `outDir`: `"./dist"` +- `rootDir`: `"./src"` +- `paths`: エイリアス設定(`"@/*": ["./src/*"]`) + +### テスト設定(vitest.config.ts) + +- `include`: `["tests/**/*.test.ts"]` +- `coverage.provider`: `"v8"` +- `coverage.reporter`: `["text", "json-summary"]` + +### Linter/Formatter(biome.json) + +- `formatter.indentStyle`: `"space"` / `"tab"` +- `linter.rules.recommended`: `true` +- チーム規模大: `linter.rules.nursery` を追加有効化 + +## エントリポイント + +| タイプ | パス | 内容 | +|--------|------|------| +| Web (Next.js) | `src/app/page.tsx` | ルートページコンポーネント | +| Web (Next.js) | `src/app/layout.tsx` | ルートレイアウト | +| API (Hono) | `src/index.ts` | アプリ作成・ルート登録・サーバー起動 | +| API (Fastify) | `src/index.ts` | Fastify インスタンス・プラグイン登録 | +| CLI | `src/index.ts` | コマンド定義・parse実行 | +| ライブラリ | `src/index.ts` | パブリック API のエクスポート | + +## テスト雛形 + +- ファイル配置: `tests/unit/.test.ts` +- 最小構成: 1つのスモークテスト(インポート確認 or サーバー起動確認) +- API: `app.request()` で HTTP テスト(Hono)/ `inject()` で HTTP テスト(Fastify) + +## Docker ガイド + +- ベースイメージ: `node:20-slim`(Bun: `oven/bun:1`) +- マルチステージ: `builder`(依存+ビルド)→ `runner`(本番) +- `.dockerignore`: `node_modules`, `dist`, `.git`, `.env*` +- pnpm の場合: `corepack enable && corepack prepare pnpm@latest --activate` + +### 開発用 Docker + +- 開発用ベースイメージ: `node:20-slim`(Bun: `oven/bun:1`) +- Volume mount: `- .:/app` でソースコードをマウント、`node_modules` は named volume で分離 +- Hot-reload: `pnpm dev`(tsx --watch)で自動再起動 +- Dockerfile.dev: マルチステージ不要、依存インストール + dev server コマンド + +## CI (GitHub Actions) ガイド + +- Node.js セットアップ: `actions/setup-node@v4` + `node-version-file: '.node-version'` +- pnpm キャッシュ: `actions/setup-node` の `cache: 'pnpm'` +- ステップ: install → lint → test → build +- マトリクス: Node.js バージョン(20, 22) + +## 検証コマンド + +| 操作 | コマンド (pnpm) | コマンド (bun) | +|------|----------------|----------------| +| 依存インストール | `pnpm install` | `bun install` | +| ビルド | `pnpm run build` | `bun run build` | +| テスト | `pnpm test` | `bun test` | +| Lint | `pnpm run lint` | `bun run lint` | +| 開発サーバー | `pnpm dev` | `bun dev` | diff --git a/skills/dev-navigate/SKILL.md b/skills/dev-navigate/SKILL.md new file mode 100644 index 0000000..3377de6 --- /dev/null +++ b/skills/dev-navigate/SKILL.md @@ -0,0 +1,280 @@ +--- +name: dev-navigate +description: This skill should be used when the user asks to "dev-navigate", "どこから始めれば", "何を使えばいい", "スキルを選んで", "ナビ", "navigate", "which skill", "how to start", "開発の進め方", "何から始める". 開発者がやりたいことをヒアリングし、最適なtsumikiスキルとその実行順序をナビゲーションする。 +--- + +# Dev Navigate + +開発者がやりたいことを対話で把握し、最適なtsumikiスキルの開始ポイントを提案するナビゲーションスキル。提案後、ユーザーの承認があればそのスキルを起動する。 + +## 対象スキル一覧 + +| スキル | 概要 | +|---|---| +| `dcs:feature-rubber-duck` | アイデアを整理して実現可能なPRDを作成する | +| `dcs:incremental-dev` | 既存コードへの段階的な機能追加の計画を立案する | +| `dcs:impact-analysis` | 変更の影響範囲を分析する | +| `dev-plan` | 要件をタスク分解して実装計画を立てる | +| `dev-impl` | テストファースト実装を行う(Plan指定 or クイックモード) | +| `dev-run` | impl → verify → debug を自動で連続実行する | +| `dev-verify` | Plan 単位でテスト・ビルド・Lint を一括検証する | +| `dev-debug` | エラーをカテゴリ別に診断して修正する(webtest エラーにも対応) | +| `dev-screen-spec` | ソースコードまたは受け入れ条件から画面仕様を自動生成・差分更新する | +| `dev-webtest-plan` | dev-plan の成果物から Web テスト計画を生成する。画面仕様の差分更新にも対応 | +| `dev-webtest` | Playwright で画面の動作確認・視覚テストを行い、問題を検出・記録する | + +## ワークフロー + +### Step 1: メイン質問(Q1) + +AskUserQuestion で以下を質問する: + +**質問:** 「今やりたいことに一番近いのはどれですか?」 + +| 選択肢 | 説明 | +|---|---| +| アイデアを整理してPRDにしたい | まだ構想段階。アイデアを実現可能なPRDに落とし込みたい | +| 既存コードに変更を加えたい | 既に動いているコードに機能追加や変更をしたい | +| すぐに実装・修正に入りたい | 要件やplanは明確。実装作業を始めたい | +| テスト・画面確認をしたい | 実装済みのコードの検証や Web 画面の動作確認をしたい | +| エラーやバグを修正したい | テスト失敗、ビルドエラー、画面の不具合などを直したい | +| 画面仕様やテスト計画を最新化したい | ソースコード変更後に画面仕様やテスト計画を差分更新したい | + +### Step 2: 結果の判定 + +Q1の回答に応じて分岐する。 + +#### Q1 = 「アイデアを整理してPRDにしたい」 + +**提案スキル:** `dcs:feature-rubber-duck` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dcs:feature-rubber-duck` + +アイデアを対話で深掘りし、実現可能なPRDドキュメントに整理します。 +PRDが完成したら `/dev-plan` でタスク分解に進めます。 + +**推奨フロー:** +1. `dcs:feature-rubber-duck` — アイデアをPRDに整理 +2. `dev-plan` — PRDからタスク分解 +3. `dev-impl` — タスクごとに実装 +``` + +#### Q1 = 「既存コードに変更を加えたい」 + +追加質問 Q2 に進む(Step 3)。 + +#### Q1 = 「すぐに実装・修正に入りたい」 + +**提案スキル:** `dev-impl` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-impl` + +- Planとタスクがある場合: `/dev-impl ` +- 小さな修正の場合: `/dev-impl "修正内容"`(クイックモード) +- 複数タスクを自動実行する場合: `/dev-run ` + +Planがまだない場合は先に `/dev-plan` でタスク分解することも検討してください。 +``` + +#### Q1 = 「テスト・画面確認をしたい」 + +追加質問 Q2b に進む(Step 3b)。 + +#### Q1 = 「エラーやバグを修正したい」 + +**提案スキル:** `dev-debug` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-debug` + +- テスト失敗やビルドエラーの自動検出: `/dev-debug` +- 特定のエラーを指定: `/dev-debug "エラーメッセージ"` +- Web 画面テストで検出されたエラー: `/dev-debug webtest` + +修正後は `/dev-verify` で回帰確認、Web 画面の場合は `/dev-webtest retest` で再テストできます。 +``` + +#### Q1 = 「画面仕様やテスト計画を最新化したい」 + +**提案スキル:** `dev-screen-spec` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-screen-spec` + +ソースコードの変更を画面仕様に反映し、テスト計画も連動更新します。 + +**推奨フロー:** +1. `dev-screen-spec` — 画面仕様を差分更新(初回は自動で一括生成) +2. `dev-webtest-plan update` — 画面仕様の変更からテスト計画を差分更新 +3. `dev-webtest` — 更新されたテスト計画でテスト実行 + +※ 実装前に受け入れ条件から画面仕様を作る場合: `/dev-screen-spec from-plan ` +``` + +### Step 3: 追加質問(Q2) — 既存コード変更の場合のみ + +AskUserQuestion で以下を質問する: + +**質問:** 「既存コードの変更について、今の状況に一番近いのはどれですか?」 + +| 選択肢 | 説明 | +|---|---| +| 影響範囲を先に把握したい | 変更がどこに波及するかわからず不安。先に調査したい | +| 段階的な実装計画を立てたい | 影響範囲はだいたいわかるが、段階的に進めたい | +| タスク分解して計画を立てたい | 要件は明確。タスクに分解して着手したい | + +#### Q2 = 「影響範囲を先に把握したい」 + +**提案スキル:** `dcs:impact-analysis`(+ 連携フロー) + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dcs:impact-analysis` + +まず影響範囲を可視化し、安全に変更を進められるようにします。 +分析結果を踏まえて、次のステップを選択できます。 + +**推奨フロー:** +1. `dcs:impact-analysis` — 影響範囲を可視化 +2. `dcs:incremental-dev` — 段階的な実装計画を立案(または `dev-plan` でタスク分解) +3. `dev-impl` — タスクごとに実装 +``` + +#### Q2 = 「段階的な実装計画を立てたい」 + +**提案スキル:** `dcs:incremental-dev` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dcs:incremental-dev` + +既存コードへの変更を段階的に計画し、安全に機能追加を進めます。 + +**推奨フロー:** +1. `dcs:incremental-dev` — 段階的な実装計画を立案 +2. `dev-impl` — タスクごとに実装 +``` + +#### Q2 = 「タスク分解して計画を立てたい」 + +**提案スキル:** `dev-plan` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-plan` + +要件をインターフェースファースト設計でタスクに分解し、実装計画を作成します。 + +**推奨フロー:** +1. `dev-plan` — 要件からタスク分解 +2. `dev-impl` — タスクごとに実装 +3. `dev-verify` — 実装完了の検証 +``` + +### Step 3b: 追加質問(Q2b) — テスト・画面確認の場合のみ + +AskUserQuestion で以下を質問する: + +**質問:** 「テスト・確認について、今の状況に一番近いのはどれですか?」 + +| 選択肢 | 説明 | +|---|---| +| Plan 単位でテスト・ビルドを一括検証したい | 実装が一通り終わった。全体の整合性を確認したい | +| Web 画面の動作確認をしたい | ブラウザ上で画面が正しく動くか確認したい | +| テスト計画を作ってから体系的にテストしたい | dev-plan の成果物からテスト計画を自動生成してテストしたい | + +#### Q2b = 「Plan 単位でテスト・ビルドを一括検証したい」 + +**提案スキル:** `dev-verify` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-verify` + +Plan 内の全タスクの完了状態を確認し、テスト・ビルド・Lint・カバレッジを一括検証します。 + +**推奨フロー:** +1. `dev-verify ` — 全体検証 +2. `dev-debug` — 問題があれば修正 +``` + +#### Q2b = 「Web 画面の動作確認をしたい」 + +**提案スキル:** `dev-webtest` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-webtest` + +- テスト計画に沿ったテスト: `/dev-webtest ` +- 単一ページのクイックチェック: `/dev-webtest check ` +- ランダム操作テスト: `/dev-webtest monkey ` +- プラン一覧から選択: `/dev-webtest`(引数なし) + +問題が見つかったら `/dev-debug webtest` で修正し、`/dev-webtest retest` で再確認できます。 +``` + +#### Q2b = 「テスト計画を作ってから体系的にテストしたい」 + +**提案スキル:** `dev-webtest-plan` + +提案メッセージ: +``` +## Nav 結果 + +**推奨スキル:** `/dev-webtest-plan` + +dev-plan の成果物から Playwright 用テスト計画を自動生成し、そのシナリオに沿ってテストします。 + +**推奨フロー:** +1. `dev-webtest-plan ` — テスト計画を自動生成 +2. `dev-webtest ` — テスト計画に沿ってテスト実行 +3. `dev-debug webtest` — 問題があれば修正 +4. `dev-webtest retest` — 修正確認 +``` + +### Step 4: 起動確認 + +提案メッセージを出力した後、AskUserQuestion で起動確認する: + +**質問:** 「推奨スキルを起動しますか?」 + +| 選択肢 | 説明 | +|---|---| +| 起動する | 推奨フローの最初のスキルを起動します | +| 起動しない | 提案内容を参考に、自分のタイミングで実行します | + +- 「起動する」の場合: Skill ツールで推奨フローの最初のスキルを呼び出す +- 「起動しない」の場合: 提案内容を表示したまま終了する + +## ルール・制約 + +- 質問は最大2問(Q1 + 必要時のみQ2/Q2b)に抑える +- Q1の回答だけで特定できる場合はQ2/Q2bをスキップする +- 提案時は必ず「推奨フロー」として後続スキルの流れも示す +- 起動確認では常にフローの最初のスキルを起動対象とする +- ユーザーが Other で自由入力した場合は、内容を解釈して最適なスキルを判定する diff --git a/skills/dev-plan/SKILL.md b/skills/dev-plan/SKILL.md new file mode 100644 index 0000000..3cecf59 --- /dev/null +++ b/skills/dev-plan/SKILL.md @@ -0,0 +1,233 @@ +--- +name: dev-plan +description: This skill should be used when the user asks to "dev-plan", "実装計画を作成", "要件からタスク分解", "create implementation plan", "plan tasks", "タスクを分割", "設計してタスクにする", "詳細要件定義", "full-spec plan", "EARS要件". ユーザーの要件をインターフェースファースト設計とテスト可能なタスクに分解し、Plan単位でdocs/dev/plans/に保存する。Lightweight(素早い計画)とFull-spec(EARS要件定義付き)の2モードに対応。 +argument-hint: ' "" | ' +--- + +# Dev Plan + +ユーザーの要件を分析し、インターフェースファーストの設計とテスト可能なタスクに分解する。Plan名で名前空間を分離し、複数要件の並行開発をサポートする。出力は `docs/dev/plans//` に保存される。 + +## 前提知識 + +### dev-*スキルフロー内の位置 + +``` +dev-context → [dev-plan] → dev-impl → dev-verify +``` + +### 前提条件 + +- `docs/dev/context.md` が存在すること(dev-contextで生成済み) +- context.md がない場合、先に `/dev-context` の実行を案内する + +### 引数フォーマット + +``` +/dev-plan "<要件の説明>" +/dev-plan +``` + +- `plan-name`: 英数字とハイフンのみ(例: `auth`, `payment-integration`, `user-profile`) + - **日本語が含まれる場合は自動変換する**(Phase 0.5 参照) +- 要件の説明: 自然言語での機能要件 +- PRDファイルパス: PRD ドキュメントのファイルパス(`.md` 等)。ファイル内容を要件として読み込む + +### 実行モード + +| モード | 説明 | 出力 | +|-------|------|------| +| Lightweight | 素早い要件明確化→設計→タスク分解 | plan.md + tasks/ | +| Full-spec | EARS要件定義→ユーザーストーリー→受入基準→設計→タスク分解 | requirements.md + user-stories.md + acceptance-criteria.md + plan.md + tasks/ | + +## ワークフロー + +### Phase 0: モード選択 + +AskUserQuestion で実行モードを選択する: + +- **Lightweight(推奨: 小さな機能追加・バグ修正)**: 素早く要件を明確化し、設計→タスク分解まで進む +- **Full-spec(推奨: 新規システム・複雑な要件)**: EARS要件定義→ユーザーストーリー→受入基準を作成した上で、設計→タスク分解に進む + +選択されたモードに応じて以降の Phase の振る舞いが変わる。 + +### Phase 0.5: plan-name の正規化 + +plan-name に日本語(非ASCII文字)が含まれる場合、以下のルールで英数字ケバブケースに自動変換する: + +1. 日本語の要件名を簡潔な英語に翻訳する +2. ケバブケース(kebab-case)に変換する +3. 最大50文字程度に収める +4. 変換例: + - "ユーザー認証システム" → `user-auth-system` + - "データエクスポート機能" → `data-export` + - "パスワードリセット" → `password-reset` + - "お気に入り管理" → `favorite-management` + - "検索フィルター追加" → `search-filter` +5. 変換後のplan-nameをユーザーに提示し、確認を取ってから続行する + +plan-name が既に英数字とハイフンのみの場合はこのフェーズをスキップする。 + +### Phase 1: 要件明確化 + +1. **要件入力の判定**: 第2引数がファイルパスかテキストかを判定する + - ファイルパスの場合(パスに `/` を含む、または `.md` 等の拡張子で終わる)→ Read ツールでファイルを読み込み、内容を要件として使用する + - PRDファイルが **200行を超える** 場合: + 1. 最初の200行を Read で読み込む + 2. 残りは Explore サブエージェント(`model: haiku`)で要約を取得する + 3. メインコンテキストには **先頭200行 + 要約(50行以内)** のみ保持する + - ファイルが存在しない場合 → エラーメッセージを表示して終了する + - テキストの場合 → 従来通りテキストを要件として使用する +2. `docs/dev/context.md` を読み込み、プロジェクトコンテキストを把握する +3. ユーザーの要件(テキストまたはPRDファイル内容)を分析し、不明確な点を特定する +4. AskUserQuestion で曖昧さを段階的に解消する(最大2-3ラウンド) + +確認すべき観点: +- 機能のスコープと境界(何をやるか / 何をやらないか) +- ユーザーから見た振る舞い(入力と期待する出力) +- 既存機能への影響範囲 +- 非機能要件(パフォーマンス、セキュリティ等)の有無 + +**Full-spec モードの場合の追加確認**(3-5ラウンド): +- ペルソナ(誰がどのような目的で使うか) +- パフォーマンス目標値(レスポンスタイム、スループット等の具体的数値) +- セキュリティ要件(認証・認可・データ保護の方針) +- エッジケース(異常系・境界値・競合状態) +- 外部システム連携(API・DB・サードパーティサービス) +- 優先順位(MoSCoW: Must/Should/Could/Won't) + +### Phase 1.5: 詳細要件定義(Full-spec のみ) + +Full-spec モードの場合のみ実行する。Lightweight の場合はスキップして Phase 2 に進む。 + +**コンテキスト節約のため、3ドキュメント生成はサブエージェントに委譲する(dev-run パターン)。** + +1. `references/fullspec-prompt-template.md` を Read してプロンプトテンプレートを取得する +2. Phase 1 のヒアリング結果を **200行以内** に要約する +3. `docs/dev/context.md` から Tech Stack + Project Structure セクションを **100行以内** に抽出する +4. テンプレートのプレースホルダーを置換する: + - `{{HEARING_SUMMARY}}` ← ヒアリング結果の要約 + - `{{PLAN_NAME}}` ← Plan名 + - `{{CONTEXT_EXCERPT}}` ← context.md 抜粋 +5. general-purpose サブエージェントを起動し、置換済みプロンプトを渡す。サブエージェントが以下の3ドキュメントを一括生成する: + - `docs/dev/plans//requirements.md` — EARS形式の機能要件・非機能要件・制約・用語集 + - `docs/dev/plans//user-stories.md` — ペルソナ・エピック・ストーリー(As a/I want/So that)・MoSCoW優先度・ジャーニー + - `docs/dev/plans//acceptance-criteria.md` — Given/When/Then形式の受入基準・テストチェックリスト・横断的基準 +6. サブエージェントの結果マーカーを確認する: + - `FULLSPEC_SUCCESS` → 赤信号リストのみメインコンテキストに取り込む + - `FULLSPEC_FAILED` → エラー内容を確認し、リトライまたはユーザーに報告する +7. 赤信号(🔴)がある場合は AskUserQuestion でユーザーに確認し、解消してから Phase 2 に進む + +### Phase 2: 設計(Architect的役割) + +**Full-spec モードの場合**: Plan サブエージェントに Phase 1.5 で生成した3ドキュメントの **ファイルパス** を渡し、サブエージェントが直接 Read で読み込んで設計に反映する。これにより設計がEARS要件に基づいたものになり、かつメインコンテキストで3ドキュメント(~1500行)を保持し続ける必要がなくなる。 + - `docs/dev/plans//requirements.md` + - `docs/dev/plans//user-stories.md` + - `docs/dev/plans//acceptance-criteria.md` + +Plan サブエージェント(`subagent_type: Plan`)で関連コードベースを分析する: + +1. **既存コードの調査**: 関連する既存実装、インターフェース、型定義を探索 +2. **インターフェースファースト設計**: + - 実装詳細より先に型/インターフェースを定義する + - これが後続の dev-impl で「幻覚」を防ぐ契約書として機能する + - dev-impl は context.md + インターフェース定義だけで実装可能にする +3. **データフロー整理**: 入力→処理→出力の流れを整理する +4. **依存関係の特定**: 既存コードとの接続点、新規モジュール間の依存を明確にする + +### Phase 3: タスク分解 + +テスト可能な単位にタスクを分割する: + +1. **タスクの粒度**: 1タスク = 1つのテスト可能な振る舞い単位 +2. **依存関係グラフ**: タスク間の実装順序を決定する +3. **複雑度見積もり**: 各タスクを low / medium / high に分類 +4. **テスト方針**: 各タスクに「何をテストするか」を明記する +5. **ファイル影響範囲**: 各タスクが影響するファイルパスを列挙する + +### Phase 4: ファイル出力 + +以下のディレクトリとファイルを生成する: + +```bash +PROJECT_ROOT="$(git rev-parse --show-toplevel)" +mkdir -p "$PROJECT_ROOT/docs/dev/plans//tasks" +mkdir -p "$PROJECT_ROOT/docs/dev/plans//reports" +``` + +#### 出力ディレクトリ構成 + +**Lightweight モード**: +``` +docs/dev/plans// +├── plan.md +├── tasks/ +│ └── NNN-task-name.md +└── reports/ +``` + +**Full-spec モード**: +``` +docs/dev/plans// +├── plan.md # 要件概要・設計メモ・タスク依存グラフ +├── requirements.md # EARS要件定義(Phase 1.5で生成済み) +├── user-stories.md # ユーザーストーリー(Phase 1.5で生成済み) +├── acceptance-criteria.md # 受入基準(Phase 1.5で生成済み) +├── tasks/ +│ └── NNN-task-name.md +└── reports/ +``` + +#### plan.md の生成 + +`docs/dev/plans//plan.md` に要件概要と設計メモを記録: + +```markdown +# Plan: +## Requirements Summary +[要件の要約] + + +## Design Overview +[インターフェース設計の概要] +## Task Dependency Graph +[タスク間の依存関係] +## Cross-Plan Dependencies +[他のPlanとの共有インターフェースがある場合に記載] +``` + +Full-spec モードの場合、Requirements Summary に要件ドキュメントへの相対リンクを記載する。 + +#### タスクファイルの生成 + +各タスクを `docs/dev/plans//tasks/NNN-task-name.md` に出力する。`references/task-template.md` のテンプレートに従う。 + +## 信号機システム + +設計の各要素に確信度を付与する: + +- 🔵 **前工程指示**: 既存コードのパターンに完全に沿った設計、明示的な仕様に基づく +- 🟡 **妥当な推測**: ベストプラクティスに基づくが、プロジェクトでの明示的な前例がない +- 🔴 **AI推論補完**: アーキテクチャ判断が必要、組織固有のポリシーに依存する箇所 + +インターフェース定義の各メソッド/プロパティに確信度を付与し、タスクファイルに記録する。🔴 がある場合はユーザーに AskUserQuestion で確認する。 + +## ルール・制約 + +- context.md が存在しない場合、先に `/dev-context` の実行を案内して終了する +- 既存の `docs/dev/plans//` が存在する場合、上書きするか確認する +- タスクファイルは 001 から連番で命名する +- 1タスクの見積もり粒度: dev-impl 1回で完了する単位 +- インターフェース定義は可能な限り具体的に(`any` や `unknown` を避ける) +- テスト方針は具体的な振る舞いで記述する(「正しく動作する」のような曖昧表現を避ける) +- 各タスクファイルは500行以内 +- サブエージェントによる探索結果は要約のみメインコンテキストに返す +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) + +## 追加リソース + +### リファレンスファイル + +- **`references/task-template.md`** — タスクファイルのテンプレートとフロントマター仕様 +- **`references/fullspec-templates.md`** — Full-spec モード用の要件ドキュメントテンプレート(requirements.md, user-stories.md, acceptance-criteria.md)と EARS 記述ガイド +- **`references/fullspec-prompt-template.md`** — Full-spec モード Phase 1.5 のサブエージェント用プロンプトテンプレート(`{{HEARING_SUMMARY}}`, `{{PLAN_NAME}}`, `{{CONTEXT_EXCERPT}}` を置換して使用) diff --git a/skills/dev-plan/references/fullspec-prompt-template.md b/skills/dev-plan/references/fullspec-prompt-template.md new file mode 100644 index 0000000..979de9a --- /dev/null +++ b/skills/dev-plan/references/fullspec-prompt-template.md @@ -0,0 +1,113 @@ +# Full-spec サブエージェント プロンプトテンプレート + +dev-plan がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは EARS 要件定義のエキスパートです。以下のヒアリング結果に基づき、3つの要件ドキュメントを生成してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- すべてのファイルは **500行以内** に収めること + +## Plan 情報 + +- **Plan名**: {{PLAN_NAME}} +- **出力先**: `docs/dev/plans/{{PLAN_NAME}}/` + +## ヒアリング結果 + +{{HEARING_SUMMARY}} + +## プロジェクトコンテキスト(抜粋) + +{{CONTEXT_EXCERPT}} + +## 生成ワークフロー + +### Step 1: テンプレート取得 + +このスキルの `references/fullspec-templates.md` を Read して、3ドキュメントのテンプレートと EARS 記述ガイドを取得する。 + +ファイルパス: `skills/dev-plan/references/fullspec-templates.md` + +Glob で実際のパスを探索し、Read で読み込むこと。 + +### Step 2: 出力ディレクトリ準備 + +```bash +PROJECT_ROOT="$(git rev-parse --show-toplevel)" +mkdir -p "$PROJECT_ROOT/docs/dev/plans/{{PLAN_NAME}}" +``` + +### Step 3: requirements.md の生成 + +fullspec-templates.md のテンプレート1に従い、EARS 形式で機能要件・非機能要件・制約・用語集を記述する。 + +- `{{PLAN_NAME}}` をプラン名に置換する +- ヒアリング結果から要件を抽出し、EARS 5タイプに分類する +- 各要件に信号機(🔵🟡🔴)を付与する +- ID は FR-001〜, NFR-001〜, CON-001〜 で採番する + +出力先: `docs/dev/plans/{{PLAN_NAME}}/requirements.md` + +### Step 4: user-stories.md の生成 + +fullspec-templates.md のテンプレート2に従い、ペルソナ・エピック・ストーリーを記述する。 + +- requirements.md で定義した FR-XXX を参照する +- 各ストーリーに US-XXX の ID を付与する +- MoSCoW 優先度を設定する +- 各ストーリーに信号機を付与する + +出力先: `docs/dev/plans/{{PLAN_NAME}}/user-stories.md` + +### Step 5: acceptance-criteria.md の生成 + +fullspec-templates.md のテンプレート3に従い、Given/When/Then 形式の受入基準を記述する。 + +- requirements.md の FR-XXX, user-stories.md の US-XXX を参照する +- 各基準に AC-XXX の ID を付与する +- テストチェックリスト(正常系・異常系・境界値)を含める +- 各基準に信号機を付与する + +出力先: `docs/dev/plans/{{PLAN_NAME}}/acceptance-criteria.md` + +### Step 6: 相互参照の整合性検証 + +3ドキュメント間の ID 参照が整合していることを検証する: + +- requirements.md の各 FR-XXX に対応する US-XXX, AC-XXX が存在するか +- user-stories.md の各 US-XXX が参照する FR-XXX が存在するか +- acceptance-criteria.md の各 AC-XXX が参照する FR-XXX, US-XXX が存在するか + +不整合があれば修正する。 + +### Step 7: 完了報告 + +#### 赤信号リストの出力 + +🔴(赤信号)がある要件・ストーリー・基準を以下のフォーマットでリスト出力する: + +``` +## 赤信号リスト(要確認) + +- [ID]: [要件/ストーリー/基準の概要] — [確認が必要な理由] +- [ID]: [要件/ストーリー/基準の概要] — [確認が必要な理由] +``` + +赤信号がない場合は「赤信号なし」と出力する。 + +#### 結果マーカー + +- 成功時: 最後の行に `FULLSPEC_SUCCESS` を出力する +- 失敗時: 以下を出力する: + - 発生したエラーの詳細 + - 最後の行に `FULLSPEC_FAILED` を出力する diff --git a/skills/dev-plan/references/fullspec-templates.md b/skills/dev-plan/references/fullspec-templates.md new file mode 100644 index 0000000..1f1e52c --- /dev/null +++ b/skills/dev-plan/references/fullspec-templates.md @@ -0,0 +1,313 @@ +# Full-spec テンプレート & 記述ガイド + +Full-spec モードで生成する3つの要件ドキュメントのテンプレートと記述ガイド。 +Phase 1.5 でこのファイルを Read し、テンプレートに従ってドキュメントを生成する。 + +出力先: `docs/dev/plans//` 直下 + +--- + +## ID体系と相互参照 + +ドキュメント間は以下のID体系で相互参照する: + +| ドキュメント | ID接頭辞 | 例 | +|------------|---------|-----| +| requirements.md | FR-XXX, NFR-XXX | FR-001, NFR-101 | +| user-stories.md | US-XXX | US-001 | +| acceptance-criteria.md | AC-XXX | AC-001 | + +**参照ルール**: +- requirements.md の各要件 → 関連する US-XXX, AC-XXX を記載 +- user-stories.md の各ストーリー → 関連する FR-XXX を記載 +- acceptance-criteria.md の各基準 → 対応する FR-XXX, US-XXX を記載 + +--- + +## EARS 5タイプの説明 + +EARS(Easy Approach to Requirements Syntax)は要件を5つのパターンで記述する: + +| タイプ | パターン | 例 | +|-------|---------|-----| +| **Ubiquitous(普遍)** | システムは〈動作〉しなければならない(SHALL) | システムはすべてのAPIレスポンスにリクエストIDを含めなければならない | +| **Event-driven(イベント駆動)** | 〈トリガー〉の場合、システムは〈動作〉しなければならない(WHEN-THEN) | ユーザーがパスワードを3回連続で間違えた場合、システムはアカウントを一時ロックしなければならない | +| **State-driven(状態駆動)** | 〈状態〉にある間、システムは〈動作〉しなければならない(WHERE) | メンテナンスモード中、システムは読み取り専用アクセスのみ許可しなければならない | +| **Optional(任意)** | システムは〈機能〉してもよい(MAY) | システムはダークモードを提供してもよい | +| **Unwanted(禁止)** | システムは〈動作〉してはならない(MUST NOT) | システムは平文でパスワードを保存してはならない | + +--- + +## 信号機の基準 + +各要件・ストーリー・受入基準に以下の確信度を付与する: + +- 🔵 **青信号(前工程指示)**: PRD・設計文書・ユーザーヒアリング・既存コードに基づく確実な内容 +- 🟡 **黄信号(妥当な推測)**: ベストプラクティスや類似パターンからの妥当な推測 +- 🔴 **赤信号(AI推論補完)**: 明示的な根拠がなくAIが補完した内容。Phase 2 に進む前に AskUserQuestion で確認必須 + +--- + +## 制約 + +- 各ファイルは **500行以内** に収める +- プロジェクトルートからの **相対パス** を使用する +- 信号機は **すべての要件・ストーリー・基準** に必ず付与する + +--- + +## テンプレート1: requirements.md + +```markdown +# 要件定義書 + +## 概要 + +[要件の概要と背景] + +## 関連文書 + +- **ユーザーストーリー**: [user-stories.md](user-stories.md) +- **受入基準**: [acceptance-criteria.md](acceptance-criteria.md) +- **設計・タスク**: [plan.md](plan.md) + +## 用語集 + +| 用語 | 定義 | +|-----|------| +| [用語1] | [定義] | + +## 機能要件(EARS記法) + +**【信頼性レベル凡例】**: +- 🔵 PRD・設計文書・ヒアリングに基づく確実な要件 +- 🟡 妥当な推測による要件 +- 🔴 AI推論補完による要件(要確認) + +### 普遍要件(SHALL) + +- **FR-001**: システムは〈動作〉しなければならない 🔵 *[出典]* + - 関連: US-XXX, AC-XXX + +### イベント駆動要件(WHEN-THEN) + +- **FR-101**: 〈トリガー〉の場合、システムは〈動作〉しなければならない 🔵 *[出典]* + - 関連: US-XXX, AC-XXX + +### 状態駆動要件(WHERE) + +- **FR-201**: 〈状態〉にある間、システムは〈動作〉しなければならない 🟡 *[出典]* + - 関連: US-XXX, AC-XXX + +### 任意要件(MAY) + +- **FR-301**: システムは〈機能〉してもよい 🟡 *[出典]* + - 関連: US-XXX, AC-XXX + +### 禁止要件(MUST NOT) + +- **FR-401**: システムは〈動作〉してはならない 🔵 *[出典]* + - 関連: AC-XXX + +## 非機能要件 + +### パフォーマンス + +- **NFR-001**: [パフォーマンス要件と目標値] 🟡 *[出典]* + +### セキュリティ + +- **NFR-101**: [セキュリティ要件] 🔵 *[出典]* + +### ユーザビリティ + +- **NFR-201**: [ユーザビリティ要件] 🟡 *[出典]* + +## 制約 + +- **CON-001**: [技術的・ビジネス的制約] 🔵 *[出典]* + +## 信頼性レベルサマリー + +- 🔵 青信号: X件 +- 🟡 黄信号: X件 +- 🔴 赤信号: X件(要確認) +``` + +--- + +## テンプレート2: user-stories.md + +```markdown +# ユーザーストーリー + +## 関連文書 + +- **要件定義**: [requirements.md](requirements.md) +- **受入基準**: [acceptance-criteria.md](acceptance-criteria.md) + +**【信頼性レベル凡例】**: +- 🔵 確実なストーリー +- 🟡 妥当な推測によるストーリー +- 🔴 AI推論補完(要確認) + +--- + +## ペルソナ + +### ペルソナ1: [名前/役割] + +- **役割**: [ユーザー種別] +- **目的**: [主な利用目的] +- **技術レベル**: [初級/中級/上級] + +--- + +## エピック1: [エピック名] + +### US-001: [ストーリー名] 🔵 + +**私は** [ユーザー種別] **として** +**[具体的な行動] をしたい** +**そうすることで** [得られる価値] + +- **関連要件**: FR-XXX, FR-XXX +- **優先度**: Must Have / Should Have / Could Have / Won't Have +- **受入基準**: AC-XXX + +### US-002: [ストーリー名] 🟡 + +**私は** [ユーザー種別] **として** +**[具体的な行動] をしたい** +**そうすることで** [得られる価値] + +- **関連要件**: FR-XXX +- **優先度**: Should Have +- **受入基準**: AC-XXX + +--- + +## エピック2: [エピック名] + +### US-101: [ストーリー名] 🔵 + +(同様の形式) + +--- + +## ユーザージャーニー + +### ジャーニー1: [シナリオ名] + +``` +[ステップ1] → [ステップ2] → [ステップ3] → [完了] + US-001 US-002 US-003 +``` + +--- + +## ストーリーマップ + +| 優先度 | エピック1 | エピック2 | +|-------|----------|----------| +| Must Have | US-001 🔵 | US-101 🔵 | +| Should Have | US-002 🟡 | US-102 🟡 | +| Could Have | US-003 🟡 | - | + +## 信頼性レベルサマリー + +- 🔵 青信号: X件 (X%) +- 🟡 黄信号: X件 (X%) +- 🔴 赤信号: X件 (X%) +``` + +--- + +## テンプレート3: acceptance-criteria.md + +```markdown +# 受入基準 + +## 関連文書 + +- **要件定義**: [requirements.md](requirements.md) +- **ユーザーストーリー**: [user-stories.md](user-stories.md) + +**【信頼性レベル凡例】**: +- 🔵 確実な基準 +- 🟡 妥当な推測による基準 +- 🔴 AI推論補完(要確認) + +--- + +## AC-001: [FR-XXX] [要件名] 🔵 + +**関連**: FR-XXX, US-XXX + +### Given(前提条件) +- [テスト実行前の状態] + +### When(実行条件) +- [ユーザーが実行するアクション] + +### Then(期待結果) +- [期待される出力・状態変化] + +### テストチェックリスト + +- [ ] **正常系**: [具体的なテストケース] 🔵 +- [ ] **異常系**: [エラーケース] 🟡 +- [ ] **境界値**: [境界値ケース] 🟡 + +--- + +## AC-002: [FR-XXX] [要件名] 🟡 + +**関連**: FR-XXX, US-XXX + +### Given(前提条件) +- [テスト実行前の状態] + +### When(実行条件) +- [ユーザーが実行するアクション] + +### Then(期待結果) +- [期待される出力・状態変化] + +### テストチェックリスト + +- [ ] **正常系**: [具体的なテストケース] 🟡 +- [ ] **異常系**: [エラーケース] 🟡 + +--- + +## 横断的受入基準 + +### パフォーマンス(NFR-XXX) + +- [ ] [パフォーマンス基準と測定方法] 🟡 + +### セキュリティ(NFR-XXX) + +- [ ] [セキュリティ基準と検証方法] 🔵 + +### アクセシビリティ(NFR-XXX) + +- [ ] [アクセシビリティ基準] 🟡 + +--- + +## テストサマリー + +| カテゴリ | 正常系 | 異常系 | 境界値 | 合計 | +|---------|--------|--------|--------|------| +| 機能要件 | X | X | X | X | +| 非機能要件 | X | X | X | X | +| **合計** | X | X | X | X | + +## 信頼性レベル分布 + +- 🔵 青信号: X件 (X%) +- 🟡 黄信号: X件 (X%) +- 🔴 赤信号: X件 (X%) +``` diff --git a/skills/dev-plan/references/task-template.md b/skills/dev-plan/references/task-template.md new file mode 100644 index 0000000..68d8c10 --- /dev/null +++ b/skills/dev-plan/references/task-template.md @@ -0,0 +1,150 @@ +# タスクファイル テンプレート + +## テンプレート + +各タスクファイルは以下のフォーマットで `docs/dev/plans//tasks/NNN-task-name.md` に保存する。 + +```markdown +--- +id: "NNN" +title: "タスク名" +status: pending +priority: 1 +dependencies: [] +estimated_complexity: medium +--- + +# Task: タスク名 + +## Goal + +[このタスクが達成すべきこと(1-2文で簡潔に)] + +## Interfaces + +[このタスクで実装/使用するインターフェース・型定義をコードブロックで記述] + +> 信号機: 各インターフェース要素に 🔵🟡🔴 を付与 + +## Test Strategy + +- [ ] テストケース1: [具体的な振る舞いの記述] +- [ ] テストケース2: [具体的な振る舞いの記述] +- [ ] エッジケース: [境界値・異常系の記述] + +## Implementation Notes + +- 参照すべき既存コード: [ファイルパス] +- 実装のヒント: [アプローチの要点] +- 注意事項: [既存コードとの整合性、副作用等] + +## Files + +- 新規: [作成するファイルパス] +- 変更: [変更するファイルパス] +- テスト: [テストファイルパス] +``` + +## フロントマター仕様 + +### id (必須) +- 3桁の連番文字列: "001", "002", ... +- Plan内で一意 + +### title (必須) +- タスクの簡潔な名称 +- 動詞で始める(「認証サービスを実装」「バリデーションを追加」等) + +### status (必須) +- `pending`: 未着手 +- `in_progress`: 実装中 +- `done`: 完了(テスト通過済み) + +### priority (必須) +- `1`: 最高(基盤・インターフェース定義等) +- `2`: 高(コア機能) +- `3`: 中(標準機能) +- `4`: 低(補助機能) +- `5`: 最低(オプション) + +### dependencies (必須) +- このタスクが依存する他のタスクIDの配列 +- 例: `["001", "002"]` +- 空配列 `[]` は依存なし + +### estimated_complexity (必須) +- `low`: テスト+実装をバッチ生成可能。シンプルなCRUD、ユーティリティ関数等 +- `medium`: 標準的なRed-Green-Refactorサイクル。通常のビジネスロジック等 +- `high`: 段階的にテスト追加・実装。複雑なアルゴリズム、複数の外部依存等 + +## 各セクションの記述ガイド + +### Goal +- 1-2文で完結する +- 「何を」「なぜ」が分かるように +- テスト可能な形で記述する + +### Interfaces +- 言語に応じたインターフェース/型定義を記述 +- TypeScript: `interface`, `type` +- Rust: `trait`, `struct` +- Go: `interface`, `struct` +- Python: `Protocol`, `dataclass`, `TypedDict` +- 各要素に信号機マークを付与する + +信号機の付与例: + +```typescript +interface AuthService { + login(email: string, password: string): Promise; // 🔵 既存パターン準拠 + logout(token: string): Promise; // 🔵 既存パターン準拠 + refreshToken(token: string): Promise; // 🟡 ベストプラクティスから推定 + revokeAllSessions(userId: string): Promise; // 🔴 セキュリティポリシー要確認 +} +``` + +### Test Strategy +- チェックリスト形式で列挙 +- 「正しく動作する」のような曖昧表現を避ける +- 具体的な入力→期待出力のペアで記述する +- 正常系、異常系、エッジケースを含める + +良い例: +``` +- [ ] 有効なメール+パスワードでログインするとAuthResultが返る +- [ ] 無効なパスワードでログインするとAuthErrorが投げられる +- [ ] 空文字のメールでログインするとValidationErrorが投げられる +- [ ] トークン期限切れ時にrefreshTokenで新しいトークンが取得できる +``` + +悪い例: +``` +- [ ] ログイン機能が正しく動作する +- [ ] エラーハンドリングが適切 +``` + +### Implementation Notes +- 既存コードへのファイルパスを具体的に指定 +- 既存パターンの踏襲ポイントを明記 +- 使用するライブラリ・ユーティリティがあれば記載 + +### Files +- 相対パスで記載 +- 「新規」「変更」「テスト」に分類 +- テストファイルは対象実装ファイルと1:1対応を推奨 + +## タスク分解の指針 + +### 分割の粒度 +- 1タスク = dev-impl 1回で完了する単位 +- テストファイル1つ + 実装ファイル1-2つ程度 +- 目安: テストケース3-8個 / タスク + +### 依存関係の設計 +- インターフェース定義タスクを最初に配置する(priority: 1) +- 型定義 → 実装 → 統合 の順で依存関係を設計 +- 循環依存を避ける + +### 命名規則 +- ファイル名: `NNN-kebab-case-description.md` +- 例: `001-auth-interfaces.md`, `002-auth-service.md`, `003-auth-middleware.md` diff --git a/skills/dev-run/SKILL.md b/skills/dev-run/SKILL.md new file mode 100644 index 0000000..b5e7de9 --- /dev/null +++ b/skills/dev-run/SKILL.md @@ -0,0 +1,273 @@ +--- +name: dev-run +description: This skill should be used when the user asks to "dev-run", "自動実装", "タスクを一括実装", "auto implement", "run all tasks", "タスクを自動実行", "バッチ実装", "dev-run auth 001 005". Plan内の指定範囲のタスクをdev-impl/dev-verify/dev-debugのワークフローで自動実行するオーケストレーションスキル。 +argument-hint: ' ' +--- + +# Dev Run + +Plan 内の指定範囲タスクに対し、impl → verify → debug のループを自動実行するオーケストレーションスキル。各タスクを Task サブエージェントに委託し、TaskCreate/TaskUpdate で依存関係付きの進捗管理を行う。 + +## 前提知識 + +### dev-* スキルフロー内の位置 + +``` +dev-context → dev-plan → [dev-run] → (完了) + ├─ impl サブエージェント (×タスク数) + ├─ debug サブエージェント (エラー時) + └─ verify サブエージェント (全タスク完了後) +``` + +### 引数フォーマット + +``` +/dev-run +``` + +- `plan-name`: 既存の Plan 名(`docs/dev/plans//` が存在すること) +- `from-task-id`: 開始タスク ID(例: "001") +- `to-task-id`: 終了タスク ID(例: "005") + +### サブエージェント制約(重要) + +サブエージェントは Task ツールを使用できない(ネスト不可のアーキテクチャ制約)。そのため: +- コード探索は Glob/Grep/Read を直接使用する +- TodoWrite は使用しない(TaskCreate/TaskUpdate で進捗管理する) +- プロンプトに context.md を埋め込み、サブエージェントのファイル読み込みを最小化する + +## ワークフロー + +### Step 1: 事前検証とコンテキスト読み込み + +1. `docs/dev/context.md` の存在を確認する。存在しない場合は `/dev-context` の実行を案内して終了する +2. `docs/dev/plans//` の存在を確認する。存在しない場合は `/dev-plan` の実行を案内して終了する +3. `docs/dev/context.md` を Read で読み込み、以下を抽出する: + - テスト実行コマンド(Test Framework セクション) + - ビルドコマンド(Build & Run セクション、あれば) + - Lint コマンド(Build & Run セクション、あれば) + - カバレッジ閾値(Test Framework セクションの Coverage Threshold) +4. `docs/dev/plans//plan.md` を Read で読み込む +5. 指定範囲(from-task-id 〜 to-task-id)の全タスクファイルを Glob + Read で読み込む +6. 各タスクの `status`, `dependencies`, `estimated_complexity` を確認する + +#### 範囲外依存チェック + +タスクファイルの `dependencies` に、指定範囲外のタスク ID が含まれる場合: +- そのタスクファイルを Read し、`status` を確認する +- `status: done` → 問題なし +- それ以外 → AskUserQuestion でユーザーに警告し、続行/中断を確認する + +### Step 2: TaskCreate で依存関係グラフ構築 + +#### 2a. タスクの登録 + +指定範囲内で `status` が `done` でないタスクごとに TaskCreate を実行する: + +``` +TaskCreate: + subject: "impl-NNN: <タスクタイトル>" + description: "Plan のタスク NNN を TDD 実装する" + activeForm: "Implementing task NNN: <タスクタイトル>" +``` + +#### 2b. 依存関係の設定 + +タスクファイルの `dependencies` を TaskUpdate の `addBlockedBy` にマッピングする。 + +ID マッピングテーブルを構築: `{"001": "", "002": "", ...}` + +- 範囲内の依存: 対応する TaskCreate ID を blockedBy に設定 +- 範囲外の依存(done 済み): blockedBy から除外 +- `status: done` のタスク: TaskCreate しない、依存元からも除外 + +#### 2c. verify タスクの登録 + +``` +TaskCreate: + subject: "verify: " + description: "Plan の全体検証を実行する" + activeForm: "Verifying plan " + addBlockedBy: [全 impl タスクの ID] +``` + +### Step 3: 実装ループ + +TaskList で `status: pending` かつ `blockedBy` が空のタスクを取得し、順に実行する。 + +#### 3a. impl タスクの実行 + +1. TaskUpdate で `in_progress` にする +2. `references/impl-prompt-template.md` を Read で読み込む +3. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_CONTENT}}` ← context.md の全文 + - `{{TASK_FILE_CONTENT}}` ← タスクファイルの全文 + - `{{PLAN_MD_EXCERPT}}` ← plan.md の設計概要 + - `{{TEST_COMMAND}}` ← テスト実行コマンド + - `{{TASK_FILE_PATH}}` ← タスクファイルのパス + - `{{ESTIMATED_COMPLEXITY}}` ← タスクの複雑度 + - `{{COVERAGE_THRESHOLD}}` ← カバレッジ閾値 +4. Task サブエージェント(general-purpose)を起動する +5. サブエージェントの出力を確認する: + - `IMPL_SUCCESS` を含む → 成功処理(3c へ) + - `IMPL_FAILED` を含む → debug 処理(3b へ) + +#### 3b. debug 処理(impl 失敗時) + +1. impl サブエージェントの出力からエラー情報を抽出する +2. `references/debug-prompt-template.md` を Read で読み込む +3. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_CONTENT}}` ← context.md の全文 + - `{{ERROR_DETAILS}}` ← エラー情報(impl の出力から抽出) + - `{{TASK_FILE_CONTENT}}` ← タスクファイルの全文 + - `{{TEST_COMMAND}}` ← テスト実行コマンド +4. Task サブエージェント(general-purpose)を起動する +5. サブエージェントの出力を確認する: + - `DEBUG_SUCCESS` → 成功処理(3c へ) + - `DEBUG_FAILED` → エスカレーション: + AskUserQuestion で以下を提示: + - このタスクをスキップして次へ進む + - 自動実行を中断する + - 手動修正後に再開する + +#### 3c. 成功処理 + +1. タスクファイルの frontmatter `status` を `done` に更新する(Edit ツール使用) + - **注意**: dev-run の allowed-tools に Edit は含まれないため、ここはサブエージェント内で実施済みのはず。サブエージェントが更新していない場合は Read で確認する +2. TaskUpdate で `completed` にする +3. TaskList で次のブロック解除タスクを確認する +4. 次のタスクがあれば 3a に戻る + +### Step 4: 全体検証(verify タスク実行) + +全 impl タスクが completed になると verify タスクのブロックが解除される。 + +1. TaskUpdate で verify を `in_progress` にする +2. `references/verify-prompt-template.md` を Read で読み込む +3. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_CONTENT}}` ← context.md の全文 + - `{{PLAN_NAME}}` ← Plan 名 + - `{{TEST_COMMAND}}`, `{{BUILD_COMMAND}}`, `{{LINT_COMMAND}}` + - `{{COVERAGE_THRESHOLD}}` ← カバレッジ閾値 + - `{{TODAY_DATE}}` ← 実行日(YYYY-MM-DD) +4. Task サブエージェント(general-purpose)を起動する +5. サブエージェントが検証レポートを `docs/dev/plans//reports/verify-<日付>.md` に出力する + +### Step 5: 検証結果パースと修正ループ + +verify サブエージェント完了後: + +1. 出力マーカーを確認する: + - `VERIFY_ALL_PASSED` → 全パス、Step 6 へ + - `VERIFY_ISSUES_FOUND` → 修正ループへ + +#### 修正ループ(最大2サイクル) + +サイクルごとに: + +1. レポートファイルを Read で読み込む +2. Issues Found セクションから問題を抽出する +3. 問題ごとに fix タスクを TaskCreate する: + ``` + subject: "fix-NNN: <問題概要>" + activeForm: "Fixing: <問題概要>" + addBlockedBy: [verify タスクの ID] + ``` +4. re-verify タスクを TaskCreate する: + ``` + subject: "re-verify-N: " + activeForm: "Re-verifying plan " + addBlockedBy: [全 fix タスクの ID] + ``` +5. fix タスクを実行する(debug サブエージェント使用、3b と同じフロー) +6. re-verify タスクを実行する(verify サブエージェント使用、Step 4 と同じフロー) +7. 結果を確認: + - 全パス → Step 6 へ + - まだ問題あり: + - サイクル 1 → サイクル 2 へ + - サイクル 2 → 残存問題を報告して Step 6 へ + +### Step 6: 最終レポート + +ユーザーに以下を出力する: + +```markdown +## dev-run 完了レポート + +### 実行概要 +- Plan: +- 範囲: +- 実行タスク数: X / スキップ: Y (done 済み) + +### 結果サマリー +| タスク | 結果 | 信号機 | +|-------|------|--------| +| NNN | 成功 / debug後成功 / スキップ | 🔵/🟡/🔴 | + +### 検証結果 +- テスト: X passed, Y failed +- カバレッジ: X/Y packages above threshold +- ビルド: OK / NG / N/A +- Lint: OK / NG / N/A +- 500行ルール: OK / X files over + +### verify → fix サイクル +- サイクル N: [修正内容の概要] + +### 残存問題(ある場合) +- [問題の詳細と推奨アクション] + +### 🟡 要確認ファイル +- [ファイル一覧と確認ポイント] + +### 🔴 要判断ファイル +- [ファイル一覧と判断が必要な理由] +``` + +### Step 7: Docker クリーンアップ + +プロジェクトルートに `docker-compose.yml` または `docker-compose.yaml` が存在するか確認する。存在する場合: + +1. `docker compose down` を実行してコンテナを停止する +2. 停止に失敗した場合はユーザーに報告する(ブロッキングにしない) + +## エスカレーション条件 + +以下の場合は自動実行を停止し、AskUserQuestion でユーザーに確認する: + +1. **範囲外依存が未完了**: 依存先タスクが done でない +2. **impl + debug 両方失敗**: サブエージェントが修正できなかった +3. **verify 2サイクル後も問題残存**: 残存問題をレポートして終了 +4. **🔴 セキュリティ/パフォーマンス問題**: レポートに明記、人間レビュー推奨 +5. **context.md / plan が存在しない**: 前提スキルの実行を案内して終了 + +## マーカー文字列 + +| マーカー | 意味 | +|---------|------| +| `IMPL_SUCCESS` | 実装成功(テスト全通過) | +| `IMPL_FAILED` | 実装失敗(3サイクル超え) | +| `DEBUG_SUCCESS` | デバッグ成功(エラー解消) | +| `DEBUG_FAILED` | デバッグ失敗(3サイクル超え) | +| `VERIFY_ALL_PASSED` | 検証全項目 OK | +| `VERIFY_ISSUES_FOUND` | 検証で問題あり | + +## ルール・制約 + +- context.md が存在しない場合は `/dev-context` を案内して終了する +- plan が存在しない場合は `/dev-plan` を案内して終了する +- `status: done` のタスクはスキップする(再開対応) +- verify → fix → re-verify のサイクルは最大2回 +- サブエージェントには Task ツールを使用させない(プロンプトで明示) +- 各プロンプトに context.md を埋め込みサブエージェントの Read 回数を最小化する +- テスト/ビルド/Lint コマンドは context.md から取得する(ハードコードしない) +- すべてのファイルは 500 行以内 +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) + +## 追加リソース + +### リファレンスファイル + +- **`references/impl-prompt-template.md`** — impl サブエージェントに渡すプロンプトテンプレート +- **`references/debug-prompt-template.md`** — debug サブエージェントに渡すプロンプトテンプレート +- **`references/verify-prompt-template.md`** — verify サブエージェントに渡すプロンプトテンプレート diff --git a/skills/dev-run/references/debug-prompt-template.md b/skills/dev-run/references/debug-prompt-template.md new file mode 100644 index 0000000..0fc0a48 --- /dev/null +++ b/skills/dev-run/references/debug-prompt-template.md @@ -0,0 +1,141 @@ +# Debug サブエージェント プロンプトテンプレート + +dev-run がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたはデバッグのエキスパートです。以下のエラーを診断・修正してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- すべてのファイルは **500行以内** に収めること +- テスト実行コマンド: `{{TEST_COMMAND}}` + +## プロジェクトコンテキスト + +{{CONTEXT_MD_CONTENT}} + +## エラー情報 + +{{ERROR_DETAILS}} + +## 関連タスク情報 + +{{TASK_FILE_CONTENT}} + +## デバッグワークフロー + +### Step 1: エラー分類 + +エラーメッセージを分析し、以下のカテゴリに分類する: + +| カテゴリ | パターン | +|---------|---------| +| コンパイル/型エラー | TypeError, SyntaxError, Cannot find module, missing import | +| テスト失敗 | AssertionError, expect(, assert, test failed | +| ランタイムエラー | null, undefined, panic, NullPointerException, segfault | +| 環境・設定 | ENOENT, Permission denied, port already in use, env | +| Lint/フォーマット | eslint, prettier, clippy, unused variable | +| 依存関係 | ERESOLVE, version conflict, peer dependency | + +### Step 2: カテゴリ別診断 + +**最小コンテキスト原則**: エラーに関連するファイルだけ読み込む。プロジェクト全体を読まない。 + +#### コンパイル/型エラー + +1. エラーメッセージから該当ファイルと行番号を特定する +2. 該当ファイルの関連部分を Read の offset/limit で読み込む +3. 型定義・インターフェースが関係する場合は Grep で検索して Read する +4. 修正案を生成する + +#### テスト失敗 + +1. 失敗テストのファイルと名称を特定する +2. テストファイルを Read し、期待値を確認する +3. 対象の実装ファイルを Read する +4. 期待値と実際の差分から原因を特定する +5. **判断**: テストが正しいか、実装が正しいかを判断する + - テストが正しい → 実装を修正 + - 実装が正しい → テストを修正(レポートに 🟡 として記録) + +#### ランタイムエラー + +1. スタックトレースからコールチェーンを特定する +2. 最も関連性の高いファイルから Read する +3. null/undefined チェックの漏れ、例外ハンドリングの不足を特定する +4. ガード句やエラーハンドリングを追加する + +#### 環境・設定 + +1. 設定ファイルを Glob で探索する +2. 環境変数、パス設定、ポート設定等を確認する +3. AI 単独で解決できない場合は明確にレポートに記載する + +#### Lint/フォーマット + +1. Lint/フォーマッターの自動修正コマンドがあれば実行する +2. 自動修正できない場合は手動で修正する +3. 修正後に再度 Lint を実行して確認する + +#### 依存関係 + +1. パッケージマネージャのエラー出力を分析する +2. 依存ツリーの競合を確認する +3. 互換性のあるバージョンを提案する + +### Intent コメントルール + +コード修正時に、既存の Intent コメント(🔵🟡🔴)を維持し、修正箇所には適切に追加・更新する: +- 既存の Intent コメントがある関数を修正する場合は、コメント内容が正確であれば維持。意図が変わった場合は更新する +- 新しい関数を追加する場合は public 関数に Intent コメントを付与する(🔵前工程指示 / 🟡妥当な推測 / 🔴AI推論補完) + +### Step 3: 修正の適用と検証 + +1. 修正案を適用する +2. カテゴリに応じた検証コマンドを実行する: + - コンパイル/型エラー → ビルド実行 + - テスト失敗 → 失敗していたテストを実行 + - ランタイムエラー → 関連テストを実行 + - Lint → Lint 再実行 +3. 修正が不十分な場合は Step 2 に戻る(**最大3サイクル**) + +### Step 4: 回帰テストと報告 + +1. 修正対象のエラーが解消されたことを確認する +2. 全テストを実行し、回帰がないことを確認する: `{{TEST_COMMAND}}` +3. 結果を以下のフォーマットで出力する: + +``` +## dev-debug 結果 + +### 検出されたエラー +- カテゴリ: [エラーカテゴリ] +- 原因: [根本原因の説明] + +### 適用した修正 +- [ファイル](パス): [修正内容] + +### 検証結果 +- 対象エラー: 解消 / 未解消 +- 回帰テスト: passed / failed + +### 確信度 +- 🔵/🟡/🔴: [修正の確信度と理由] +``` + +### 結果マーカー + +- 成功時: 最後の行に `DEBUG_SUCCESS` を出力する +- 失敗時(3サイクルで解決できない場合): 以下を出力する: + - これまでの診断結果の概要 + - 試行した修正の一覧 + - 考えられる追加の原因仮説 + - 最後の行に `DEBUG_FAILED` を出力する diff --git a/skills/dev-run/references/impl-prompt-template.md b/skills/dev-run/references/impl-prompt-template.md new file mode 100644 index 0000000..8746a8d --- /dev/null +++ b/skills/dev-run/references/impl-prompt-template.md @@ -0,0 +1,177 @@ +# Impl サブエージェント プロンプトテンプレート + +dev-run がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは TDD テストファースト実装のエキスパートです。以下のタスクを実装してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- すべてのファイルは **500行以内** に収めること +- テスト実行コマンド: `{{TEST_COMMAND}}` +- カバレッジ閾値: {{COVERAGE_THRESHOLD}} + +## プロジェクトコンテキスト + +{{CONTEXT_MD_CONTENT}} + +## タスク情報 + +{{TASK_FILE_CONTENT}} + +## Plan 設計概要 + +{{PLAN_MD_EXCERPT}} + +## 実装ワークフロー + +### Step 1: コンテキスト構築(最小限) + +インターフェースファーストで必要最小限のファイルだけ読み込む: + +1. タスクファイルの Interfaces セクションの型定義を確認する +2. 関連する型定義ファイルを Grep で探索する(必要時のみ) +3. 関連する既存テストファイルのパターンを Glob で探す(必要時のみ) +4. 実装ファイルの関連関数を Read の offset/limit で確認する(必要時のみ) + +### Step 2: テストケース生成(Red) + +タスクファイルの Test Strategy に基づきテストコードを生成する: + +1. 既存テストファイルのパターン(コンテキストの規約)に合わせる +2. タスクのインターフェース定義に基づくテストケースを記述する +3. テストを実行する: `{{TEST_COMMAND}}` +4. **失敗を確認する**(Red 状態) + +テストが先に通ってしまう場合は、要件やテストの妥当性を再確認する。 + +#### 複雑度別の戦略 + +複雑度: **{{ESTIMATED_COMPLEXITY}}** + +- **low**: テスト + 実装を一括生成し、テスト実行で検証する。失敗時のみ個別修正に移行する +- **medium**: テスト → Red 確認 → 実装 → Green 確認の標準サイクル +- **high**: テストケースを1-2個ずつ追加し、1つずつ Green にする段階的アプローチ + +### Step 3: 実装(Green) + +テストを通す最小限の実装を生成する: + +1. インターフェース定義に準拠したコードを書く +2. **Intent コメントを付与する**(下記ルール参照) +3. テスト実行 → **成功を確認する**(Green 状態) +4. 失敗した場合はエラーを分析し修正する(最大3サイクル) +5. 3サイクルで解決しない場合は Step 5 の失敗処理へ + +#### Intent コメントルール + +すべての public 関数・メソッドに、設計判断の理由を示すコメントを付与する: + +- 🔵 **前工程指示**: タスクファイル・plan.md で明示的に指示された設計判断 +- 🟡 **妥当な推測**: 指示内容から推論した妥当な設計判断 +- 🔴 **AI推論補完**: 前工程に根拠がなくAIが推論で補完した判断 + +形式例: +``` +// 🔵 Intent: タスクファイルで指定された TodoRepository インターフェースを実装。 +func (r *PostgresTodoRepository) Create(ctx context.Context, todo *model.Todo) error { +``` + +- private 関数は設計判断がある場合のみ。テストコードには付与しない +- 1コメント = 1-2行で簡潔に + +### Step 4: リファクタリング + 品質チェック + +テストが Green の状態で以下を実行する: + +#### 4a. 500行ルール + +関連するすべてのファイルの行数を確認する(絶対パスを使用): + +```bash +wc -l "$(git rev-parse --show-toplevel)/<ファイルの相対パス>" +``` + +500行を超えるファイルがある場合: +- 責務の境界で分割する(Single Responsibility Principle) +- テストファイルも対応して分割する +- インポート/エクスポートの整合性を維持する +- 分割後にテストを再実行する + +#### 4b. セキュリティチェック + +- インジェクション(SQL, コマンド, XSS)がないか +- 認証・認可チェックの漏れがないか +- 機密情報のログ出力がないか +- ユーザー入力のバリデーション不足がないか + +#### 4c. パフォーマンスチェック + +- N+1問題(ループ内の DB/API クエリ) +- メモリリーク(イベントリスナー未解除、クロージャ参照保持) +- 非効率なアルゴリズム(O(n^2) 以上で改善可能な箇所) + +#### 4d. コード品質 + +- 重複コードの排除 +- 命名の改善 +- 不要なコメントの削除 + +#### 4e. カバレッジチェック + +1. カバレッジ閾値: {{COVERAGE_THRESHOLD}} +2. タスクファイルの Files セクションから対象パッケージを特定する +3. パッケージごとにカバレッジを計測する(Coverage Command をパッケージ単位で実行) +4. `[no test files]` は 0% として扱う +5. **閾値未達時**: テストを追加し再計測する(最大3サイクル) +6. **3サイクル後も未達**: 🟡 として報告し続行する(ブロッキングにしない) + +テスト再実行 → 成功維持を確認する。 + +### Step 5: 完了報告 + +#### タスクファイルの更新 + +タスクファイル `{{TASK_FILE_PATH}}` の frontmatter の `status` を `done` に更新する。 + +Edit ツールで以下を置換: +- `status: pending` → `status: done` +- または `status: in_progress` → `status: done` + +#### 確信度レポートの出力 + +実装した各ファイルに確信度を付与し、以下のフォーマットで出力する: + +``` +## dev-impl 確信度レポート + +### カバレッジ結果 +| パッケージ | カバレッジ | 閾値 | 結果 | +|-----------|----------|------|------| +| internal/handler | 85.2% | 80% | OK | + +### 🔵 前工程指示(レビュー低優先) +- [ファイル名](パス) — 既存パターン準拠 + +### 🟡 妥当な推測(要確認) +- [ファイル名](パス) — [確認すべき点] + +### 🔴 AI推論補完(人間の確認必須) +- [ファイル名](パス) — [判断が必要な理由] +``` + +#### 結果マーカー + +- 成功時: 最後の行に `IMPL_SUCCESS` を出力する +- 失敗時(3サイクルで解決できない場合): 以下を出力する: + - 発生したエラーの詳細 + - 試みた修正の概要 + - 最後の行に `IMPL_FAILED` を出力する diff --git a/skills/dev-run/references/verify-prompt-template.md b/skills/dev-run/references/verify-prompt-template.md new file mode 100644 index 0000000..f938a4d --- /dev/null +++ b/skills/dev-run/references/verify-prompt-template.md @@ -0,0 +1,154 @@ +# Verify サブエージェント プロンプトテンプレート + +dev-run がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは検証のエキスパートです。Plan 内の全タスクの完了状態とテスト・ビルド・Lint の整合性を検証してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- カバレッジ閾値: {{COVERAGE_THRESHOLD}} + +## プロジェクトコンテキスト + +{{CONTEXT_MD_CONTENT}} + +## Plan 情報 + +- Plan 名: {{PLAN_NAME}} +- タスクディレクトリ: `docs/dev/plans/{{PLAN_NAME}}/tasks/` +- レポート出力先: `docs/dev/plans/{{PLAN_NAME}}/reports/verify-{{TODAY_DATE}}.md` + +## 検証ワークフロー + +### Step 1: タスク完了チェック + +`docs/dev/plans/{{PLAN_NAME}}/tasks/` 内の全タスクファイルを Glob で列挙し、各ファイルを Read して frontmatter の `status` を確認する。 + +- すべて `done` → 記録して次へ +- `pending` / `in_progress` がある → 記録する(中断しない) + +### Step 2: 全テスト実行 + +テスト実行コマンド: `{{TEST_COMMAND}}` + +テスト結果を記録する: passed / failed / skipped の件数。 + +失敗テストがある場合はテスト名とエラーメッセージを記録する。 + +### Step 3: カバレッジチェック + +プロジェクト全体のカバレッジを計測し、パッケージごとに閾値({{COVERAGE_THRESHOLD}})と比較する。 + +1. Coverage Command でプロジェクト全体のカバレッジを計測する +2. パッケージごとにカバレッジ率を抽出し、閾値と比較する +3. `[no test files]` は 0% として扱う +4. 閾値未達のパッケージは Issues Found に記録する + +### Step 4: ビルド確認 + +{{BUILD_COMMAND}} + +ビルドコマンドが空の場合は N/A と記録する。 + +### Step 5: Lint 実行 + +{{LINT_COMMAND}} + +Lint コマンドが空の場合は N/A と記録する。 + +### Step 6: ファイルサイズチェック(500行ルール) + +各タスクファイルの Files セクションから対象ファイルパスを収集する(絶対パスを使用)。 + +```bash +wc -l "$(git rev-parse --show-toplevel)/<ファイルの相対パス>" +``` + +500行を超えるファイルがあれば警告として記録する。 + +### Step 7: 信号機サマリー + +全タスクの impl 結果から確信度情報を集約する: + +- 🟡 中確信の項目一覧 +- 🔴 要判断の項目一覧 + +🔴 が残っている場合は明確に警告する。 + +### Step 8: レポート出力 + +検証結果を `docs/dev/plans/{{PLAN_NAME}}/reports/verify-{{TODAY_DATE}}.md` に Write する。 + +レポートフォーマット: + +```markdown +# Verification Report - {{TODAY_DATE}} +## Plan: {{PLAN_NAME}} + +## Summary + +| Item | Result | +|------|--------| +| Tasks | X/Y completed | +| Tests | Z passed, W failed, V skipped | +| Coverage | X/Y packages above threshold (threshold: {{COVERAGE_THRESHOLD}}) | +| Build | OK / NG / N/A | +| Lint | OK / NG / N/A | +| 500-line rule | OK / X files over limit | + +## Task Status + +| ID | Title | Status | +|----|-------|--------| +| 001 | ... | done | +| 002 | ... | done | + +## Test Results + +[テスト実行の出力サマリー] +[失敗テストがある場合は詳細] + +## Coverage Results + +| パッケージ | カバレッジ | 閾値 | 結果 | +|-----------|----------|------|------| +| internal/handler | XX.X% | {{COVERAGE_THRESHOLD}} | OK / NG | + +[閾値未達パッケージの詳細(ある場合)] + +## File Size Check + +[500行超過ファイルの一覧(ある場合)] + +## Confidence Summary + +### 🟡 要確認(Medium Confidence) +- [ファイル](パス) — [確認すべき点] + +### 🔴 要判断(Low Confidence) +- [ファイル](パス) — [判断が必要な理由] + +## Issues Found + +[検出された問題の詳細] + +## Recommendations + +[問題がある場合の次アクション提案] +``` + +### 結果マーカー + +レポート出力後、以下のマーカーを出力する: + +- Summary の全項目が OK/N/A かつ失敗テストなし かつカバレッジ閾値未達パッケージなし: 最後の行に `VERIFY_ALL_PASSED` を出力する +- いずれかの項目に問題あり(カバレッジ閾値未達を含む): 最後の行に `VERIFY_ISSUES_FOUND` を出力する diff --git a/skills/dev-screen-spec/SKILL.md b/skills/dev-screen-spec/SKILL.md new file mode 100644 index 0000000..d36edbe --- /dev/null +++ b/skills/dev-screen-spec/SKILL.md @@ -0,0 +1,550 @@ +--- +name: dev-screen-spec +description: This skill should be used when the user asks to "dev-screen-spec", "画面仕様を生成", "画面仕様を更新", "screen spec", "generate screen spec", "update screen spec", "画面仕様ドキュメント". ソースコードから画面仕様ドキュメントを自動生成・差分更新する。受け入れ条件から画面仕様を事前生成する from-plan モードも対応。 +argument-hint: '[init|update [screen-id]|from-plan ]' +--- + +# Dev Screen Spec + +ソースコードから画面仕様ドキュメント(Screen Spec)を生成・差分更新するスキル。 +`docs/dev/screen-specs/` 配下に画面ごとの Markdown with frontmatter 形式で出力する。 +webtest 計画の差分更新パイプラインにおいて、ソースコード変更を画面・機能単位の変更に翻訳する中間レイヤーとして機能する。 + +## 前提知識 + +### dev-* スキルフロー内の位置 + +``` +[ソースコード変更] ← dev-impl / 手作業 / 何でも + │ + │ git diff (last_synced_commit → HEAD) + ▼ +[dev-screen-spec] ← 手動実行(本スキル) + │ + │ 画面仕様の差分 + ▼ +[dev-webtest-plan] ← 既存の受け入れ要件 + 画面仕様を入力に + │ + ▼ +[dev-webtest] ← 既存のまま +``` + +### 引数フォーマット + +``` +/dev-screen-spec # 自動判定(初回 or 差分更新) +/dev-screen-spec init # 強制的に初回生成モード +/dev-screen-spec update # 強制的に差分更新モード +/dev-screen-spec update login # 特定画面のみ更新 +/dev-screen-spec from-plan # AC変更のある plan を自動検出 +/dev-screen-spec from-plan # 特定の plan を明示指定 +``` + +### モード自動判定 + +`docs/dev/screen-specs/_index.md` の存在で自動判定する(ユーザー質問不要): + +| モード | 判定条件 | 特徴 | +|-------|---------|------| +| from-plan | 引数が `from-plan` で始まる | 受け入れ条件(AC + plan.md)から画面仕様を生成。ソースコード不要 | +| 初回生成 | `_index.md` が存在しない、または引数 `init` | ソースコード全体を解析して一括生成 | +| 差分更新 | `_index.md` が存在する、または引数 `update` | git diff で影響画面のみ更新 | + +### サブエージェント制約(重要) + +サブエージェントは Task ツールを使用できない(ネスト不可のアーキテクチャ制約)。そのため: +- コード探索は Glob/Grep/Read を直接使用する +- TodoWrite は使用しない +- サブエージェントに渡すのはファイルパスのみ。サブエージェントが自分で Read する + +### コンテキスト管理戦略 + +メインコンテキストの肥大化を防ぐため、**中間ファイルとパス参照** を使用する: +- メインエージェントはファイルの全文を Read しない(パス存在確認・Grep での部分情報取得のみ) +- サブエージェントに渡すのはファイルパス。サブエージェントが自分で Read する +- Phase 間のデータ受け渡しは中間ファイル経由(`tmp/screen-spec/`) +- サブエージェントの返却はマーカー+ファイルパス+行数のみ + +### 中間ファイル + +``` +tmp/screen-spec/ +├── explore-routes.md # Phase 1: ルーティング探索結果 +├── explore-pages.md # Phase 1: ページコンポーネント一覧 +├── group-.md # Phase 3: グループサマリー(初回生成) +├── diff-.md # 差分更新 Phase 2: 各画面の変更サマリー +├── sync-.md # 差分更新 Phase 1.5: from-plan ソース同期分析 +└── from-plan/ + └── screen-analysis.md # from-plan Phase 2: 画面構成分析結果 +``` + +### 信号機 + +| 信号 | 基準 | +|------|------| +| 🔵 | ソースコードから直接読み取れた情報(HTML要素、バリデーション属性、ルーティング定義等) | +| 🟡 | ソースコードから推測した情報(コンポーネント名から画面名を推定、import関係からの推論等) | +| 🔴 | AI推論補完(ソースに明示されていないが、一般的なWebアプリとして必要と判断した項目) | + +from-plan モードでの信号機基準: +| 信号 | 基準 | +|------|------| +| 🔵 | ACに明示されている情報 | +| 🟡 | plan.md から推測した情報 | +| 🔴 | AI推論補完 | + +## ワークフロー: 初回生成モード + +### Phase 1: プロジェクト分析(メイン) + +1. `docs/dev/context.md` の存在を確認する。存在しない場合は `/dev-context` の実行を案内して終了する +2. `docs/dev/context.md` を Read して技術スタック(フレームワーク、言語)を把握する +3. 中間ファイルディレクトリを作成する: + ```bash + mkdir -p "$(git rev-parse --show-toplevel)/tmp/screen-spec" + ``` +4. general-purpose サブエージェントを **2つ並列** で起動する: + +#### 1a. ルーティング探索(general-purpose) + +1. `references/explore-routes-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_PATH}}` ← `docs/dev/context.md` の絶対パス + - `{{TMP_DIR}}` ← `tmp/screen-spec/` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力のマーカーを確認する: + - `EXPLORE_ROUTES_SUCCESS` → 次へ + - `EXPLORE_ROUTES_FAILED` → エラー理由をユーザーに報告して終了 + +#### 1b. ページコンポーネント探索(general-purpose) + +1. `references/explore-pages-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_PATH}}` ← `docs/dev/context.md` の絶対パス + - `{{TMP_DIR}}` ← `tmp/screen-spec/` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力のマーカーを確認する: + - `EXPLORE_PAGES_SUCCESS` → 次へ + - `EXPLORE_PAGES_FAILED` → エラー理由をユーザーに報告して終了 + +### Phase 2: グループ分割の設計(メイン) + +1. Phase 1 の中間ファイルの「パス構造のみ」を Grep で取得する: + - `tmp/screen-spec/explore-routes.md` + - `tmp/screen-spec/explore-pages.md` +2. ルーティング情報とページコンポーネント情報を統合する +3. 画面一覧を構成する: + - 画面ID(ケバブケース)、画面名(日本語)、パス、認証要否を決定 + - 各画面の related_files(対応するソースファイルパス)を決定 +4. グループ案を自動生成する(URLパス構造や機能ドメインに基づく) +5. AskUserQuestion でユーザーに確認・調整する: + - 画面一覧(画面ID, 画面名, パス, グループ) + - グループ分割案 + - 修正が必要ならユーザーの指示を反映 +6. 画面遷移フローを設計する: + - ルーティング情報とページ間のリンク関係から遷移フローを構成 + - 業務的な意味のあるフロー単位でまとめる +7. 到達不能画面チェックを実施する: + - 全画面がいずれかのフローに含まれているか検証 + - 含まれていない画面があれば警告リストに追加 + +### Phase 3: 画面仕様ファイル生成(グループ単位並列サブエージェント) + +グループ単位で general-purpose サブエージェントを起動(並列)。1サブエージェントが「グループ内の全画面」を担当する: + +1. `references/generate-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{GROUP_NAME}}` ← グループ名 + - `{{SCREENS}}` ← グループ内の画面情報一覧(画面ID, 画面名, パス, 認証要否, related_files) + - `{{SCREEN_SPEC_FORMAT_PATH}}` ← `references/screen-spec-format.md` の絶対パス + - `{{CONTEXT_MD_PATH}}` ← `docs/dev/context.md` の絶対パス + - `{{OUTPUT_DIR}}` ← `docs/dev/screen-specs/` の絶対パス + - `{{TMP_DIR}}` ← `tmp/screen-spec/` の絶対パス +3. general-purpose サブエージェントを起動する +4. サブエージェントの作業: + - グループ内の全画面仕様ファイルを生成 + - グループサマリーを中間ファイルに出力: `tmp/screen-spec/group-.md` +5. 出力のマーカーを確認する: + - `GENERATE_SCREEN_SPEC_SUCCESS` → 完了 + - `GENERATE_SCREEN_SPEC_FAILED` → エラー理由を記録 + +複数グループがある場合は並列で実行する(Agent ツールを複数同時起動)。 + +### Phase 4: 完了処理(メイン) + +1. グループサマリー(パス+行数のみ)から `_index.md` を組み立てる: + - 画面一覧テーブル(Phase 2 の設計に基づく) + - グループ情報 + - 画面遷移フロー(Phase 2 の設計に基づく) + - 到達不能画面チェック結果 + - frontmatter: `last_synced_commit` を現在の HEAD に設定、`updated_at` を今日の日付に設定、`groups` を設定 +2. `_index.md` の frontmatter にグループ情報を含める: + ```yaml + --- + last_synced_commit: abc1234 + updated_at: "2026-03-10" + groups: + - name: user-management + screens: [user-list, user-detail, user-create] + - name: auth + screens: [login, forgot-password] + - name: settings + screens: [user-settings] + --- + ``` +3. 全ファイルの `last_synced_commit` を現在の HEAD(短縮形)に設定する: + ```bash + git rev-parse --short HEAD + ``` +4. 生成結果のサマリーを表示する: + +```markdown +## dev-screen-spec 完了レポート(初回生成) + +### 生成概要 +- 画面数: N +- グループ数: N +- 生成ファイル数: N + 1(_index.md 含む) +- last_synced_commit: + +### 生成ファイル一覧 + +| ファイル | 画面名 | パス | グループ | 項目数 | 🔵 | 🟡 | 🔴 | +|---------|--------|------|---------|--------|-----|-----|-----| +| _index.md | 画面一覧 | - | - | - | - | - | - | +| login.md | ログイン | /login | auth | 4 | 3 | 1 | 0 | +| ... + +### ⚠️ 🔴 警告 +以下の項目はソースコードに根拠がなく、AI が推論で追加しました。内容を確認してください: +- <ファイル名> <セクション>: <項目名> + +### ⚠️ 到達不能画面 +- <画面ID>: いずれの遷移フローにも含まれていません + +### 次のステップ +- 画面仕様の内容を確認してください +- 差分更新: ソースコード変更後に `/dev-screen-spec` を再実行 +- テスト計画生成: `/dev-webtest-plan` で画面仕様を入力としてテスト計画を生成 +``` + +5. 中間ファイルをクリーンアップする: + ```bash + rm -rf "$(git rev-parse --show-toplevel)/tmp/screen-spec/" + ``` + +## ワークフロー: 差分更新モード + +### Phase 1: 変更検知(メイン) + +1. `docs/dev/screen-specs/_index.md` の `last_synced_commit` を Grep で取得する +2. `last_synced_commit` が現在の git history に存在するか確認する: + ```bash + git cat-file -t + ``` + 存在しない場合 → ユーザーに「初回生成モードで再生成」を提案して終了 +3. `git diff --name-only ..HEAD` で変更ファイル一覧を取得する +4. 変更ファイルが50件を超える場合 → ユーザーに確認後、初回生成モードにフォールバック +5. 各画面の `related_files` を Grep で取得し、変更ファイル一覧と突き合わせる: + ``` + 影響判定ロジック: + - related_files に含まれるファイルが変更されている → 影響あり + - related_files に含まれないが、ルーティング定義が変更されている → 新画面追加の可能性 + - related_files のファイルが削除されている → 画面削除の可能性 + ``` +6. 特定画面のみ更新(引数で `screen-id` 指定時)の場合は、その画面のみを対象にする +7. 影響画面がない場合 → 「変更なし」を表示して終了 +8. 影響画面の一覧を表示する +9. 中間ファイルディレクトリを作成する: + ```bash + mkdir -p "$(git rev-parse --show-toplevel)/tmp/screen-spec" + ``` + +### Phase 1.5: from-plan 画面のソース同期判定(メイン) + +1. `source: from-plan` かつ `last_synced_commit: null` の画面を Grep で検出する +2. 該当画面がある場合: + a. 各画面の `related_files` が空なので、ルーティング情報から対応するソースファイルを特定する + b. ソースファイルが見つかった画面について、general-purpose サブエージェントで分析(画面数分並列): + - 既存の画面仕様(from-plan)を Read + - ソースファイルを Read + - 差分(from-plan の内容 vs ソースの実装)を表示用にまとめる + - 中間ファイルに出力: `tmp/screen-spec/sync-.md` + - マーカー: `SYNC_ANALYZE_SUCCESS` / `SYNC_ANALYZE_FAILED` + c. 各画面について AskUserQuestion で解決方法を選ばせる: + - 「ソースを採用」: ソースコードの実装状態で画面仕様を上書き + - 「from-plan を維持」: 画面仕様はそのまま(実装が仕様と異なる場合は実装を修正すべき) + - 「マージ」: 両方の情報を統合(サブエージェントがマージ実行) + d. 選択結果に基づいて画面仕様を更新、`source: from-source`, `last_synced_commit: HEAD` に変更 +3. 該当画面がない場合: 通常の差分更新フローに進む + +### Phase 2: 差分内容の分析(グループ単位並列サブエージェント) + +影響のある画面が属するグループ単位で general-purpose サブエージェントを起動(並列): + +1. `references/diff-analyze-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{SCREEN_ID}}` ← 画面ID + - `{{LAST_SYNCED_COMMIT}}` ← last_synced_commit + - `{{RELATED_FILES}}` ← その画面の related_files 一覧 + - `{{EXISTING_SCREEN_SPEC_PATH}}` ← 既存の画面仕様ファイルパス + - `{{TMP_DIR}}` ← `tmp/screen-spec/` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力のマーカーを確認する: + - `DIFF_ANALYZE_SUCCESS` → Phase 3 へ + - `DIFF_ANALYZE_FAILED` → エラー理由を記録 + +### Phase 3: 画面仕様の更新(グループ単位並列サブエージェント) + +グループ単位で general-purpose サブエージェントを起動(並列): + +1. `references/diff-update-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{SCREEN_ID}}` ← 画面ID + - `{{DIFF_SUMMARY_PATH}}` ← `tmp/screen-spec/diff-.md` の絶対パス + - `{{EXISTING_SCREEN_SPEC_PATH}}` ← 既存の画面仕様ファイルパス + - `{{SCREEN_SPEC_FORMAT_PATH}}` ← `references/screen-spec-format.md` の絶対パス + - `{{OUTPUT_DIR}}` ← `docs/dev/screen-specs/` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力のマーカーを確認する: + - `UPDATE_SCREEN_SPEC_SUCCESS` → 完了 + - `UPDATE_SCREEN_SPEC_FAILED` → エラー理由を記録 + +### Phase 4: 新画面・削除画面の処理(メイン) + +- **新画面**: ルーティング変更が検出された場合、初回生成モードの Phase 3 と同様に生成する +- **削除画面**: ソースファイルが全て削除されている画面は、ユーザーに削除を確認する + +### Phase 5: 完了処理(メイン) + +1. `_index.md` を更新する: + - 画面一覧テーブルの更新(新規追加・削除を反映) + - グループ情報の更新 + - 画面遷移フローの更新 + - 到達不能画面チェックの再実施 + - `last_synced_commit` を HEAD に更新、`updated_at` を今日の日付に更新 +2. 全更新ファイルの `last_synced_commit` を更新する +3. 変更サマリーを表示する: + +```markdown +## dev-screen-spec 完了レポート(差分更新) + +### 更新概要 +- 前回同期: → 今回: +- 変更ファイル数: N +- 影響画面数: N + +### 更新画面一覧 + +| 画面ID | 画面名 | 変更セクション | 変更概要 | +|--------|--------|-------------|---------| +| login | ログイン | バリデーション | パスワード最低文字数を6→8に変更 | + +### 新規追加画面 +- <画面ID>: <画面名> + +### 削除画面 +- <画面ID>: <画面名>(ユーザー確認済み) + +### ⚠️ 🔴 警告 +以下の項目はソースコードに根拠がなく、AI が推論で追加しました: +- <ファイル名> <セクション>: <項目名> + +### ⚠️ 到達不能画面 +- <画面ID>: いずれの遷移フローにも含まれていません +``` + +4. 中間ファイルをクリーンアップする: + ```bash + rm -rf "$(git rev-parse --show-toplevel)/tmp/screen-spec/" + ``` + +## ワークフロー: from-plan モード + +### Phase 0: 対象 plan の特定(メイン) + +plan-name が明示指定されている場合はそのまま Phase 1 へ進む。省略されている場合は自動検出する: + +1. `docs/dev/screen-specs/_index.md` が存在する場合: + a. `last_synced_commit` を Grep で取得する + b. 以下のコマンドで AC が変更された plan を検出する: + ```bash + git diff --name-only ..HEAD -- docs/dev/plans/*/acceptance-criteria.md + ``` + c. 結果のパスから plan 名を抽出する(例: `docs/dev/plans/auth/acceptance-criteria.md` → `auth`) +2. `_index.md` が存在しない場合: + a. Glob で `docs/dev/plans/*/acceptance-criteria.md` を取得する + b. 全 plan を候補にする +3. 候補が0件 → 「対象の plan がありません」と報告して終了 +4. 候補が1件 → そのまま Phase 1 へ進む +5. 候補が複数 → AskUserQuestion で選択する: + ``` + 以下の plan の acceptance-criteria.md が変更されています。対象を選んでください: + 1. auth + 2. user-management + (all で全部、カンマ区切りで複数選択可) + ``` +6. 複数 plan が選択された場合、選択された plan を **順番に** Phase 1〜5 のワークフローを繰り返す + +### Phase 1: 入力検証(メイン) + +1. `docs/dev/context.md` の存在を確認する。存在しない場合は `/dev-context` の実行を案内して終了する +2. `docs/dev/plans//acceptance-criteria.md` の存在を確認する。存在しない場合は「Full-spec モードの `/dev-plan` で受け入れ条件を作成してください」と案内して終了する +3. `docs/dev/plans//plan.md` の存在を確認する(任意だが推奨) +4. 既存の `docs/dev/screen-specs/_index.md` がある場合、既存画面仕様への追加になることを通知する +5. 中間ファイルディレクトリを作成する: `mkdir -p tmp/screen-spec/from-plan/` + +### Phase 2: 画面構成分析(general-purpose サブエージェント) + +1. `references/from-plan-analyze-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{ACCEPTANCE_CRITERIA_PATH}}` ← acceptance-criteria.md の絶対パス + - `{{PLAN_MD_PATH}}` ← plan.md の絶対パス(存在しない場合は「なし」) + - `{{EXISTING_INDEX_PATH}}` ← 既存の _index.md の絶対パス(存在しない場合は「なし」) + - `{{TMP_DIR}}` ← `tmp/screen-spec/from-plan/` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力: `tmp/screen-spec/from-plan/screen-analysis.md`(画面一覧、各画面の要件、グループ案) +5. マーカー: `FROM_PLAN_ANALYZE_SUCCESS` / `FROM_PLAN_ANALYZE_FAILED` + +### Phase 3: ユーザー確認(メイン) + +1. 中間ファイルの画面一覧とグループ案を Grep で要約取得する +2. AskUserQuestion でユーザーに確認する: + - 画面一覧(画面ID, 画面名, パス, グループ) + - グループ分割 + - 修正が必要ならユーザーの指示を反映 + +### Phase 4: 画面仕様ファイル生成(並列 general-purpose サブエージェント) + +グループ単位でサブエージェントを起動(並列): + +1. `references/from-plan-generate-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{GROUP_NAME}}` ← グループ名 + - `{{SCREEN_ANALYSIS_PATH}}` ← `tmp/screen-spec/from-plan/screen-analysis.md` の絶対パス + - `{{ACCEPTANCE_CRITERIA_PATH}}` ← acceptance-criteria.md の絶対パス + - `{{PLAN_MD_PATH}}` ← plan.md の絶対パス + - `{{SCREEN_SPEC_FORMAT_PATH}}` ← `references/screen-spec-format.md` の絶対パス + - `{{PLAN_NAME}}` ← plan 名 + - `{{OUTPUT_DIR}}` ← `docs/dev/screen-specs/` の絶対パス +3. サブエージェントの作業: + - ACとplan.mdを Read + - グループ内の各画面について画面仕様ファイルを生成 + - frontmatter に `source: from-plan`, `source_plan: `, `last_synced_commit: null` を設定 + - `related_files` は空(ソースがまだないため) + - 信号機: ACに明示 → 🔵、plan.mdから推測 → 🟡、AI推論 → 🔴 +4. マーカー: `FROM_PLAN_GENERATE_SUCCESS` / `FROM_PLAN_GENERATE_FAILED` + +### Phase 5: 完了処理(メイン) + +1. `_index.md` を生成または更新する: + - 画面一覧テーブル + - グループ情報 + - 画面遷移フロー(ACから読み取れる範囲) + - frontmatter: `last_synced_commit` は現在の HEAD、`updated_at` は今日の日付 +2. 完了レポートを表示する: + +```markdown +## dev-screen-spec 完了レポート(from-plan) + +### 生成概要 +- Source Plan: +- 画面数: N +- グループ数: N + +### 生成ファイル一覧 + +| ファイル | 画面名 | パス | グループ | 🔵 | 🟡 | 🔴 | +|---------|--------|------|---------|-----|-----|-----| +| login.md | ログイン | /login | auth | 3 | 1 | 0 | + +### ⚠️ 注意 +これらの画面仕様は受け入れ条件から生成されたものです。 +実装後に `/dev-screen-spec update` を実行してソースコードと同期してください。 + +### 次のステップ +- 画面仕様の内容をレビューしてください +- `/dev-webtest-plan ` でテスト計画を生成 +- `/dev-impl ` で実装を開始 +- 実装後: `/dev-screen-spec update` でソースコードと同期 +``` + +3. 中間ファイルをクリーンアップする + +## サブエージェント戦略 + +| Phase | タイプ | 用途 | 並列 | +|-------|-------|------|------| +| 初回 1a | general-purpose | ルーティング探索 | 1b と並列 | +| 初回 1b | general-purpose | ページコンポーネント探索 | 1a と並列 | +| 初回 3 | general-purpose | グループ単位で画面仕様生成 | グループ数分並列 | +| 差分 1.5 | general-purpose | from-plan ソース同期分析 | 画面数分並列 | +| 差分 2 | general-purpose | git diff の分析と変更サマリー出力 | グループ単位並列 | +| 差分 3 | general-purpose | 画面仕様ファイル更新 | グループ単位並列 | +| from-plan 2 | general-purpose | 画面構成分析 | 単独 | +| from-plan 4 | general-purpose | グループ単位で画面仕様生成 | グループ数分並列 | + +## エスカレーション条件 + +以下の場合は自動処理を停止し、ユーザーに確認する: + +1. **context.md 不在**: `/dev-context` を案内して終了 +2. **last_synced_commit が git history にない**: rebase や force push 後。「初回生成モードで再生成」を提案 +3. **変更ファイルが50件超**: ユーザーに確認後、初回生成モードにフォールバック +4. **画面削除の検出**: ユーザーに削除を確認 +5. **related_files のファイルが存在しない**: 該当画面の related_files を再探索 +6. **acceptance-criteria.md 不在(from-plan時)**: 「Full-spec モードの `/dev-plan` で受け入れ条件を作成してください」と案内して終了 +7. **from-plan 画面のソース同期で対応ソースが見つからない**: 該当画面をスキップし、ユーザーに報告(実装がまだの可能性) + +## マーカー文字列 + +| マーカー | 意味 | +|---------|------| +| `EXPLORE_ROUTES_SUCCESS` | ルーティング探索成功 | +| `EXPLORE_ROUTES_FAILED` | ルーティング探索失敗 | +| `EXPLORE_PAGES_SUCCESS` | ページコンポーネント探索成功 | +| `EXPLORE_PAGES_FAILED` | ページコンポーネント探索失敗 | +| `GENERATE_SCREEN_SPEC_SUCCESS` | 画面仕様ファイル生成成功 | +| `GENERATE_SCREEN_SPEC_FAILED` | 画面仕様ファイル生成失敗 | +| `DIFF_ANALYZE_SUCCESS` | 差分分析成功 | +| `DIFF_ANALYZE_FAILED` | 差分分析失敗 | +| `UPDATE_SCREEN_SPEC_SUCCESS` | 画面仕様更新成功 | +| `UPDATE_SCREEN_SPEC_FAILED` | 画面仕様更新失敗 | +| `FROM_PLAN_ANALYZE_SUCCESS` | from-plan 画面構成分析成功 | +| `FROM_PLAN_ANALYZE_FAILED` | from-plan 画面構成分析失敗 | +| `FROM_PLAN_GENERATE_SUCCESS` | from-plan 画面仕様生成成功 | +| `FROM_PLAN_GENERATE_FAILED` | from-plan 画面仕様生成失敗 | +| `SYNC_ANALYZE_SUCCESS` | from-plan ソース同期分析成功 | +| `SYNC_ANALYZE_FAILED` | from-plan ソース同期分析失敗 | + +## ルール・制約 + +- context.md が存在しない場合は `/dev-context` を案内して終了する +- モード判定は自動(ユーザー質問不要) +- `docs/dev/screen-specs/` が存在しない場合は自動作成する +- 画面仕様ファイルはソースコードの「現在の状態」を反映する(あるべき姿ではなく実装の状態) +- from-plan モードで生成された画面仕様は受け入れ条件に基づく(実装前の仕様) +- 差分更新ではソースコードの変更のみを反映する(仕様変更の推測はしない) +- related_files はソース内の import/include 関係を辿って特定する(手動メンテ不要) +- 1画面1ファイルの原則を維持する(複合ページでも画面単位で分割) +- 中間ファイルはスキル完了時に必ず削除する +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- サブエージェントは Task/TodoWrite 使用禁止 +- メインエージェントはファイル全文を Read しない(パス確認・Grep のみ) +- サブエージェントにはファイルパスを渡し、サブエージェントが自分で Read する +- Phase 間のデータ受け渡しは中間ファイル(`tmp/screen-spec/`)経由 +- サブエージェントはマーカー+ファイルパス+行数のみ返す(結果本文は返さない) +- 🔴 は完了レポートで警告表示する + +## 追加リソース + +### リファレンスファイル + +- **`references/screen-spec-format.md`** — 画面仕様ドキュメントの出力フォーマット定義 +- **`references/explore-routes-prompt-template.md`** — Phase 1: ルーティング探索用プロンプトテンプレート +- **`references/explore-pages-prompt-template.md`** — Phase 1: ページコンポーネント探索用プロンプトテンプレート +- **`references/generate-prompt-template.md`** — Phase 3: 画面仕様ファイル生成用プロンプトテンプレート +- **`references/diff-analyze-prompt-template.md`** — 差分更新 Phase 2: 変更分析用プロンプトテンプレート +- **`references/diff-update-prompt-template.md`** — 差分更新 Phase 3: 画面仕様更新用プロンプトテンプレート +- **`references/from-plan-analyze-prompt-template.md`** — from-plan Phase 2: 画面構成分析用プロンプトテンプレート +- **`references/from-plan-generate-prompt-template.md`** — from-plan Phase 4: 画面仕様ファイル生成用プロンプトテンプレート diff --git a/skills/dev-screen-spec/references/diff-analyze-prompt-template.md b/skills/dev-screen-spec/references/diff-analyze-prompt-template.md new file mode 100644 index 0000000..da042f5 --- /dev/null +++ b/skills/dev-screen-spec/references/diff-analyze-prompt-template.md @@ -0,0 +1,177 @@ +# 差分分析 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは画面仕様ドキュメントの差分アナリストです。git diff の内容を分析し、既存の画面仕様のどのセクションに影響があるかを特定してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 分析パラメータ + +- **画面ID**: {{SCREEN_ID}} +- **前回同期コミット**: {{LAST_SYNCED_COMMIT}} + +## 入力データ + +### 関連ソースファイル(diff の対象) + +{{RELATED_FILES}} + +### 既存の画面仕様ファイル + +{{EXISTING_SCREEN_SPEC_PATH}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 分析タスク + +### 1. git diff の取得 + +以下のコマンドで該当ファイルの diff を取得する: + +```bash +git diff {{LAST_SYNCED_COMMIT}}..HEAD -- {{RELATED_FILES}} +``` + +Bash ツールで実行し、diff の内容を確認する。 + +### 2. 既存画面仕様の読み込み + +`{{EXISTING_SCREEN_SPEC_PATH}}` を Read で読み込み、現在の画面仕様の内容を把握する。 + +### 3. 変更内容の分類 + +diff の変更を以下のカテゴリに分類する: + +#### 3a. 画面項目の変更 +- フォーム要素の追加/削除/変更(input, select, textarea, button, link) +- 表示要素の追加/削除(テーブル、リスト、見出し等) +- 属性の変更(name, type, required, placeholder 等) + +#### 3b. バリデーションの変更 +- バリデーションルールの追加/削除/変更 +- エラーメッセージの変更 +- HTML5属性の変更(required, pattern, min, max 等) + +#### 3c. インタラクションの変更 +- イベントハンドラーの追加/削除/変更 +- API 呼び出し先の変更 +- 画面遷移先の変更 +- モーダル/ダイアログの追加/削除 + +#### 3d. 状態の変更 +- 状態管理の追加/削除 +- 状態遷移条件の変更 +- ローディング/エラー表示の変更 + +#### 3e. related_files の変更 +- 新しい import/include の追加 +- 既存 import の削除 +- ファイルパスの変更(リネーム等) + +### 4. 影響度の判定 + +各変更について影響度を判定する: + +| 影響度 | 基準 | +|-------|------| +| HIGH | 画面項目の追加/削除、バリデーションルールの変更、インタラクションの追加/削除 | +| MEDIUM | 既存項目の属性変更、エラーメッセージの変更、状態管理の変更 | +| LOW | コメント変更、リファクタリング(機能変更なし)、import順序の変更 | + +### 5. 変更されたソースの現在の状態の確認 + +diff だけでなく、変更後のソースファイルの現在の状態も Read で確認し、更新後の正しい仕様を把握する。 + +## 出力 + +分析結果を以下の構成で `{{TMP_DIR}}/diff-{{SCREEN_ID}}.md` に Write する: + +```markdown +# 差分分析結果: {{SCREEN_ID}} + +## 変更概要 + +- 前回同期: {{LAST_SYNCED_COMMIT}} +- 変更ファイル数: N +- 影響セクション: <セクション名一覧> + +## 変更ファイル一覧 + +| ファイル | 変更種別 | 影響セクション | +|---------|---------|-------------| +| src/pages/login.tsx | 修正 | 画面項目, インタラクション | +| src/api/auth.ts | 修正 | バリデーション | + +## セクション別変更詳細 + +### 画面項目の変更 + +| 変更種別 | 項目名 | 変更前 | 変更後 | 影響度 | +|---------|--------|--------|--------|--------| +| 追加 | 二要素認証コード | - | text input, 必須 | HIGH | +| 変更 | パスワード | minlength=6 | minlength=8 | MEDIUM | + +### バリデーションの変更 + +| 変更種別 | 項目 | ルール | 変更前 | 変更後 | 影響度 | +|---------|------|--------|--------|--------|--------| +| 変更 | パスワード | 最低文字数 | 6文字以上 | 8文字以上 | HIGH | +| 追加 | パスワード | 英数字混在 | - | 英字と数字を含むこと | HIGH | + +### インタラクションの変更 + +| 変更種別 | インタラクション名 | 変更内容 | 影響度 | +|---------|----------------|---------|--------| +| 追加 | 二要素認証 | ログイン後に認証コード入力画面を表示 | HIGH | + +### 状態の変更 + +| 変更種別 | 状態名 | 変更内容 | 影響度 | +|---------|--------|---------|--------| +| 追加 | 二要素認証待ち | 認証コード入力待ち状態を追加 | HIGH | + +### related_files の変更 + +| 変更種別 | ファイルパス | 理由 | +|---------|------------|------| +| 追加 | src/components/TwoFactorForm.tsx | 新規インポート | + +## 更新アクション + +以下のアクションで画面仕様を更新する: + +1. 画面項目テーブルに「二要素認証コード」行を追加 +2. バリデーションテーブルの「パスワード」ルールを更新 +3. インタラクションに「二要素認証」セクションを追加 +4. 状態テーブルに「二要素認証待ち」行を追加 +5. related_files に `src/components/TwoFactorForm.tsx` を追加 +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 分析完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/diff-{{SCREEN_ID}}.md (N行) + 影響セクション: <セクション名一覧> + 影響度: <最大影響度> + DIFF_ANALYZE_SUCCESS + ``` +- 分析失敗時: 理由と共に `DIFF_ANALYZE_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/diff-update-prompt-template.md b/skills/dev-screen-spec/references/diff-update-prompt-template.md new file mode 100644 index 0000000..48bae33 --- /dev/null +++ b/skills/dev-screen-spec/references/diff-update-prompt-template.md @@ -0,0 +1,127 @@ +# 差分更新 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは画面仕様ドキュメントの更新担当です。差分分析結果に基づいて、既存の画面仕様ファイルの該当セクションのみを更新してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 結果として返すのは**マーカー+ファイルパス+行数のみ**(更新内容は返さない) +- **差分更新ではソースコードの変更のみを反映する**(仕様変更の推測はしない) + +## 更新パラメータ + +- **画面ID**: {{SCREEN_ID}} + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から更新してください: + +### 差分分析結果(Phase 2 の出力) + +{{DIFF_SUMMARY_PATH}} + +### 既存の画面仕様ファイル + +{{EXISTING_SCREEN_SPEC_PATH}} + +### 画面仕様フォーマット定義 + +{{SCREEN_SPEC_FORMAT_PATH}} + +## 更新タスク + +### 1. 差分分析結果の読み込み + +`{{DIFF_SUMMARY_PATH}}` を Read し、更新アクションの一覧を確認する。 + +### 2. 既存画面仕様の読み込み + +`{{EXISTING_SCREEN_SPEC_PATH}}` を Read し、現在の画面仕様の全内容を把握する。 + +### 3. フォーマット定義の確認 + +`{{SCREEN_SPEC_FORMAT_PATH}}` を Read し、出力フォーマットを確認する。 + +### 4. セクション別の更新 + +差分分析結果の「更新アクション」に従い、該当セクションのみを更新する。 + +#### 更新ルール + +1. **画面項目テーブル**: + - 行の追加: 既存テーブルの末尾に追加し、# を振り直す + - 行の削除: 該当行を削除し、# を振り直す + - 行の変更: 該当行の値を更新する + +2. **バリデーションテーブル**: + - ルールの追加: 該当項目の直後に新しい行を追加する + - ルールの変更: 該当行の値を更新する + - ルールの削除: 該当行を削除する + - エラーメッセージの変更: 該当行のメッセージを更新する + +3. **インタラクション**: + - インタラクションの追加: 新しい `###` 見出しセクションを追加する + - インタラクションの変更: 該当セクションの内容を更新する + - インタラクションの削除: 該当 `###` セクション全体を削除する + +4. **状態テーブル**: + - 行の追加/変更/削除: 画面項目テーブルと同様のルール + +5. **related_files**: + - frontmatter の `related_files` リストを更新する + +6. **frontmatter の更新**: + - `last_synced_commit` は `` に設定する(メインエージェントが後で更新) + - `updated_at` は `` に設定する(メインエージェントが後で更新) + - その他のフィールド(screen_id, screen_name, path, auth_required)は変更しない + +### 5. 信号機の付与 + +更新した項目に信号機を付与する: + +- 🔵: 変更後のソースコードから直接読み取れた情報 +- 🟡: 変更後のソースコードから推測した情報 +- 🔴: ソースに根拠がなく AI が推論で追加した情報 + +既存項目の信号機は変更しない(更新対象の項目のみ新しい信号機を付与する)。 + +### 6. 整合性チェック + +更新後の画面仕様ファイル全体の整合性を確認する: + +- 画面項目テーブルの # が連番になっているか +- バリデーションテーブルの項目名が画面項目テーブルに存在するか +- インタラクションで参照している項目名が画面項目テーブルに存在するか + +## ファイル出力 + +1. Write ツールで既存ファイルを上書き更新する + - 出力先: `{{EXISTING_SCREEN_SPEC_PATH}}` + +2. **変更しなかったセクションはそのまま保持する**(影響のないセクションは一切変更しない) + +## 結果マーカー + +**更新内容やファイルの中身は返さないこと。返却するのは以下のみ:** + +- 更新完了時: + ``` + 更新完了: {{EXISTING_SCREEN_SPEC_PATH}} (N行) + 更新セクション: <更新したセクション名一覧> + 信号機サマリー: 🔵 N / 🟡 N / 🔴 N(更新項目のみ) + 🔴項目: + - <セクション>: <項目名>(あれば列挙、なければ「なし」) + UPDATE_SCREEN_SPEC_SUCCESS + ``` +- 更新失敗時: 理由と共に `UPDATE_SCREEN_SPEC_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/explore-pages-prompt-template.md b/skills/dev-screen-spec/references/explore-pages-prompt-template.md new file mode 100644 index 0000000..3483045 --- /dev/null +++ b/skills/dev-screen-spec/references/explore-pages-prompt-template.md @@ -0,0 +1,150 @@ +# ページコンポーネント探索 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web アプリケーションの画面構造アナリストです。プロジェクトのページコンポーネント/テンプレートファイルを探索し、画面単位のファイル一覧と各画面の概要情報を抽出してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から調査してください: + +### プロジェクトコンテキスト + +{{CONTEXT_MD_PATH}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 調査タスク + +### 1. ページファイルの検出 + +context.md の技術スタック情報に基づいて、ページ/画面を構成するファイルを探索する: + +| フレームワーク | 探索パターン | +|-------------|------------| +| React | `src/pages/**/*.tsx`, `src/views/**/*.tsx`, `src/routes/**/*.tsx` | +| Next.js (App Router) | `app/**/page.tsx`, `app/**/page.jsx` | +| Next.js (Pages Router) | `pages/**/*.tsx`, `pages/**/*.jsx` | +| Vue | `src/views/**/*.vue`, `src/pages/**/*.vue` | +| Nuxt.js | `pages/**/*.vue` | +| Go + templ | `**/*.templ`, `templates/**/*.html` | +| Go + html/template | `templates/**/*.html`, `views/**/*.html` | +| Express + EJS/Pug | `views/**/*.ejs`, `views/**/*.pug` | +| Django | `**/templates/**/*.html` | +| Ruby on Rails | `app/views/**/*.html.erb` | + +Glob で上記パターンを検索し、該当ファイル一覧を取得する。 + +### 2. ページコンポーネントの分析 + +検出したページファイルごとに以下を調査する(Read で読み込む): + +#### 2a. 画面の基本情報 +- ファイルパス +- エクスポート名/コンポーネント名 +- 画面タイトル(``, `<h1>`, `document.title` 等から推定) + +#### 2b. 使用している子コンポーネント/パーシャル +- import 文から子コンポーネントのパスを抽出 +- テンプレートの include/partial 呼び出しを検出 +- フォームコンポーネント、テーブルコンポーネント等の利用を検出 + +#### 2c. フォームの検出 +- `<form>` 要素の存在 +- フォームライブラリの使用(React Hook Form, Formik, VeeValidate 等) +- 入力フィールドの一覧(name, type, required) + +#### 2d. ページ間リンクの検出 +- `<a href>`, `<Link to>`, `router.push`, `navigate` 等の遷移先パス +- ナビゲーションコンポーネントの使用 + +### 3. 共有レイアウト/コンポーネントの検出 + +複数ページで共有されるレイアウトやナビゲーションを検出する: + +- レイアウトコンポーネント(`Layout`, `AppShell`, `MainLayout` 等) +- ヘッダー/フッター/サイドバー +- ナビゲーションメニュー(メニュー項目=遷移先画面の手がかり) + +### 4. 関連ファイルの特定 + +各ページに関連するファイルを import/include 関係から辿る: + +- API 呼び出しモジュール +- バリデーションスキーマ +- 型定義ファイル +- ユーティリティ関数 + +## 出力 + +上記の調査結果を以下のセクション構成で `{{TMP_DIR}}/explore-pages.md` に Write する: + +```markdown +# ページコンポーネント探索結果 + +## 検出フレームワーク + +- 種別: <フレームワーク名> +- ページディレクトリ: <パス> + +## ページ一覧 + +### <推定画面名> (<ファイルパス>) + +- コンポーネント名: <名前> +- 推定画面タイトル: <タイトル> +- フォーム: あり/なし + - フォーム名: <name/id> + - フィールド数: N +- 子コンポーネント: + - <コンポーネント名> (<ファイルパス>) + - <コンポーネント名> (<ファイルパス>) +- ページ間リンク: + - <遷移先パス> (<リンクテキスト>) +- 関連ファイル: + - <ファイルパス> (<役割: API/バリデーション/型定義等>) + +### <推定画面名> (<ファイルパス>) +... + +## 共有レイアウト + +### <レイアウト名> (<ファイルパス>) +- 使用ページ: <一覧> +- ナビゲーション項目: + - <テキスト> → <パス> + +## ページ間遷移マップ + +以下のページ間遷移が検出された: +- <画面A> → <画面B> (リンクテキスト: <テキスト>) +- <画面A> → <画面C> (router.push) +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 調査完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/explore-pages.md (N行) + EXPLORE_PAGES_SUCCESS + ``` +- 調査失敗時(ページファイルが見つからない等): 理由と共に `EXPLORE_PAGES_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/explore-routes-prompt-template.md b/skills/dev-screen-spec/references/explore-routes-prompt-template.md new file mode 100644 index 0000000..af294a4 --- /dev/null +++ b/skills/dev-screen-spec/references/explore-routes-prompt-template.md @@ -0,0 +1,128 @@ +# ルーティング探索 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web アプリケーションのルーティング構造アナリストです。プロジェクトのルーティング定義を探索し、URL パスとハンドラーのマッピングを抽出してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から調査してください: + +### プロジェクトコンテキスト + +{{CONTEXT_MD_PATH}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 調査タスク + +### 1. フレームワーク検出 + +context.md の技術スタック情報から、使用されているフレームワークを特定し、適切な探索戦略を選択する: + +| フレームワーク | 探索対象 | +|-------------|---------| +| React Router | `routes.tsx`, `App.tsx`, `createBrowserRouter`, `<Route` | +| Next.js (App Router) | `app/` ディレクトリ構造(`page.tsx`, `layout.tsx`) | +| Next.js (Pages Router) | `pages/` ディレクトリ構造 | +| Vue Router | `router/index.ts`, `routes` 配列 | +| Nuxt.js | `pages/` ディレクトリ構造 | +| Go (net/http) | `HandleFunc`, `Handle`, `http.ServeMux` | +| Go (Echo) | `e.GET`, `e.POST`, `e.Group` | +| Go (Gin) | `r.GET`, `r.POST`, `r.Group` | +| Go (Chi) | `r.Get`, `r.Post`, `r.Route` | +| Express.js | `app.get`, `app.post`, `router.get` | +| FastAPI | `@app.get`, `@app.post`, `@router.get` | +| Django | `urlpatterns`, `path()`, `re_path()` | +| Ruby on Rails | `config/routes.rb`, `resources`, `get`, `post` | + +### 2. ルーティング定義の探索 + +フレームワークに応じた方法でルーティング定義を探索する: + +1. Grep でルーティング関連のキーワードを検索する +2. 見つかったファイルを Read で読み込む +3. 各ルートについて以下を抽出する: + - HTTP メソッド(GET, POST, PUT, DELETE 等) + - URL パス(パスパラメータ含む) + - ハンドラー関数/コンポーネント名 + - ミドルウェア(認証ガード等) + +### 3. 認証・認可の検出 + +ルーティング定義から認証・認可に関する情報を抽出する: + +- 認証ミドルウェア/ガードの存在(`auth`, `protected`, `requireAuth`, `middleware` 等で Grep) +- パブリックルートと保護ルートの区別 +- ロールベースのアクセス制御 + +### 4. ルートグループの検出 + +ルートのグルーピング・ネスト構造を検出する: + +- プレフィックス付きグループ(`/api/v1/`, `/admin/` 等) +- レイアウト共有グループ +- ネストされたルーティング + +## 出力 + +上記の調査結果を以下のセクション構成で `{{TMP_DIR}}/explore-routes.md` に Write する: + +```markdown +# ルーティング探索結果 + +## フレームワーク + +- 種別: <フレームワーク名> +- ルーティング方式: <ファイルベース / 設定ベース / コードベース> +- ルーティング定義ファイル: <ファイルパス> + +## ルート一覧 + +| メソッド | パス | ハンドラー/コンポーネント | 認証 | グループ | ソースファイル | +|---------|------|----------------------|------|---------|-------------| +| GET | /login | LoginPage | 不要 | - | src/pages/login.tsx | +| POST | /api/login | handleLogin | 不要 | api | src/api/auth.ts | +| GET | /dashboard | DashboardPage | 必要 | - | src/pages/dashboard.tsx | + +## 認証構造 + +- 認証ミドルウェア: <ファイルパス・関数名> +- 公開ルート: <一覧> +- 保護ルート: <一覧> + +## ルートグループ + +### <グループ名> +- プレフィックス: <パス> +- ミドルウェア: <適用されるミドルウェア> +- 含まれるルート: <一覧> +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 調査完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/explore-routes.md (N行) + EXPLORE_ROUTES_SUCCESS + ``` +- 調査失敗時(ルーティング定義が見つからない等): 理由と共に `EXPLORE_ROUTES_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/from-plan-analyze-prompt-template.md b/skills/dev-screen-spec/references/from-plan-analyze-prompt-template.md new file mode 100644 index 0000000..c525bec --- /dev/null +++ b/skills/dev-screen-spec/references/from-plan-analyze-prompt-template.md @@ -0,0 +1,165 @@ +# from-plan 画面構成分析 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは受け入れ条件(Acceptance Criteria)から画面構成を分析するアナリストです。AC と plan.md を読み込み、画面一覧・各画面の要件・グループ案を中間ファイルに出力してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から分析してください: + +### 受け入れ条件(必須) + +{{ACCEPTANCE_CRITERIA_PATH}} + +### Plan 概要 + +{{PLAN_MD_PATH}} + +(「なし」の場合はスキップする) + +### 既存の画面一覧(追加モード時) + +{{EXISTING_INDEX_PATH}} + +(「なし」の場合は新規作成として扱う) + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 分析タスク + +### 1. 画面の特定 + +AC の Given/When/Then から画面を特定する: + +- **Given** 句: 前提となる画面・状態(「ログイン画面が表示されている」→ ログイン画面) +- **When** 句: ユーザー操作が行われる画面(「登録ボタンをクリックする」→ 登録画面) +- **Then** 句: 結果が確認される画面(「ダッシュボードに遷移する」→ ダッシュボード画面) +- plan.md がある場合は画面構成の記述も参照する + +特定の指針: +- URL パスが異なれば別画面とする +- モーダルやダイアログは親画面のインタラクションとして扱う(別画面にしない) +- 同一 URL でも状態によって大きく異なる表示がある場合は、画面の「状態」セクションで管理する + +### 2. 各画面の要件抽出 + +特定した画面ごとに、AC から以下を抽出する: + +#### 画面項目 +- AC に登場するフォーム要素(入力フィールド、ボタン、リンク等) +- 表示要素(テーブル、リスト、ラベル等) + +#### バリデーション +- AC に記載されたバリデーションルール +- エラーメッセージ + +#### インタラクション +- ボタン押下、リンククリック等のアクションと結果 +- 画面遷移 +- API 呼び出し後の挙動 + +#### 状態 +- 画面が取りうる状態(初期表示、ローディング、エラー、成功等) + +### 3. 画面遷移フローの分析 + +AC の When/Then から画面間の遷移を特定する: +- 「〜画面に遷移する」「〜にリダイレクトする」等の記述 +- plan.md のフロー記述がある場合はそれも参照 +- 業務的な意味のあるフロー単位でまとめる + +### 4. グループ案の生成 + +画面を業務的な意味のあるグループに分割する: +- URL プレフィックスの共通性(`/users/*` → user-management) +- 業務フロー上の関連性(ログイン + パスワードリセット → auth) +- CRUD 操作の対象(一覧 + 詳細 + 登録 + 編集 → 同グループ) + +### 5. 既存画面一覧との整合 + +既存の `_index.md` がある場合: +- 既存画面と重複する画面がないか確認する +- 重複がある場合は既存画面の screen_id を維持する +- 新規画面のみを追加対象とする +- 既存のグループ構造を尊重する + +## 出力 + +上記の分析結果を以下のセクション構成で `{{TMP_DIR}}/screen-analysis.md` に Write する: + +```markdown +# 画面構成分析結果 + +## 画面一覧 + +| # | 画面ID | 画面名 | パス | 認証 | グループ | 新規/既存 | +|---|--------|--------|------|------|---------|----------| +| 1 | login | ログイン | /login | 不要 | auth | 新規 | +| 2 | dashboard | ダッシュボード | /dashboard | 必要 | main | 新規 | + +## グループ案 + +### <グループ名> +- 画面: <画面ID一覧> +- 説明: <グループの説明> + +## 画面遷移フロー + +### <フロー名> +<画面ID> → <画面ID> +<画面ID> --[アクション名]--> <画面ID> + +## 各画面の要件サマリー + +### <画面ID>: <画面名> + +#### 画面項目 +- <項目名> (<種別>) [必須/任意] + +#### バリデーション +- <項目名>: <ルール> → <エラーメッセージ> + +#### インタラクション +- <アクション> → <結果> + +#### 状態 +- <状態名>: <条件> + +## AC カバレッジ + +### カバーされた AC +- AC-N: <AC タイトル> + +### カバーされていない AC(画面に紐付かない要件) +- AC-N: <AC タイトル>(理由: <API のみ / バッチ処理等>) +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 分析完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/screen-analysis.md (N行) + 画面数: N、グループ数: N + FROM_PLAN_ANALYZE_SUCCESS + ``` +- 分析失敗時: 理由と共に `FROM_PLAN_ANALYZE_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/from-plan-generate-prompt-template.md b/skills/dev-screen-spec/references/from-plan-generate-prompt-template.md new file mode 100644 index 0000000..c11ff91 --- /dev/null +++ b/skills/dev-screen-spec/references/from-plan-generate-prompt-template.md @@ -0,0 +1,169 @@ +# from-plan 画面仕様ファイル生成 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは画面仕様ドキュメントのジェネレーターです。受け入れ条件(AC)と Plan の情報から、グループ内の全画面の画面仕様ファイルを生成してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 出力先: `{{OUTPUT_DIR}}/<screen_id>.md`(グループ内の各画面ごとに1ファイル) +- 結果として返すのは**マーカー+ファイルパス+行数のみ**(生成内容は返さない) + +## 生成パラメータ + +- **担当グループ**: {{GROUP_NAME}} +- **元 Plan 名**: {{PLAN_NAME}} + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から生成してください: + +### 画面構成分析結果 + +{{SCREEN_ANALYSIS_PATH}} + +この中から **{{GROUP_NAME}}** グループに属する画面の情報を抽出する。 + +### 受け入れ条件 + +{{ACCEPTANCE_CRITERIA_PATH}} + +### Plan 概要 + +{{PLAN_MD_PATH}} + +(「なし」の場合はスキップする) + +### 画面仕様フォーマット定義 + +{{SCREEN_SPEC_FORMAT_PATH}} + +## 生成タスク + +### 1. グループ内の画面特定 + +画面構成分析結果から、{{GROUP_NAME}} グループに属する全画面を特定する。 + +### 2. 各画面の画面仕様ファイル生成 + +グループ内の各画面について、以下の手順で画面仕様ファイルを生成する: + +#### 2a. AC からの情報抽出 + +画面構成分析結果の「各画面の要件サマリー」を参照し、AC の原文も確認して詳細を補完する: + +- **画面項目**: AC に登場するフォーム要素、表示要素を列挙する + - AC に明示されていないが一般的に必要な要素(戻るボタン、ページタイトル等)は 🔴 で追加可能 +- **バリデーション**: AC に記載されたバリデーションルールとエラーメッセージ + - AC に記載のないバリデーション(必須チェック等)は 🟡 で追加 +- **インタラクション**: AC の When/Then から画面操作と結果を抽出 +- **状態**: AC から読み取れる画面の状態遷移 + +#### 2b. 信号機の付与 + +from-plan モードでの信号機基準: + +| 信号 | 基準 | +|------|------| +| 🔵 | AC に明示的に記載されている項目・ルール・操作 | +| 🟡 | plan.md の記述から推測した項目、AC に暗示されているが明示はされていない項目 | +| 🔴 | AC にも plan.md にも根拠がなく、一般的な Web アプリとして必要と判断した項目 | + +#### 2c. ファイル生成 + +フォーマット定義に従い、以下の構成でファイルを生成する: + +##### frontmatter +```yaml +--- +screen_id: <画面ID> +screen_name: <画面名> +path: <URLパス> +auth_required: <true/false> +source: from-plan +source_plan: {{PLAN_NAME}} +last_synced_commit: null +updated_at: <PLACEHOLDER> +related_files: [] +--- +``` + +**注意**: +- `source` は必ず `from-plan` にする +- `source_plan` は `{{PLAN_NAME}}` にする +- `last_synced_commit` は `null` にする(ソースコードとの同期がまだのため) +- `related_files` は空配列にする(ソースコードがまだないため) +- `updated_at` は `<PLACEHOLDER>` で出力する。メインエージェントが後で正しい値に置換する + +##### 本文セクション + +1. **画面概要**: 画面の目的を1-2文で記述 +2. **画面項目**: テーブル形式(# | 項目名 | 種別 | 必須 | 説明) +3. **バリデーション**: テーブル形式(項目 | ルール | エラーメッセージ) + - AC にバリデーション記載がない画面では省略可 +4. **インタラクション**: `###` 見出しで個別のインタラクションを記述 +5. **状態**: テーブル形式(状態 | 条件 | 表示内容の変化) +6. **備考**: 実装時の注意事項や制約(なければ省略可) + +### 3. 信号機の記法 + +各項目に信号機をコメントとして付与する: + +```markdown +| 1 | メールアドレス | text input | Yes | ユーザーのメールアドレス <!-- 🔵 --> | +| 2 | 戻るボタン | button | - | 一覧画面に戻る <!-- 🔴 --> | + +### ログイン成功 <!-- 🔵 --> + +| 初期表示 | ページ読み込み時 | フォームは空、ボタンは活性 <!-- 🟡 --> | +``` + +## ファイル出力 + +1. 出力ディレクトリの確認・作成: + ```bash + mkdir -p "{{OUTPUT_DIR}}" + ``` + +2. グループ内の各画面について Write ツールでファイルを生成する + +3. グループサマリーを `{{OUTPUT_DIR}}/../tmp/screen-spec/group-{{GROUP_NAME}}.md` に Write する: + ※ 実際のパスは `$(git rev-parse --show-toplevel)/tmp/screen-spec/group-{{GROUP_NAME}}.md` + +```markdown +# グループサマリー: {{GROUP_NAME}} + +## 生成ファイル + +| 画面ID | ファイル | 行数 | 🔵 | 🟡 | 🔴 | +|--------|---------|------|-----|-----|-----| +| login | login.md | 45 | 5 | 2 | 1 | + +## 🔴 項目一覧 +- <画面ID> <セクション>: <項目名>(あれば列挙、なければ「なし」) +``` + +## 結果マーカー + +**生成内容やファイルの中身は返さないこと。返却するのは以下のみ:** + +- 生成完了時: + ``` + グループ {{GROUP_NAME}} 生成完了: + - 画面数: N + - 生成ファイル: <ファイルパス一覧> + - グループサマリー: <サマリーファイルパス> (N行) + 信号機サマリー(グループ合計): 🔵 N / 🟡 N / 🔴 N + FROM_PLAN_GENERATE_SUCCESS + ``` +- 生成失敗時: 理由と共に `FROM_PLAN_GENERATE_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/generate-prompt-template.md b/skills/dev-screen-spec/references/generate-prompt-template.md new file mode 100644 index 0000000..f16c7ce --- /dev/null +++ b/skills/dev-screen-spec/references/generate-prompt-template.md @@ -0,0 +1,154 @@ +# 画面仕様ファイル生成 サブエージェント プロンプトテンプレート + +dev-screen-spec がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは画面仕様ドキュメントのジェネレーターです。ソースコードを解析し、画面仕様ファイルを生成してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 出力先: `{{OUTPUT_DIR}}/{{SCREEN_ID}}.md` +- 結果として返すのは**マーカー+ファイルパス+行数のみ**(生成内容は返さない) + +## 生成パラメータ + +- **画面ID**: {{SCREEN_ID}} +- **画面名**: {{SCREEN_NAME}} +- **URLパス**: {{SCREEN_PATH}} +- **認証要否**: {{AUTH_REQUIRED}} + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から生成してください: + +### 画面仕様フォーマット定義 + +{{SCREEN_SPEC_FORMAT_PATH}} + +### プロジェクトコンテキスト + +{{CONTEXT_MD_PATH}} + +### 関連ソースファイル + +以下のファイルを **すべて Read** し、画面の構造を分析してください: + +{{RELATED_FILES}} + +## 生成タスク + +### 1. ソースファイルの分析 + +関連ソースファイルを Read し、以下の情報を抽出する: + +#### 1a. 画面項目の抽出 +- HTML/テンプレートからフォーム要素を検出: `<input>`, `<select>`, `<textarea>`, `<button>`, `<a>` +- 各要素の属性を記録: name, type, required, placeholder, ラベルテキスト +- テーブル、リスト等の表示要素も検出 +- 各項目に信号機を付与: + - 🔵: ソースに明示的に存在する要素 + - 🟡: コード構造から推測した要素(条件分岐内等) + - 🔴: 一般的なWebアプリとして必要と判断した追加要素 + +#### 1b. バリデーションルールの抽出 +- HTML5バリデーション属性: required, pattern, min, max, minlength, maxlength, type +- JavaScript/TypeScript バリデーション: Zod, Yup, Joi, React Hook Form rules, VeeValidate 等 +- サーバーサイドバリデーション: ハンドラー内の入力チェック処理 +- エラーメッセージ文字列の抽出 + +#### 1c. インタラクションの抽出 +- イベントハンドラー: onClick, onSubmit, onChange 等 +- API 呼び出し: fetch, axios, useSWR, useQuery 等 +- 画面遷移: router.push, navigate, redirect, window.location 等 +- モーダル/ダイアログの表示制御 +- 条件付き表示/非表示の切り替え + +#### 1d. 状態の抽出 +- useState, useReducer, store 等の状態管理 +- ローディング状態の管理 +- エラー状態の管理 +- フォーム送信状態の管理 + +### 2. import/include 関係の追跡 + +関連ソースファイルから import/include されているファイルも必要に応じて Read し、情報を補完する: + +- API クライアントモジュール → API エンドポイントとレスポンス構造 +- バリデーションスキーマ → バリデーションルールの詳細 +- 型定義 → データ構造 + +ただし、探索の深さは2階層までとする(ページ → 子コンポーネント → 孫コンポーネントまで)。 + +### 3. 画面仕様ファイルの生成 + +フォーマット定義に従い、以下のセクション構成でファイルを生成する: + +#### frontmatter +```yaml +--- +screen_id: {{SCREEN_ID}} +screen_name: {{SCREEN_NAME}} +path: {{SCREEN_PATH}} +auth_required: {{AUTH_REQUIRED}} +last_synced_commit: <PLACEHOLDER> +updated_at: <PLACEHOLDER> +related_files: + - <実際に読み込んだファイルパス一覧> +--- +``` + +**注意**: `last_synced_commit` と `updated_at` は `<PLACEHOLDER>` で出力する。メインエージェントが後で正しい値に置換する。 + +#### 本文セクション + +1. **画面概要**: 画面の目的を1-2文で記述 +2. **画面項目**: テーブル形式で項目一覧(# | 項目名 | 種別 | 必須 | 説明) +3. **バリデーション**: テーブル形式でルール一覧(項目 | ルール | エラーメッセージ) + - バリデーションが存在しない画面(一覧表示のみ等)ではセクションを省略する +4. **インタラクション**: `###` 見出しで個別のインタラクションを記述 +5. **状態**: テーブル形式で状態一覧(状態 | 条件 | 表示内容の変化) +6. **備考**: その他の注意事項(なければ省略可) + +### 4. 信号機の付与 + +各項目に信号機をコメントとして付与する: + +```markdown +| 1 | メールアドレス | text input | Yes | ユーザーのメールアドレス <!-- 🔵 --> | + +### ログイン成功 <!-- 🔵 --> + +| 初期表示 | ページ読み込み時 | フォームは空、ボタンは活性 <!-- 🟡 --> | +``` + +## ファイル出力 + +1. 出力ディレクトリの確認・作成: + ```bash + mkdir -p "{{OUTPUT_DIR}}" + ``` + +2. Write ツールでファイルを生成する + +## 結果マーカー + +**生成内容やファイルの中身は返さないこと。返却するのは以下のみ:** + +- 生成完了時: + ``` + 生成完了: {{OUTPUT_DIR}}/{{SCREEN_ID}}.md (N行) + 信号機サマリー: 🔵 N / 🟡 N / 🔴 N + 🔴項目: + - <セクション>: <項目名>(あれば列挙、なければ「なし」) + GENERATE_SCREEN_SPEC_SUCCESS + ``` +- 生成失敗時: 理由と共に `GENERATE_SCREEN_SPEC_FAILED` を出力する diff --git a/skills/dev-screen-spec/references/screen-spec-format.md b/skills/dev-screen-spec/references/screen-spec-format.md new file mode 100644 index 0000000..215c81e --- /dev/null +++ b/skills/dev-screen-spec/references/screen-spec-format.md @@ -0,0 +1,223 @@ +# 画面仕様ドキュメント 出力フォーマット定義 + +サブエージェントが画面仕様ファイルを生成・更新する際に準拠するフォーマット定義。 + +## 配置 + +``` +docs/dev/screen-specs/ +├── _index.md # 画面一覧とルーティング +├── login.md +├── dashboard.md +├── user-settings.md +└── ... +``` + +--- + +## _index.md(画面一覧) + +### frontmatter + +```yaml +--- +last_synced_commit: abc1234 +updated_at: "2026-03-09" +groups: + - name: auth + screens: [login, forgot-password] + - name: user-management + screens: [user-list, user-detail, user-create] + - name: settings + screens: [user-settings] +--- +``` + +| フィールド | 型 | 説明 | +|-----------|-----|------| +| `last_synced_commit` | string | dev-screen-spec 最終同期時の commit hash(短縮形) | +| `updated_at` | string | 最終更新日(YYYY-MM-DD) | +| `groups` | object[] | 画面のグループ分割。各グループに name と screens(画面ID配列)を持つ | + +### 本文構造 + +```markdown +# 画面一覧 + +| 画面ID | 画面名 | パス | 認証 | 備考 | +|--------|--------|------|------|------| +| login | ログイン | /login | 不要 | | +| dashboard | ダッシュボード | /dashboard | 必要 | | +| user-list | ユーザー一覧 | /users | 必要 | | +| user-detail | ユーザー詳細 | /users/:id | 必要 | | + +## 画面遷移フロー + +### 認証フロー +login → dashboard + +### ユーザー管理 CRUD フロー +user-list → user-create → user-list +user-list → user-detail → user-list + +### ユーザー登録→確認フロー +user-create --[登録ボタン]--> user-detail --[一覧に戻る]--> user-list + +### グローバルナビゲーション +dashboard → user-list +dashboard → user-settings +user-list → dashboard +user-settings → dashboard + +## 到達不能画面チェック +<!-- dev-screen-spec が自動生成: 全画面がいずれかのフローに含まれているか検証 --> +- ⚠️ なし(全画面に到達経路あり) +``` + +### 画面遷移フロー記法 + +``` +<画面ID> → <画面ID> # 単純遷移 +<画面ID> --[アクション名]--> <画面ID> # アクション付き遷移 +<画面ID> → <画面ID> → <画面ID> # 連続遷移 +``` + +- 各フローに名前をつけて `###` 見出しで管理する +- 業務的な意味のあるフロー単位でまとめる(CRUD、認証、特定業務フローなど) +- 全画面がいずれかのフローに含まれていることを「到達不能画面チェック」で検証する +- 到達不能画面があれば `⚠️ <画面ID>: いずれの遷移フローにも含まれていません` で警告する + +--- + +## 個別画面ファイル + +### frontmatter + +```yaml +--- +screen_id: login +screen_name: ログイン +path: /login +auth_required: false +source: from-source +source_plan: null +last_synced_commit: abc1234 +updated_at: "2026-03-09" +related_files: + - src/pages/login.tsx + - src/components/LoginForm.tsx + - src/api/auth.ts +--- +``` + +| フィールド | 型 | 説明 | +|-----------|-----|------| +| `screen_id` | string | 画面の一意ID(ケバブケース) | +| `screen_name` | string | 画面の日本語名 | +| `path` | string | URLパス | +| `auth_required` | boolean | 認証が必要か | +| `source` | string | 生成元。`from-source`(ソースコードから生成)または `from-plan`(受け入れ条件から生成) | +| `source_plan` | string/null | from-plan の場合の元 plan 名。from-source の場合は null | +| `last_synced_commit` | string/null | この画面を最後に同期した commit hash(短縮形)。from-plan で未同期の場合は null | +| `updated_at` | string | 最終更新日(YYYY-MM-DD) | +| `related_files` | string[] | この画面に関連するソースファイルのパス。from-plan で未同期の場合は空配列 | + +### 本文構造 + +```markdown +# <画面名> + +<画面の概要(1-2文)> + +## 画面項目 + +| # | 項目名 | 種別 | 必須 | 説明 | +|---|--------|------|------|------| +| 1 | メールアドレス | text input | Yes | ユーザーのメールアドレス | +| 2 | パスワード | password input | Yes | 8文字以上 | +| 3 | ログインボタン | button | - | フォーム送信 | +| 4 | パスワードを忘れた方 | link | - | /forgot-password へ遷移 | + +## バリデーション + +| 項目 | ルール | エラーメッセージ | +|------|--------|-----------------| +| メールアドレス | 必須 | メールアドレスを入力してください | +| メールアドレス | メール形式 | 正しいメールアドレスを入力してください | +| パスワード | 必須 | パスワードを入力してください | +| パスワード | 8文字以上 | パスワードは8文字以上で入力してください | + +## インタラクション + +### ログイン成功 +- ログインボタン押下 → API呼び出し → /dashboard へリダイレクト + +### ログイン失敗 +- ログインボタン押下 → API呼び出し → エラーメッセージ「メールアドレスまたはパスワードが正しくありません」を表示 + +### パスワード表示切替 +- パスワードフィールドの目アイコン押下 → パスワードの表示/非表示が切り替わる + +## 状態 + +| 状態 | 条件 | 表示内容の変化 | +|------|------|---------------| +| 初期表示 | ページ読み込み時 | フォームは空、ボタンは活性 | +| 送信中 | APIリクエスト中 | ボタン非活性、ローディング表示 | +| エラー | API 401応答 | エラーメッセージ表示 | + +## 備考 + +- ソーシャルログイン(Google, GitHub)は Phase 2 で追加予定 +``` + +--- + +## 信号機の付与ルール + +各セクションの項目に信号機を付与する。信号機はテーブルの備考欄やインタラクション見出しの末尾にコメントとして記載する。 + +```markdown +| 1 | メールアドレス | text input | Yes | ユーザーのメールアドレス <!-- 🔵 --> | + +### ログイン成功 <!-- 🔵 --> + +| 初期表示 | ページ読み込み時 | フォームは空、ボタンは活性 <!-- 🟡 --> | +``` + +| 信号 | 基準 | +|------|------| +| 🔵 | ソースコードから直接読み取れた情報(HTML要素、バリデーション属性、ルーティング定義、エラーメッセージ文字列等) | +| 🟡 | ソースコードから推測した情報(コンポーネント名からの推定、コードの制御フローからの推論等) | +| 🔴 | AI推論補完(ソースに明示されていないが一般的なWebアプリとして必要と判断した項目) | + +--- + +## セクションの独立性 + +各セクションは独立しており、差分更新時に特定セクションだけを更新可能: + +- **画面項目** → webtest の要素確認シナリオ +- **バリデーション** → webtest のフォームバリデーション確認 +- **インタラクション** → webtest のテストシナリオ(手順+期待結果) +- **状態** → webtest の状態遷移テスト + +## related_files による変更検知 + +- git diff の変更ファイル一覧と `related_files` を突き合わせることで、影響のある画面を高速に特定できる +- LLM に全 diff を読ませる必要がなく、トークン消費を抑えられる +- import/include 関係を辿って related_files を特定する(手動メンテ不要) + +## from-plan モードによる設計先行 + +- 新規開発時は受け入れ条件(AC + plan.md)から画面仕様を先に生成し、レビュー後に実装に進む +- 実装後の `dev-screen-spec update` でソースコードと同期する際、from-plan の内容と実装の差分をユーザーが解決する +- 画面仕様が「設計書」(from-plan)と「実装の翻訳」(from-source)の両方の役割を果たす +- from-plan で生成された画面は `source: from-plan`, `last_synced_commit: null`, `related_files: []` で識別可能 + +## グループによる大規模プロジェクト対応 + +- 画面をグループ単位(業務ドメイン、URL プレフィックス等)に分割して管理する +- `_index.md` の frontmatter にグループ情報を記録し、バッチ処理・差分更新の単位として使用する +- コンテキスト肥大化を防ぐため、サブエージェントはグループ単位で起動する(1サブエージェント = 1グループ内の全画面) +- グループ分割はスキル実行時に自動提案し、AskUserQuestion でユーザーが確認・調整する diff --git a/skills/dev-verify/SKILL.md b/skills/dev-verify/SKILL.md new file mode 100644 index 0000000..d497719 --- /dev/null +++ b/skills/dev-verify/SKILL.md @@ -0,0 +1,162 @@ +--- +name: dev-verify +description: This skill should be used when the user asks to "dev-verify", "実装の検証", "完了チェック", "verify implementation", "全テスト実行", "run all tests", "dev-verify auth". Plan単位で全タスクの完了状態とテスト・ビルド・Lintの整合性を検証し、レポートを出力する。 +argument-hint: '<plan-name>' +--- + +# Dev Verify + +Plan単位ですべてのタスクの完了状態を確認し、全テスト実行・ビルド・Lint・ファイルサイズチェックを行い、検証レポートを `docs/dev/plans/<plan-name>/reports/` に出力する。 + +## 前提知識 + +### dev-*スキルフロー内の位置 + +``` +dev-context → dev-plan → dev-impl → [dev-verify] + ↘ dev-debug +``` + +### 引数フォーマット + +``` +/dev-verify <plan-name> +``` + +## ワークフロー + +### Step 1: タスク完了チェック + +`docs/dev/plans/<plan-name>/tasks/` 内の全タスクファイルを読み込み、フロントマターの `status` を確認する。 + +- すべて `done` → Step 2 へ進む +- `pending` / `in_progress` のタスクがある → ユーザーに未完了タスクの一覧を報告し、続行するか確認する(AskUserQuestion) + +### Step 2: 全テスト実行 + +`docs/dev/context.md` からテスト実行コマンドを取得し、全テストを実行する。 + +```bash +# context.md の Test Framework セクションからコマンドを取得 +<test-command> +``` + +テスト結果を記録する: passed / failed / skipped の件数。 + +### Step 3: カバレッジチェック + +`docs/dev/context.md` の Test Framework セクションから Coverage Command と Coverage Threshold を取得し、プロジェクト全体のカバレッジを計測する。 + +1. Coverage Command でプロジェクト全体のカバレッジを計測する +2. パッケージごとにカバレッジ率を抽出し、閾値と比較する +3. `[no test files]` は 0% として扱う +4. 閾値未達のパッケージは Issues Found に記録する + +### Step 4: ビルド確認 + +コンパイル言語やビルドステップがある場合、ビルドコマンドを実行する(context.md から取得)。 + +インタープリタ言語でビルドステップがない場合はスキップする。 + +### Step 5: Lint実行 + +context.md に Lint コマンドが記載されている場合、実行する。記載がない場合はスキップする。 + +### Step 6: ファイルサイズチェック(500行ルール) + +Planで変更・作成されたファイル(各タスクファイルの Files セクションから収集)の行数を確認する(絶対パスを使用): + +```bash +wc -l "$(git rev-parse --show-toplevel)/<ファイルの相対パス>" +``` + +500行を超えるファイルがあれば警告として記録する。 + +### Step 7: 信号機サマリー + +Plan内の全タスクの確信度レポートを集約する: + +- 🟡 妥当な推測の項目一覧(ユーザー確認推奨) +- 🔴 AI推論補完の項目一覧(人間の確認必須) + +🔴 が残っている場合は明確に警告する。 + +### Step 8: レポート出力 + +検証結果を `docs/dev/plans/<plan-name>/reports/verify-YYYY-MM-DD.md` に出力する。 + +```markdown +# Verification Report - YYYY-MM-DD +## Plan: <plan-name> + +## Summary + +| Item | Result | +|------|--------| +| Tasks | X/Y completed | +| Tests | Z passed, W failed, V skipped | +| Coverage | X/Y packages above threshold (threshold: 80%) | +| Build | OK / NG / N/A | +| Lint | OK / NG / N/A | +| 500-line rule | OK / X files over limit | + +## Task Status + +| ID | Title | Status | +|----|-------|--------| +| 001 | ... | done | +| 002 | ... | done | + +## Test Results + +[テスト実行の出力サマリー] +[失敗テストがある場合は詳細] + +## Coverage Results + +| パッケージ | カバレッジ | 閾値 | 結果 | +|-----------|----------|------|------| +| internal/handler | XX.X% | 80% | OK / NG | + +[閾値未達パッケージの詳細(ある場合)] + +## File Size Check + +[500行超過ファイルの一覧(ある場合)] + +## Confidence Summary + +### 🟡 妥当な推測(要確認) +- [ファイル](パス) — [確認すべき点] + +### 🔴 AI推論補完(人間の確認必須) +- [ファイル](パス) — [判断が必要な理由] + +## Issues Found + +[検出された問題の詳細] + +## Recommendations + +[問題がある場合の次アクション提案] +- テスト失敗 → `/dev-debug` の使用を推奨 +- 500行超過 → `/dev-impl` のリファクタリングを推奨 +- 🔴 残存 → 該当ファイルの人間レビューを推奨 +``` + +### Step 9: Docker クリーンアップ + +プロジェクトルートに `docker-compose.yml` または `docker-compose.yaml` が存在するか確認する。存在する場合: + +1. `docker compose down` を実行してコンテナを停止する +2. 停止に失敗した場合はユーザーに報告する(ブロッキングにしない) + +## ルール・制約 + +- context.md が存在しない場合、テスト・ビルド・Lintコマンドが不明であることを報告し、可能な範囲で検証する +- テスト失敗がある場合でもレポートは出力する(中断しない) +- レポートファイルが既存の場合は日付が異なれば新規ファイルとして作成し、同日であれば上書きする +- テスト実行はサブエージェントではなく直接 Bash で実行する(結果の全文がレポートに必要) +- カバレッジ閾値未達のパッケージがある場合は VERIFY_ISSUES_FOUND とする +- Lint/ビルドコマンドが context.md にない場合はスキップし、レポートに N/A と記載する +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) diff --git a/skills/dev-webtest-plan/SKILL.md b/skills/dev-webtest-plan/SKILL.md new file mode 100644 index 0000000..3044bd9 --- /dev/null +++ b/skills/dev-webtest-plan/SKILL.md @@ -0,0 +1,548 @@ +--- +name: dev-webtest-plan +description: This skill should be used when the user asks to "dev-webtest-plan", "Webテスト計画を生成", "テスト計画を作成", "webtest plan", "E2Eテスト計画", "画面テスト計画", "generate webtest plan", "create test plan from requirements", "webtest計画を更新", "テスト計画の差分更新", "update webtest plan", "画面仕様からテスト更新". dev-planの出力からPlaywright用のWebテスト計画ファイルを自動生成する。画面仕様の変更差分からテスト計画を更新する差分更新モードも対応。 +argument-hint: '<dev-plan-name> | update [plan-name]' +--- + +# Dev Webtest Plan + +dev-plan の出力(acceptance-criteria.md の Given/When/Then、タスクファイルの Test Strategy 等)から、dev-webtest が実行する Playwright 用 Web テスト計画ファイルを自動生成するスキル。画面仕様ドキュメント(Screen Spec)の変更差分から既存テスト計画を更新する差分更新モードも備える。 + +## 前提知識 + +### dev-* スキルフロー内の位置 + +``` +dev-context → dev-plan → [dev-webtest-plan] → dev-impl → dev-verify → dev-webtest + ↓ ↑ + docs/dev/webtests/plans/*.md ─────────────────────────┘ + +dev-screen-spec → [dev-webtest-plan update] → dev-webtest + ↓ (差分更新) ↑ + docs/dev/webtests/plans/*.md ───────┘ +``` + +### 引数フォーマット + +``` +/dev-webtest-plan <dev-plan-name> # 新規生成モード +/dev-webtest-plan update # 差分更新モード(全webtest計画対象) +/dev-webtest-plan update <plan-name> # 差分更新モード(特定webtest計画のみ) +``` + +- `dev-plan-name`: 既存の Plan 名(`docs/dev/plans/<dev-plan-name>/` が存在すること) +- `update`: 差分更新モードのキーワード +- `plan-name`: 更新対象のwebtest計画名(省略時は全計画を対象) + +### モード自動判定 + +引数で自動判定する(ユーザー質問不要): + +``` +引数が "update" で始まる → 差分更新モード +それ以外 → 新規生成モード(現行通り) +``` + +#### 新規生成モードのサブ判定 + +acceptance-criteria.md の存在で自動判定する: + +| モード | 判定条件 | 特徴 | +|-------|---------|------| +| Full-spec | `docs/dev/plans/<name>/acceptance-criteria.md` が存在 | AC の Given/When/Then から直接変換(🔵 多い) | +| Lightweight | acceptance-criteria.md が存在しない | タスクの Test Strategy から推論(🟡 主体、🔵 なし) | + +#### 差分更新モード + +| モード | 判定条件 | 特徴 | +|-------|---------|------| +| 差分更新 | 引数が `update` で始まる | 画面仕様の変更差分からテスト計画を更新(🟡 source: screen-spec update) | + +### サブエージェント制約(重要) + +サブエージェントは Task ツールを使用できない(ネスト不可のアーキテクチャ制約)。そのため: +- コード探索は Glob/Grep/Read を直接使用する +- TodoWrite は使用しない(TaskCreate/TaskUpdate で進捗管理する) +- サブエージェントに渡すのはファイルパスのみ。サブエージェントが自分で Read する + +### コンテキスト管理戦略 + +メインコンテキストの肥大化を防ぐため、**中間ファイルとパス参照** を使用する: +- メインエージェントはファイルの全文を Read しない(パス存在確認・Grep での部分情報取得のみ) +- サブエージェントに渡すのはファイルパス。サブエージェントが自分で Read する +- Phase 間のデータ受け渡しは中間ファイル経由(`tmp/webtest/plan/<plan-name>/`) +- サブエージェントの返却はマーカー+ファイルパス+行数のみ + +### 中間ファイル(新規生成モード) + +``` +tmp/webtest/plan/<plan-name>/ +├── task-summary.md # Phase 2a で生成(タスクサマリー) +├── explore-plan-result.md # Phase 2a の出力(Plan 分析結果) +├── explore-code-result.md # Phase 2b の出力(UI 要素情報) +└── design-result.md # Phase 3 の出力(構造設計結果) +``` + +### 中間ファイル(差分更新モード) + +``` +tmp/webtest/update/ +└── analyze-<plan-name>.md # Phase 2 の出力(変更分析結果) +``` + +## ワークフロー(新規生成モード) + +> 以下は引数が `update` で始まらない場合のワークフロー。 + +### Phase 1: コンテキスト確認と入力検証(メイン) + +1. `docs/dev/context.md` の存在を確認する。存在しない場合は `/dev-context` の実行を案内して終了する +2. `docs/dev/plans/<dev-plan-name>/` の存在を確認する。存在しない場合は `/dev-plan` の実行を案内して終了する +3. **モード自動判定**: `docs/dev/plans/<dev-plan-name>/acceptance-criteria.md` の存在を確認する + - 存在する → **Full-spec モード** + - 存在しない → **Lightweight モード** +4. Full-spec 時: `acceptance-criteria.md`, `user-stories.md`, `requirements.md` のパスを記録する(Read はしない) +5. `docs/dev/plans/<dev-plan-name>/tasks/` 配下のタスクファイルパス一覧を Glob で取得する(Read はしない) +6. Grep で `status: done` のタスクがあるか確認する(Phase 2b 実行判定用) +7. タスクの Files セクションに記載されたファイルが実際に存在するか Grep + Glob で確認する(Phase 2b 実行判定用) +8. 既存 webtest plan との重複確認: + - `docs/dev/webtests/plans/` 配下を Glob で確認 + - 同一 `source-plan` の webtest plan が存在する場合は AskUserQuestion で上書き確認する +9. 中間ファイルディレクトリを作成する: `mkdir -p tmp/webtest/plan/<plan-name>/` + +### Phase 2: 画面・フロー・API分析(Explore サブエージェント x2 並列) + +**2a. dev-plan 分析**(Explore, haiku)と **2b. 実装コード探索**(Explore, haiku、オプション)を並列で実行する。API セットアップ/クリーンアップに必要なエンドポイント情報も同時に収集する。 + +#### 2a. dev-plan 分析 + +1. `references/explore-plan-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{PLAN_MD_PATH}}` ← plan.md の絶対パス + - `{{ACCEPTANCE_CRITERIA_PATH}}` ← acceptance-criteria.md の絶対パス(Lightweight 時は「なし」) + - `{{TASK_FILE_PATHS}}` ← 全タスクファイルの絶対パス一覧(1行1パス) + - `{{MODE}}` ← "Full-spec" または "Lightweight" + - `{{TMP_DIR}}` ← `tmp/webtest/plan/<plan-name>/` の絶対パス +3. Explore サブエージェント(haiku)を起動する +4. 出力のマーカーを確認する: + - `EXPLORE_PLAN_SUCCESS` → Phase 3 へ進む + - `EXPLORE_PLAN_FAILED` → エラー理由をユーザーに報告して終了 + +#### 2b. 実装コード探索(オプション) + +以下のいずれかの条件を満たす場合のみ実行する: +- タスクファイルに `status: done` が1つ以上存在する +- タスクの Files セクションに記載されたファイルが実際に存在する(Glob で確認) + +条件を満たさない場合はスキップし、Phase 3 で `draft: true` として設計する。 + +**追加探索**: API セットアップ/クリーンアップ用のエンドポイント情報も収集する: +- API仕様ファイルの自動探索(openapi.yaml, swagger.json 等) +- ルーティング定義からのCRUD APIエンドポイント抽出 +- 認証フローの調査(ログインAPI、トークン取得方法) + +1. `references/explore-code-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{CONTEXT_MD_PATH}}` ← context.md の絶対パス + - `{{TARGET_FILES}}` ← タスクの Files セクションから抽出したファイルパス一覧 + - `{{TMP_DIR}}` ← `tmp/webtest/plan/<plan-name>/` の絶対パス +3. Explore サブエージェント(haiku)を起動する +4. 出力のマーカーを確認する: + - `EXPLORE_CODE_SUCCESS` → Phase 3 へ進む + - `EXPLORE_CODE_FAILED` → スキップ、`draft: true` で進行 + +### Phase 3: webtest plan 構造設計(Plan サブエージェント) + +API セットアップ/クリーンアップの設計も含む。Phase 2 の分析結果からAPIエンドポイント情報を活用し、各 webtest plan に実行可能な curl コマンドを設計する。 + +1. `references/design-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{MODE}}` ← "Full-spec" または "Lightweight" + - `{{EXPLORE_PLAN_RESULT_PATH}}` ← `tmp/webtest/plan/<plan-name>/explore-plan-result.md` の絶対パス + - `{{EXPLORE_CODE_RESULT_PATH}}` ← `tmp/webtest/plan/<plan-name>/explore-code-result.md` の絶対パス(スキップ時は「なし」) + - `{{TASK_SUMMARY_PATH}}` ← `tmp/webtest/plan/<plan-name>/task-summary.md` の絶対パス + - `{{WEBTEST_PLAN_FORMAT_PATH}}` ← `references/webtest-plan-format.md` の絶対パス + - `{{TMP_DIR}}` ← `tmp/webtest/plan/<plan-name>/` の絶対パス +3. Plan サブエージェントを起動する +4. 出力のマーカーを確認する: + - `DESIGN_SUCCESS` → Phase 4 へ進む + - `DESIGN_FAILED` → エラー理由をユーザーに報告して終了 + +### Phase 4: TaskCreate で並列生成タスク登録(メイン) + +Phase 3 の中間ファイル `tmp/webtest/plan/<plan-name>/design-result.md` を Read し、webtest plan の一覧を抽出する。各 webtest plan ごとに TaskCreate を実行する: + +``` +TaskCreate: + subject: "webtest-plan: <webtest-plan-name>" + description: "<webtest-plan-name> の webtest plan ファイルを生成する" + activeForm: "Generating webtest-plan: <webtest-plan-name>" +``` + +ID マッピングテーブルを構築する: `{"login-form": "<TaskCreate_ID>", ...}` + +通常は依存関係なし(並列生成可能)。 + +### Phase 5: webtest plan ファイル生成(general-purpose サブエージェント x N) + +TaskList で `status: pending` のタスクを取得し、各タスクについて: + +1. TaskUpdate で `in_progress` にする +2. `references/generate-prompt-template.md` を Read で読み込む +3. テンプレートのプレースホルダーを置換する: + - `{{WEBTEST_PLAN_NAME}}` ← webtest plan 名 + - `{{TARGET_URL}}` ← target-url + - `{{DRAFT_FLAG}}` ← true / false + - `{{MODE}}` ← "Full-spec" または "Lightweight" + - `{{DESIGN_RESULT_PATH}}` ← `tmp/webtest/plan/<plan-name>/design-result.md` の絶対パス + - `{{TASK_SUMMARY_PATH}}` ← `tmp/webtest/plan/<plan-name>/task-summary.md` の絶対パス + - `{{EXPLORE_CODE_RESULT_PATH}}` ← `tmp/webtest/plan/<plan-name>/explore-code-result.md` の絶対パス(ない場合は「なし」) + - `{{WEBTEST_PLAN_FORMAT_PATH}}` ← `references/webtest-plan-format.md` の絶対パス + - `{{SIGNAL_GUIDELINES}}` ← 信号機基準(Full-spec / Lightweight で異なる) + - `{{ACCEPTANCE_CRITERIA_PATH}}` ← acceptance-criteria.md の絶対パス(Full-spec 時のみ、Lightweight 時は「なし」) +4. general-purpose サブエージェントを起動する +5. 出力のマーカーを確認する: + - `GENERATE_SUCCESS` → TaskUpdate で `completed` にする + - `GENERATE_FAILED` → エラー理由を記録、TaskUpdate で `completed`(レポートに失敗として記載) +6. 複数の webtest plan がある場合は並列で実行する(Agent ツールを複数同時起動) + +### Phase 6: 完了レポートと次ステップ案内(メイン) + +ユーザーに以下のレポートを出力する: + +```markdown +## dev-webtest-plan 完了レポート + +### 生成概要 +- Source Plan: <dev-plan-name> +- モード: Full-spec / Lightweight +- 生成ファイル数: N + +### 生成ファイル一覧 + +| ファイル | target-url | draft | シナリオ数 | 🔵 | 🟡 | 🔴 | APIセットアップ | +|---------|-----------|-------|----------|-----|-----|-----|--------------| +| login-form.md | http://app:8080/login | false | 5 | 3 | 1 | 1 | あり(共通1, 固有0) | +| dashboard.md | http://app:8080/dashboard | true | 3 | 0 | 2 | 1 | あり(共通1, 固有2) | + +### 対象外タスク +- task-NNN: <理由(API のみ、バッチ処理等)> + +### ⚠️ 🔴 警告 +以下のシナリオは前工程に根拠がなく、AI が推論で追加しました。内容を確認してください: +- <ファイル名> シナリオN: <シナリオ名> + +### 📋 draft ファイルの補完方法 +draft: true のファイルは UI 要素名が推定です。 +dev-impl 完了後に `/dev-webtest-plan <dev-plan-name>` を再実行すると、 +実装コードから UI 要素を確認し draft: false に更新できます。 + +### 🚀 次のステップ +- 実装前の場合: `/dev-impl <dev-plan-name>` で実装を進める +- 実装後の場合: `/dev-webtest <webtest-plan-name>` でテストを実行する +``` + +レポート出力後、中間ファイルをクリーンアップする: +```bash +rm -rf tmp/webtest/plan/<plan-name>/ +``` + +## 信号機基準(新規生成モード) + +| 信号 | 基準 | +|------|------| +| 🔵 | AC の Given/When/Then から直接変換、requirements.md の明示的要件に基づく | +| 🟡 | タスクの Test Strategy から推論、一般的 Web テストベストプラクティス | +| 🔴 | 前工程に根拠なし、AI が Web テストとして必要と判断した項目 | + +## サブエージェント戦略(新規生成モード) + +| Phase | タイプ | モデル | 用途 | 並列 | +|-------|-------|--------|------|------| +| 2a | Explore | haiku | dev-plan分析・画面分割判定 | 2bと並列 | +| 2b | Explore | haiku | 実装コード探索(オプション) | 2aと並列 | +| 3 | Plan | (default) | webtest plan構造設計 | 単独 | +| 5 | general-purpose | (default) | ファイル生成 | plan数分並列 | + +## エスカレーション条件(新規生成モード) + +以下の場合は自動処理を停止し、ユーザーに確認する: + +1. **context.md 不在**: `/dev-context` を案内して終了 +2. **plan 不在**: `/dev-plan` を案内して終了 +3. **既存 webtest plan との重複**: AskUserQuestion で上書き確認 +4. **Phase 2a 失敗**: plan.md の情報不足を報告して終了 +5. **Phase 3 失敗**: 設計不能の理由を報告して終了 + +## マーカー文字列(新規生成モード) + +| マーカー | 意味 | +|---------|------| +| `EXPLORE_PLAN_SUCCESS` | dev-plan 分析成功 | +| `EXPLORE_PLAN_FAILED` | dev-plan 分析失敗 | +| `EXPLORE_CODE_SUCCESS` | 実装コード探索成功 | +| `EXPLORE_CODE_FAILED` | 実装コード探索失敗 | +| `DESIGN_SUCCESS` | 構造設計成功 | +| `DESIGN_FAILED` | 構造設計失敗 | +| `GENERATE_SUCCESS` | ファイル生成成功 | +| `GENERATE_FAILED` | ファイル生成失敗 | + +--- + +## ワークフロー(差分更新モード) + +> 以下は引数が `update` で始まる場合のワークフロー。新規生成モードとは完全に独立。 + +### Phase 1: 入力検証と変更検知(メイン) + +1. `docs/dev/context.md` の存在を確認する。存在しない場合は `/dev-context` の実行を案内して終了する +2. `docs/dev/screen-specs/_index.md` の存在を確認する + - 存在しない場合は `/dev-screen-spec` の実行を案内して終了する +3. `docs/dev/webtests/plans/` 配下の既存テスト計画一覧を取得する + - 引数に `plan-name` が指定されている場合はそのファイルのみ対象 + - テスト計画が存在しない場合は「更新対象のテスト計画がありません」と報告して終了する +4. 画面仕様ドキュメントの変更を検知する: + - 各テスト計画の frontmatter から `last-run` 日付を取得する + - 各画面仕様の frontmatter から `updated_at` を取得する + - `updated_at` > `last-run` の画面仕様 → 変更ありと判定する + - **代替手段**: 画面仕様ファイルの `last_synced_commit` とテスト計画の `screen_spec_commit` フィールドを比較する +5. 変更のある画面仕様を特定し、影響するテスト計画をマッピングする: + - 画面仕様の `screen_id` / `path` とテスト計画の `target-url` を突き合わせる + - テスト計画のシナリオ内のURLパスとも照合する +6. 影響なしの場合 → 「変更なし」を表示して終了する +7. 影響のあるテスト計画と変更画面の対応表を表示する +8. 中間ファイルディレクトリを作成する: `mkdir -p tmp/webtest/update/` + +### Phase 2: 変更差分の分析(並列 Explore サブエージェント) + +影響のあるテスト計画ごとに Explore サブエージェントを起動する(並列): + +1. `references/update-analyze-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{WEBTEST_PLAN_PATH}}` ← 既存テスト計画ファイルの絶対パス + - `{{CHANGED_SCREEN_SPEC_PATHS}}` ← 変更のあった画面仕様ファイルの絶対パス一覧 + - `{{SCREEN_SPEC_INDEX_PATH}}` ← `docs/dev/screen-specs/_index.md` の絶対パス + - `{{TMP_DIR}}` ← `tmp/webtest/update/` の絶対パス +3. Explore サブエージェント(haiku)を起動する +4. 出力のマーカーを確認する: + - `UPDATE_ANALYZE_SUCCESS` → Phase 3 へ進む + - `UPDATE_ANALYZE_FAILED` → エラー理由をユーザーに報告して終了する + +### Phase 3: テスト計画の更新適用(並列 general-purpose サブエージェント) + +テスト計画ごとに general-purpose サブエージェントを起動する(並列): + +1. `references/update-apply-prompt-template.md` を Read で読み込む +2. テンプレートのプレースホルダーを置換する: + - `{{WEBTEST_PLAN_PATH}}` ← 既存テスト計画ファイルの絶対パス + - `{{ANALYZE_RESULT_PATH}}` ← `tmp/webtest/update/analyze-<plan-name>.md` の絶対パス + - `{{CHANGED_SCREEN_SPEC_PATHS}}` ← 変更のあった画面仕様ファイルの絶対パス一覧 + - `{{WEBTEST_PLAN_FORMAT_PATH}}` ← `references/webtest-plan-format.md` の絶対パス +3. general-purpose サブエージェントを起動する +4. 出力のマーカーを確認する: + - `UPDATE_APPLY_SUCCESS` → Phase 4 へ進む + - `UPDATE_APPLY_FAILED` → エラー理由を記録、レポートに失敗として記載する + +### Phase 4: 完了レポートと後処理(メイン) + +ユーザーに以下のレポートを出力する: + +```markdown +## dev-webtest-plan 差分更新レポート + +### 変更元 +- 画面仕様の変更: N 画面 + +### 更新されたテスト計画 + +| テスト計画 | 追加 | 修正 | 削除 | 合計シナリオ | +|-----------|------|------|------|------------| +| login-form.md | +2 | ~1 | -0 | 7 | +| dashboard.md | +0 | ~3 | -1 | 5 | + +### 変更詳細 + +#### login-form.md +- ✅ 追加: シナリオ「電話番号バリデーション」(画面仕様: login.md のバリデーション追加に対応) +- ✅ 追加: シナリオ「2要素認証フロー」(画面仕様: login.md のインタラクション追加に対応) +- ✏️ 修正: シナリオ「パスワードバリデーション」(ルール変更: 8文字→10文字) + +### 🚀 次のステップ +- `/dev-webtest <plan-name>` でテストを実行する +``` + +レポート出力後、中間ファイルをクリーンアップする: +```bash +rm -rf tmp/webtest/update/ +``` + +## webtest計画 frontmatter への追加フィールド(差分更新用) + +差分更新の追跡のため、既存のfrontmatterに以下を追加する: + +```yaml +--- +# ... 既存フィールド ... +screen_spec_commit: abc1234 # この計画が参照した画面仕様の last_synced_commit +last_updated: "2026-03-09" # 差分更新の最終日 +update_history: # 更新履歴(直近3回) + - date: "2026-03-09" + changes: "+2 ~1 -0" + source: "screen-spec update" +--- +``` + +- `screen_spec_commit`: 新規生成時にも画面仕様が存在する場合は設定する +- `last_updated`: 差分更新を実行した日付 +- `update_history`: 直近3回の更新履歴。古いものから削除する + +## 画面仕様 → テスト計画のセクション対応マッピング + +| 画面仕様セクション | テスト計画の更新対象 | +|------------------|-------------------| +| 画面項目(追加) | 新規シナリオ追加(要素の表示確認) | +| 画面項目(変更) | 既存シナリオの手順・期待結果を修正 | +| 画面項目(削除) | 該当シナリオを削除 | +| バリデーション(追加) | フォームバリデーション確認テーブルに行追加 + シナリオ追加 | +| バリデーション(変更) | フォームバリデーション確認テーブル更新 + シナリオ修正 | +| バリデーション(削除) | フォームバリデーション確認テーブルから行削除 + シナリオ削除 | +| インタラクション(追加) | 新規シナリオ追加 | +| インタラクション(変更) | 既存シナリオの手順・期待結果を修正 | +| インタラクション(削除) | 該当シナリオを削除 | +| 状態(追加/変更) | 状態遷移テストの追加・修正 | +| フロー定義(追加) | フロー全体のE2Eシナリオを新規追加 | +| フロー定義(変更) | フロー内の遷移順序・アクションが変わった場合、関連するE2Eシナリオを修正 | +| フロー定義(画面変更) | フロー内の1画面が変更された場合、そのフローのE2Eシナリオ全体を更新対象とする | + +## フローベースのE2Eシナリオ生成 + +### 概要 + +`_index.md` のフロー定義から、画面単体テストとは別に**フロー全体のE2Eシナリオ**を生成する。 + +### フロー → テストシナリオの変換例 + +フロー定義: +``` +user-create --[登録ボタン]--> user-detail --[一覧に戻る]--> user-list +``` + +生成されるテストシナリオ: +```markdown +### シナリオ: ユーザー登録→確認→一覧フロー + +**手順**: +1. `/users/new` にアクセスする +2. 各項目を入力する(user-create の画面項目を参照) +3. 「登録」ボタンをクリックする +4. `/users/:id` に遷移することを確認する +5. 登録したデータが詳細画面に表示されていることを確認する +6. 「一覧に戻る」をクリックする +7. `/users` に遷移することを確認する +8. 登録したデータが一覧に表示されていることを確認する + +**期待結果**: +- [ ] 登録後、詳細画面に遷移する +- [ ] 詳細画面に登録したデータが正しく表示される +- [ ] 一覧画面に戻れる +- [ ] 一覧画面に登録したデータが表示される +``` + +### 差分更新時のフロー影響判定 + +Phase 2 の分析時に以下を追加で判定する: +1. 変更された画面が含まれるフローを `_index.md` から特定する +2. そのフローに対応するE2Eシナリオを更新対象に追加する +3. フロー定義自体が変更された場合(遷移先の変更、フロー追加・削除)もE2Eシナリオを更新する + +### 到達不能画面の検知 + +- `_index.md` の「到達不能画面チェック」でいずれのフローにも含まれない画面を検知する +- テスト計画にも反映: 到達不能画面のテストシナリオには ⚠️ 警告を付与する + +## 信号機基準(差分更新モード) + +| 信号 | 基準 | +|------|------| +| 🟡 | 画面仕様の変更に基づく追加・修正(`source: screen-spec update`) | +| 🔵 | 既存シナリオで変更なし(元の信号を維持) | +| 🔴 | 画面仕様に根拠なし、AI が必要と判断した追加項目 | + +差分更新で追加・修正されるシナリオには `🟡 source: screen-spec update` を付与する。既存シナリオの信号機は変更しない。 + +## サブエージェント戦略(差分更新モード) + +| Phase | タイプ | モデル | 用途 | 並列 | +|-------|-------|--------|------|------| +| 2 | Explore | haiku | 変更差分の分析 | テスト計画数分並列 | +| 3 | general-purpose | (default) | テスト計画の更新適用 | テスト計画数分並列 | + +## エスカレーション条件(差分更新モード) + +以下の場合は自動処理を停止し、ユーザーに確認する: + +1. **context.md 不在**: `/dev-context` を案内して終了 +2. **画面仕様なし**: `/dev-screen-spec` を案内して終了 +3. **テスト計画なし**: 「更新対象のテスト計画がありません」と報告して終了 +4. **画面仕様とテスト計画の対応が不明**: 対応付けできなかった画面仕様を表示し、手動マッピングを依頼 +5. **分析結果が大量(20件超の変更)**: ユーザーに確認後、優先度の高いものから更新 + +## マーカー文字列(差分更新モード) + +| マーカー | 意味 | +|---------|------| +| `UPDATE_ANALYZE_SUCCESS` | 変更分析成功 | +| `UPDATE_ANALYZE_FAILED` | 変更分析失敗 | +| `UPDATE_APPLY_SUCCESS` | テスト計画更新成功 | +| `UPDATE_APPLY_FAILED` | テスト計画更新失敗 | + +## ルール・制約 + +### 共通 + +- context.md が存在しない場合は `/dev-context` を案内して終了する +- モード判定は自動(ユーザー質問不要) +- `docs/dev/webtests/plans/` が存在しない場合は自動作成する +- 各生成ファイルは **500行以内**(超過時はシナリオ分割で複数ファイルに) +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- サブエージェントは Task/TodoWrite 使用禁止 +- メインエージェントはファイル全文を Read しない(パス確認・Grep のみ) +- サブエージェントにはファイルパスを渡し、サブエージェントが自分で Read する +- サブエージェントはマーカー+ファイルパス+行数のみ返す(結果本文は返さない) + +### 新規生成モード固有 + +- plan が存在しない場合は `/dev-plan` を案内して終了する +- Phase 間のデータ受け渡しは中間ファイル(`tmp/webtest/plan/<plan-name>/`)経由 +- 🔴 は完了レポートで警告表示する +- 再実行時に `draft: true` → `false` に更新可能 +- Phase 6 完了後に中間ファイルディレクトリを削除する + +### 差分更新モード固有 + +- 画面仕様が存在しない場合は `/dev-screen-spec` を案内して終了する +- Phase 間のデータ受け渡しは中間ファイル(`tmp/webtest/update/`)経由 +- 差分更新で追加・修正されるシナリオには `🟡 source: screen-spec update` を付与する +- 既存シナリオの信号機は変更しない +- フロー定義の変更も影響判定に含める +- Phase 4 完了後に中間ファイルディレクトリを削除する +- 更新後に frontmatter の `screen_spec_commit`, `last_updated`, `update_history` を更新する + +## 追加リソース + +### リファレンスファイル + +#### 新規生成モード用 + +- **`references/webtest-plan-format.md`** — 出力フォーマット定義(dev-webtest の test-plan-template.md を拡張) +- **`references/ac-to-scenario-mapping.md`** — Given/When/Then → webtest シナリオ変換ルール +- **`references/lightweight-inference-guide.md`** — Lightweight モードでのタスク情報→シナリオ推論ガイド +- **`references/explore-plan-prompt-template.md`** — Phase 2a: dev-plan 分析 Explore サブエージェント用プロンプト +- **`references/explore-code-prompt-template.md`** — Phase 2b: 実装コード探索 Explore サブエージェント用プロンプト +- **`references/design-prompt-template.md`** — Phase 3: 構造設計 Plan サブエージェント用プロンプト +- **`references/generate-prompt-template.md`** — Phase 5: ファイル生成 general-purpose サブエージェント用プロンプト + +#### 差分更新モード用 + +- **`references/update-analyze-prompt-template.md`** — Phase 2: 変更分析 Explore サブエージェント用プロンプト +- **`references/update-apply-prompt-template.md`** — Phase 3: テスト計画更新適用 general-purpose サブエージェント用プロンプト diff --git a/skills/dev-webtest-plan/references/ac-to-scenario-mapping.md b/skills/dev-webtest-plan/references/ac-to-scenario-mapping.md new file mode 100644 index 0000000..c13f405 --- /dev/null +++ b/skills/dev-webtest-plan/references/ac-to-scenario-mapping.md @@ -0,0 +1,219 @@ +# AC → Webtest シナリオ変換ルール + +Full-spec モードにおいて、acceptance-criteria.md の Given/When/Then 構造を webtest plan のシナリオに変換するためのルール集。 + +--- + +## 変換の基本原則 + +acceptance-criteria.md の各 AC エントリは以下の構造を持つ: + +```markdown +## AC-001: [FR-XXX] [要件名] 🔵 + +### Given(前提条件) +- [テスト実行前の状態] + +### When(実行条件) +- [ユーザーが実行するアクション] + +### Then(期待結果) +- [期待される出力・状態変化] + +### テストチェックリスト +- [ ] **正常系**: [具体的なテストケース] +- [ ] **異常系**: [エラーケース] +- [ ] **境界値**: [境界値ケース] +``` + +これを webtest plan のシナリオに以下のルールで変換する。 + +--- + +## マッピングルール + +### 1. Given → 前提条件セクション + APIデータセットアップ + +| AC の Given | webtest plan の前提条件 | APIセットアップ | +|------------|----------------------|----------------| +| ユーザーがログイン済み | テストデータにログイン可能なユーザーが存在する | ユーザー作成API(ファイル共通) | +| データベースに X が存在する | テストデータに X が登録済み | X 作成API(ファイル共通 or シナリオ固有) | +| 特定のページにいる | 手順の最初にそのページへのアクセスを追加 | — | +| 権限を持っている | 適切な権限を持つテストユーザーでログイン | 権限付きユーザー作成API(ファイル共通) | +| X件のデータが一覧にある | 一覧表示用のテストデータが存在する | 複数データ作成API(シナリオ固有) | + +**変換例**: + +AC: +``` +### Given(前提条件) +- ユーザーがログイン済みである +- ユーザーは管理者権限を持っている +``` + +webtest plan(前提条件): +``` +## 前提条件 +- 管理者権限を持つテストユーザー (admin@test.com / Test1234!) でログイン可能 +- テスト開始前にログイン済み状態であること +``` + +webtest plan(APIデータセットアップ): +``` +## APIデータセットアップ + +### ファイル共通 + +<!-- 🔵 source: AC-001 Given --> +​```bash +# 管理者テストユーザー作成 +curl -X POST http://app:8080/api/users \ + -H 'Content-Type: application/json' \ + -d '{"email":"admin@test.com","password":"Test1234!","role":"admin"}' +​``` +``` + +#### APIクリーンアップへの対応 + +Given で作成したデータは、テスト完了後にクリーンアップする: + +| Given の内容 | クリーンアップ | +|-------------|--------------| +| ユーザーが存在する | DELETE /api/users/:id | +| データが存在する | DELETE /api/<resource>/:id | +| 権限が設定されている | ユーザー削除で権限も削除される前提 | + +### 2. When → 手順セクション + +| AC の When | webtest plan の手順 | +|-----------|-------------------| +| ユーザーが X を入力する | 「X」入力欄に値を入力する | +| ユーザーが X ボタンをクリックする | 「X」ボタンをクリックする | +| ユーザーが X ページにアクセスする | `<URL>` にアクセスする | +| ユーザーが X を選択する | 「X」ドロップダウンから値を選択する | +| ユーザーが X を送信する | 「X」フォームの送信ボタンをクリックする | + +**変換例**: + +AC: +``` +### When(実行条件) +- ユーザーがメールアドレスとパスワードを入力する +- ログインボタンをクリックする +``` + +webtest plan: +``` +**手順**: +1. `http://app:8080/login` にアクセスする +2. 「メールアドレス」入力欄に "admin@test.com" を入力する +3. 「パスワード」入力欄に "Test1234!" を入力する +4. 「ログイン」ボタンをクリックする +``` + +### 3. Then → 期待結果セクション + +| AC の Then | webtest plan の期待結果 | +|-----------|---------------------| +| X が表示される | `- [ ] X が表示される` | +| X ページに遷移する | `- [ ] X ページに遷移する`(URL確認含む) | +| エラーメッセージ Y が表示される | `- [ ] 「Y」というエラーメッセージが表示される` | +| データが保存される | `- [ ] 成功メッセージが表示される`(UI上で確認可能な結果に変換) | +| X の状態が Y に変わる | `- [ ] X の表示が Y に変わる`(UI上で確認可能な結果に変換) | + +**重要**: バックエンドの状態変化(DBへの保存等)は、UI上で確認可能な結果に変換する。API レスポンスの直接確認は webtest では行わない。 + +**変換例**: + +AC: +``` +### Then(期待結果) +- ダッシュボードページにリダイレクトされる +- ユーザー名が画面上部に表示される +- セッションが作成される +``` + +webtest plan: +``` +**期待結果**: +- [ ] ダッシュボードページ (`/dashboard`) に遷移する +- [ ] ページ上部に「ようこそ、テストユーザーさん」と表示される +- [ ] ナビゲーションに「ログアウト」リンクが表示される +``` + +### 4. テストチェックリスト → 追加シナリオ + +AC のテストチェックリストの各項目を個別のシナリオまたはシナリオ内のサブケースに変換する: + +| チェックリスト種別 | 変換先 | +|----------------|-------| +| 正常系 | メインシナリオの手順+期待結果 | +| 異常系 | 別シナリオ「エラーケース: ...」 | +| 境界値 | フォームバリデーション確認テーブル or 別シナリオ | + +--- + +## AC 間の関連性処理 + +### 同一画面の AC をグルーピング + +同一の target-url を持つ AC は1つの webtest plan ファイルにまとめる: + +``` +AC-001: ログインフォーム表示 → login-form.md +AC-002: ログイン成功 → login-form.md(シナリオ追加) +AC-003: ログイン失敗 → login-form.md(シナリオ追加) +AC-010: ダッシュボード表示 → dashboard.md(別ファイル) +``` + +### フロー系 AC の連結 + +ユーザーフローを構成する AC は、シナリオ内で連続手順として連結する: + +``` +AC-001(ログイン) → AC-002(商品選択) → AC-003(購入) の場合: + +purchase-flow.md に全体フローのシナリオを作成し、 +各 AC を source コメントで紐づける +``` + +--- + +## 信号機の継承と変換 + +AC の信号機は webtest plan のシナリオに継承する: + +| AC の信号 | webtest シナリオの信号 | 備考 | +|----------|---------------------|------| +| 🔵 | 🔵 | AC からの直接変換、最も信頼性が高い | +| 🟡 | 🟡 | AC の推測部分がそのまま反映 | +| 🔴 | 🔴 | AC 側で未確認の要素を含む | + +**注意**: UI要素名の特定精度で信号が変わる場合がある: +- AC 🔵 + UI要素名が実装コードで確認済み → 🔵 +- AC 🔵 + UI要素名が推定(draft: true) → 🟡(UI要素の推定部分のみ) + +--- + +## APIセットアップ/クリーンアップの信号機マッピング + +AC の情報源に応じて、APIセットアップ/クリーンアップのcurlコマンドにも信号機を付与する: + +| 情報源 | 信号 | 例 | +|--------|------|-----| +| AC の Given から直接特定 + API仕様で確認済み | 🔵 | AC-001 Given「ユーザーが存在する」→ OpenAPI spec の POST /api/users | +| AC の Given から推定 + 実装コードで確認 | 🟡 | AC-001 Given → handler/user.go のルーティングから POST /api/users を確認 | +| AC の Given から推定のみ(APIエンドポイント未確認) | 🔴 | AC-001 Given → REST慣例から POST /api/users を推定 | + +## 変換できない AC の処理 + +以下の AC は webtest plan に直接変換できない: + +| AC の種類 | 処理 | +|----------|------| +| API のみのテスト(画面なし) | スキップ、理由をログに記載。ただしAPIエンドポイントはセットアップ/クリーンアップの情報源として活用する | +| バッチ処理・非同期処理 | スキップ、理由をログに記載 | +| パフォーマンス要件(NFR) | レスポンシブ確認やページ読み込み確認に限定的に反映 | +| セキュリティ要件(NFR) | フォームバリデーション確認に反映可能な部分のみ | + +スキップした AC は完了レポートの「対象外 AC」セクションに記載する。 diff --git a/skills/dev-webtest-plan/references/design-prompt-template.md b/skills/dev-webtest-plan/references/design-prompt-template.md new file mode 100644 index 0000000..8055c0c --- /dev/null +++ b/skills/dev-webtest-plan/references/design-prompt-template.md @@ -0,0 +1,255 @@ +# Design サブエージェント プロンプトテンプレート + +dev-webtest-plan がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web テスト計画のアーキテクトです。分析結果を基に、webtest plan ファイルの詳細構造を設計してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- 設計結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** +- 各 webtest plan は **500行以内** に収まる設計にすること + +## 設計モード + +モード: **{{MODE}}** + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から設計してください: + +### Phase 2a: plan 分析結果(分割案・シナリオ方向性・タスクサマリー含む) + +{{EXPLORE_PLAN_RESULT_PATH}} + +### タスクサマリー + +{{TASK_SUMMARY_PATH}} + +### Phase 2b: UI 要素情報(実装コード探索結果、ない場合は「なし」) + +{{EXPLORE_CODE_RESULT_PATH}} + +### webtest plan 出力フォーマット + +{{WEBTEST_PLAN_FORMAT_PATH}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 設計タスク + +Phase 2 の分析結果を基に、各 webtest plan ファイルの詳細構造を設計してください。 + +### 1. webtest plan ごとの構造設計 + +各 webtest plan について以下を設計する: + +#### フロントマター + +```yaml +--- +name: <webtest-plan-name> +target-url: <URL> +status: pending +last-run: +draft: <true/false> +source-plan: <dev-plan-name> +source-acs: [<AC-ID>, ...] # Full-spec時 +source-tasks: ["<NNN>", ...] +viewports: + - 375x667 + - 768x1024 + - 1280x800 +--- +``` + +#### 前提条件 + +テスト実行に必要な状態を列挙: +- テストデータの準備 +- ログイン状態 +- Docker 環境の起動状態 + +#### APIデータセットアップ/クリーンアップ + +Phase 2 の分析結果(explore-plan-result.md の「APIセットアップ/クリーンアップ情報」セクション、explore-code-result.md の「APIエンドポイント」セクション)を基に設計する: + +**ファイル共通セットアップ**: +- 全シナリオで必要なテストデータの作成手順を curl コマンドで記述する +- 認証トークンが必要な場合はログインAPIを最初に記述する +- 各コマンドに信号機コメントを付与する + +**シナリオ固有セットアップ**: +- 特定シナリオでのみ必要なデータの作成手順を curl コマンドで記述する +- 「### シナリオN固有」の見出しで対象シナリオを明記する + +**クリーンアップ**: +- セットアップの逆順で DELETE API を記述する +- 依存関係を考慮した実行順序を設計する + +**情報源の優先順位**: +1. dev-plan(タスクファイルの Interfaces / Files / Test Strategy)→ 🔴 +2. 実装コード探索(Phase 2b のルーティング定義)→ 🟡 +3. 既存API仕様(openapi.yaml等、Phase 2b で検出)→ 🔵 + +**注意**: Phase 2b がスキップされた場合(`draft: true`)は、dev-plan からの推定のみで 🔴 として記述する。推定APIエンドポイントにはコメントで `(推定)` を付記する。 + +#### シナリオ設計 + +**Full-spec モードの場合**: + +AC の Given/When/Then を webtest シナリオに直接マッピングする: +- Given → 前提条件セクション(テスト全体に共通なもの)+ 各シナリオの手順の最初に状態準備 +- When → 手順(具体的な操作ステップに展開) +- Then → 期待結果(UI上で確認可能な形に変換) +- 各シナリオに `<!-- 🔵 source: AC-XXX -->` コメントを付与 +- テストチェックリストの異常系・境界値は追加シナリオとして設計 + +**Lightweight モードの場合**: + +タスクの Test Strategy / Goal / Files から推論: +- Test Strategy の各項目を画面テストシナリオに変換 +- 各シナリオに `<!-- 🟡 source: task-NNN Test Strategy -->` コメントを付与 +- UI要素名が未確定の場合は `(推定)` を付記 + +#### フォームバリデーション確認テーブル + +フォームが存在する場合、バリデーション確認テーブルを設計する: + +``` +| フィールド | type | required | テストパターン | +|-----------|------|----------|-------------| +``` + +テストパターンは最低限: 空, 不正形式, 正常値 +UI要素情報がある場合: HTML5属性やバリデーションルールに基づくパターンを追加 + +### 2. 信号機付与 + +各シナリオに信号機を付与する: + +| 信号 | 基準 | +|------|------| +| 🔵 | AC の Given/When/Then から直接変換、requirements.md の明示的要件に基づく | +| 🟡 | タスクの Test Strategy から推論、一般的 Web テストベストプラクティス | +| 🔴 | 前工程に根拠なし、AI が Web テストとして必要と判断した項目 | + +### 3. draft 判定 + +各 webtest plan の draft フラグを判定する: + +- UI 要素情報(Phase 2b)が存在し、シナリオの手順に使用する要素が確認済み → `draft: false` +- UI 要素情報がない、または一部の要素が未確認 → `draft: true` + +### 4. 500行チェック + +各 webtest plan の推定行数を見積もり、500行を超える場合は分割を提案する: + +- シナリオ1つ ≈ 15-25行 +- フォームバリデーション ≈ 10-20行 +- 共通セクション(アクセシビリティ、レスポンシブ等) ≈ 30行 +- フロントマター + 前提条件 ≈ 20行 + +## 出力 + +以下の構成で設計結果を `{{TMP_DIR}}/design-result.md` に Write する: + +```markdown +# Design Result + +## 設計概要 + +- webtest plan 数: N +- Full-spec / Lightweight +- draft: true の数 / false の数 + +## webtest plan 設計 + +### <webtest-plan-name-1> + +#### フロントマター +(YAML形式) + +#### 前提条件 +- ... + +#### シナリオ一覧 +| # | シナリオ名 | 信号 | ソース | 概要 | +|---|-----------|------|--------|------| +| 1 | ログイン成功 | 🔵 | AC-001 | 正常なログインフロー | +| 2 | パスワード誤り | 🔵 | AC-001 | 異常系 | + +#### シナリオ詳細 + +##### <!-- 🔵 source: AC-001 --> シナリオ1: ログイン成功 + +**手順**: +1. ... + +**期待結果**: +- [ ] ... + +**視覚チェックポイント**: +- [ ] ... + +(各シナリオを詳細設計) + +#### フォームバリデーション確認 +(テーブル形式) + +#### APIデータセットアップ +##### ファイル共通 +| 目的 | エンドポイント | ボディ | 信号 | +|------|-------------|--------|------| +| テストユーザー作成 | POST /api/users | {email, password, role} | 🟡 | + +##### シナリオ固有 +| 対象シナリオ | 目的 | エンドポイント | ボディ | 信号 | +|------------|------|-------------|--------|------| +| シナリオ3 | 注文作成 | POST /api/orders | {item_id, qty} | 🔴 | + +##### クリーンアップ +| 目的 | エンドポイント | 実行順序 | 信号 | +|------|-------------|---------|------| +| 注文削除 | DELETE /api/orders/:id | 1 | 🔴 | +| ユーザー削除 | DELETE /api/users/:id | 2 | 🟡 | + +#### 推定行数: N行 + +--- + +### <webtest-plan-name-2> +... + +## トレーサビリティサマリー + +| webtest plan | シナリオ数 | 🔵 | 🟡 | 🔴 | draft | +|-------------|----------|-----|-----|-----|-------| +| login-form | 5 | 3 | 1 | 1 | false | + +## 対象外 AC / タスク +- AC-XXX: <理由> +- task-NNN: <理由> +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 設計完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/design-result.md (N行) + DESIGN_SUCCESS + ``` +- 設計失敗時: 理由と共に `DESIGN_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/explore-code-prompt-template.md b/skills/dev-webtest-plan/references/explore-code-prompt-template.md new file mode 100644 index 0000000..8090d00 --- /dev/null +++ b/skills/dev-webtest-plan/references/explore-code-prompt-template.md @@ -0,0 +1,188 @@ +# Explore Code サブエージェント プロンプトテンプレート + +dev-webtest-plan がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## 前提 + +このサブエージェントはオプション実行。以下のいずれかの条件を満たす場合のみ起動する: +- タスクファイルに `status: done` が1つ以上存在する +- タスクの Files セクションに記載されたファイルが実際に存在する + +条件を満たさない場合はスキップし、`draft: true` でwebtest planを生成する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web アプリケーションの UI 構造アナリストです。実装コードから画面の UI 要素、ルーティング、フォーム構造を抽出してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 入力データ(ファイルパス) + +### プロジェクトコンテキスト + +以下のファイルを **Read で読み込んで** から調査してください: + +{{CONTEXT_MD_PATH}} + +### 調査対象ファイル + +以下のファイルを起点に調査してください: + +{{TARGET_FILES}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 調査タスク + +### 1. ルーティング定義の抽出 + +プロジェクトのルーティング定義を探索し、URL パスとハンドラーのマッピングを抽出する: + +- Grep で `Route`, `GET`, `POST`, `PUT`, `DELETE`, `Handle`, `HandleFunc`, `router.` 等を検索 +- ルーティングファイル(`routes.go`, `router.go`, `app.ts`, `routes/` 等)を特定 +- 各ルートの HTTP メソッド、パス、ハンドラー名を一覧化 + +### 2. HTML/テンプレートからの UI 要素抽出 + +テンプレートファイル(`.templ`, `.html`, `.tsx`, `.vue` 等)から UI 要素を抽出する: + +- Glob で `templates/`, `views/`, `pages/`, `components/` 配下のファイルを検索 +- 各テンプレートの以下の要素を抽出: + - `<form>` 要素(action, method) + - `<input>`, `<select>`, `<textarea>` 要素(name, type, required, placeholder) + - `<button>`, `<a>` 要素(テキスト内容、href) + - ヘッディング要素(`<h1>` 〜 `<h6>`) + - ナビゲーション要素 + +### 3. フォームバリデーションの調査 + +クライアントサイド・サーバーサイドのバリデーションルールを調査する: + +- HTML5 バリデーション属性(required, pattern, min, max, minlength, maxlength) +- JavaScript バリデーション(`validate`, `validation`, `check` 等で Grep) +- サーバーサイドバリデーション(ハンドラー内の入力チェック) + +### 4. エラーメッセージの抽出 + +テンプレートやコードからエラーメッセージのテキストを抽出する: + +- Grep で `error`, `エラー`, `invalid`, `required`, `validation` 等を検索 +- テンプレート内の条件付き表示(`if err`, `{{if .Error}}` 等)を特定 +- 各エラーメッセージのテキストとトリガー条件を記録 + +### 5. APIエンドポイントの詳細調査 + +テストデータのセットアップ/クリーンアップに使用可能なAPIエンドポイントを調査する: + +#### 5-1. API仕様ファイルの自動探索 + +以下のパスを Glob で探索し、存在するものを Read する: + +``` +openapi.yaml, openapi.json, swagger.yaml, swagger.json +docs/api/*, api-docs/* +*.openapi.yaml, *.swagger.json +``` + +#### 5-2. ルーティング定義からのAPI抽出 + +Step 1 で抽出したルーティング一覧から、データ操作系のAPIエンドポイントを特定する: + +- CRUD 操作(POST/PUT/DELETE)のエンドポイントを優先的に抽出 +- リクエストボディの構造(struct 定義、型情報)を特定する +- レスポンスの構造(特に POST のレスポンスで ID が返る等)を確認する +- 認証が必要なエンドポイントを特定する(middleware, auth guard 等) + +#### 5-3. 認証フローの調査 + +- ログイン/認証エンドポイントを特定する(POST /api/auth/login 等) +- トークンの取得方法(レスポンスボディの構造)を確認する +- トークンの使用方法(Authorization ヘッダーの形式: Bearer, Basic 等)を確認する + +## 出力 + +上記の調査結果を以下のセクション構成で `{{TMP_DIR}}/explore-code-result.md` に Write する: + +```markdown +# Explore Code Result + +## ルーティング一覧 +| メソッド | パス | ハンドラー | 備考 | +|---------|------|-----------|------| +| GET | /login | HandleLogin | ログインページ表示 | +| POST | /login | HandleLoginSubmit | ログイン処理 | + +## UI 要素一覧 + +### <ページ名> (<テンプレートファイルパス>) + +#### フォーム +- フォーム名: <name/id> + - action: <パス> + - method: <POST/GET> + - フィールド: + | 名前 | type | required | placeholder | ラベルテキスト | + |------|------|----------|-------------|-------------| + | email | email | yes | メールアドレス | メールアドレス | + +#### ボタン・リンク +| テキスト | タイプ | 遷移先/アクション | +|---------|-------|----------------| +| ログイン | button[submit] | フォーム送信 | +| 新規登録 | a | /register | + +#### ヘッディング・構造 +- h1: <テキスト> +- h2: <テキスト> + +## バリデーションルール + +### <フォーム名> +| フィールド | HTML5属性 | JSバリデーション | サーバー側 | +|-----------|----------|---------------|----------| +| email | required, type=email | — | 形式チェック, 重複チェック | + +## エラーメッセージ +... + +## APIエンドポイント(セットアップ/クリーンアップ用) + +### API仕様ファイル +- 検出: <openapi.yaml 等のパス、または「なし」> + +### データ操作API +| メソッド | パス | 用途 | リクエストボディ | 認証 | 情報源 | +|---------|------|------|---------------|------|--------| +| POST | /api/users | ユーザー作成 | {email, password, role} | 不要 | handler/user.go | +| DELETE | /api/users/:id | ユーザー削除 | — | Bearer token | handler/user.go | + +### 認証フロー +- ログインエンドポイント: <POST /api/auth/login> +- リクエストボディ: <{email, password}> +- レスポンス: <{token: "...", user: {...}}> +- トークン使用方法: <Authorization: Bearer {token}> +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 調査完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/explore-code-result.md (N行) + EXPLORE_CODE_SUCCESS + ``` +- 調査失敗時(対象ファイルが存在しない等): 理由と共に `EXPLORE_CODE_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/explore-plan-prompt-template.md b/skills/dev-webtest-plan/references/explore-plan-prompt-template.md new file mode 100644 index 0000000..c59c328 --- /dev/null +++ b/skills/dev-webtest-plan/references/explore-plan-prompt-template.md @@ -0,0 +1,219 @@ +# Explore Plan サブエージェント プロンプトテンプレート + +dev-webtest-plan がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web テスト計画のアナリストです。dev-plan の出力を分析し、webtest plan の分割案と画面・フロー情報を抽出してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 分析モード + +モード: **{{MODE}}** + +- Full-spec: acceptance-criteria.md の Given/When/Then を主要な情報源とする +- Lightweight: タスクファイルの Goal / Test Strategy / Files を主要な情報源とする + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から分析してください: + +### plan.md + +{{PLAN_MD_PATH}} + +### acceptance-criteria.md(Full-spec 時のみ、Lightweight 時は「なし」) + +{{ACCEPTANCE_CRITERIA_PATH}} + +### タスクファイル一覧 + +以下のファイルを **すべて Read** してください: + +{{TASK_FILE_PATHS}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 分析タスク + +### Step 1: タスクサマリーの生成 + +上記タスクファイルをすべて Read し、各タスクから以下の情報を抽出してサマリーを生成する: + +- id +- title +- status +- Goal セクションの内容 +- Test Strategy セクションの内容 +- Files セクションの内容 + +サマリーを `{{TMP_DIR}}/task-summary.md` に Write する。 + +フォーマット: + +```markdown +# Task Summary + +## task-NNN: <title> +- status: <status> +- Goal: <Goal の要約> +- Test Strategy: + - <項目1> + - <項目2> +- Files: + - <ファイルパス1> + - <ファイルパス2> + +## task-NNN: <title> +... +``` + +### Step 2: 画面/ページの特定 + +plan.md とタスクサマリーから、テスト対象となる画面/ページを特定する: + +- 画面名(日本語) +- 推定 URL パス +- 関連するタスク ID +- 関連する AC ID(Full-spec 時) + +### Step 3: webtest plan 分割案 + +特定した画面/ページをもとに、webtest plan ファイルの分割を提案する: + +- 1ファイル = 1画面/フローが基本 +- 密接に関連する画面(例: ログインフォーム + ログイン結果)は1ファイルにまとめる +- 大きなフロー(例: 購入フロー全体)は分割を検討 + +### Step 4: シナリオの方向性 + +各 webtest plan について、含めるべきシナリオの方向性を提示する: + +**Full-spec の場合**: +- AC の Given/When/Then を列挙し、webtest シナリオへの変換方針を記載 +- テストチェックリストから追加シナリオの候補を抽出 + +**Lightweight の場合**: +- タスクの Test Strategy から画面テストに変換可能な項目を列挙 +- タスクの Goal から画面の機能概要を推定 + +### Step 5: フォーム検出 + +タスクファイルから入力フォームの存在を推定する: + +- フォーム名 +- 推定フィールド(名前, type, required) +- バリデーションルール(判明分) + +### Step 6: APIセットアップ/クリーンアップ情報の抽出 + +各画面テストシナリオが前提とするデータを特定し、API経由でのデータ登録・削除手順を推論する: + +**Full-spec の場合**: +- AC の Given(前提条件)から必要なテストデータを特定する +- 「ユーザーが存在する」「データがN件ある」等の前提を API 呼び出しに変換する +- AC の Then に「データが保存される」がある場合、クリーンアップ対象として記録する + +**Lightweight の場合**: +- タスクの Test Strategy から前提データ要件を推定する +- タスクの Interfaces セクションからリソースの型定義を抽出し、API ボディを推定する +- タスクの Files からハンドラー/ルーティングファイルを特定し、APIエンドポイントを推定する + +**共通**: +- ファイル共通のセットアップ(全シナリオで必要なデータ: テストユーザー等)を特定する +- シナリオ固有のセットアップ(特定シナリオでのみ必要なデータ)を特定する +- クリーンアップ対象のリソースとDELETEエンドポイントの推定を行う +- 認証トークンが必要な場合、ログインAPIによるトークン取得手順も含める + +### Step 7: 画面関連でないタスクの特定 + +webtest plan の対象外となるタスク(API のみ、バッチ処理、マイグレーション等)を特定し、理由を記載する。ただし、対象外タスクのAPIエンドポイント情報はセットアップ/クリーンアップの情報源として記録する。 + +## 出力 + +Step 2〜7 の分析結果を以下のセクション構成で `{{TMP_DIR}}/explore-plan-result.md` に Write する: + +```markdown +# Explore Plan Result + +## 画面一覧 +... + +## 分割案 + +### <webtest-plan-name-1> +- target-url: <推定URL> +- 画面: <画面名> +- 関連タスク: [NNN, NNN] +- 関連AC: [AC-XXX, AC-XXX](Full-spec時) +- シナリオ概要: + - 正常系: <概要> + - 異常系: <概要> +- draft: true/false の推奨 + +### <webtest-plan-name-2> +... + +## シナリオ方向性 +... + +## フォーム検出結果 +... + +## APIセットアップ/クリーンアップ情報 + +### ファイル共通セットアップ +- 目的: <テストユーザー作成等> +- 推定エンドポイント: <POST /api/users> +- 推定ボディ: <{"email":"...","password":"...","role":"..."}> +- 情報源: <AC-001 Given / task-001 Test Strategy / 等> +- 信号: 🔵/🟡/🔴 + +### シナリオ固有セットアップ +- 対象: <webtest-plan-name> シナリオN +- 目的: <注文データ作成等> +- 推定エンドポイント: <POST /api/orders> +- 推定ボディ: <{"item_id":1,"quantity":2}> +- 情報源: <AC-003 Given / task-003 Test Strategy / 等> +- 信号: 🔵/🟡/🔴 + +### クリーンアップ +- 対象リソース: <users, orders> +- 推定エンドポイント: <DELETE /api/users/:id, DELETE /api/orders/:id> +- 実行順序: <orders → users(依存関係の逆順)> +- 信号: 🔵/🟡/🔴 + +### 認証トークン取得 +- 必要: Yes/No +- ログインエンドポイント: <POST /api/auth/login> +- トークン取得方法: <レスポンスボディの token フィールド> + +## 対象外タスク +... +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 分析完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/task-summary.md (N行) + - {{TMP_DIR}}/explore-plan-result.md (N行) + EXPLORE_PLAN_SUCCESS + ``` +- 分析失敗時: 理由と共に `EXPLORE_PLAN_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/generate-prompt-template.md b/skills/dev-webtest-plan/references/generate-prompt-template.md new file mode 100644 index 0000000..557ed4e --- /dev/null +++ b/skills/dev-webtest-plan/references/generate-prompt-template.md @@ -0,0 +1,253 @@ +# Generate サブエージェント プロンプトテンプレート + +dev-webtest-plan がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web テスト計画ファイルのジェネレーターです。設計に基づいて webtest plan の Markdown ファイルを生成してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- 生成するファイルは **500行以内** に収めること +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 出力先: `docs/dev/webtests/plans/{{WEBTEST_PLAN_NAME}}.md` +- 結果として返すのは**マーカー+ファイルパス+行数のみ**(生成内容は返さない) + +## 生成パラメータ + +- **webtest plan 名**: {{WEBTEST_PLAN_NAME}} +- **target-url**: {{TARGET_URL}} +- **draft**: {{DRAFT_FLAG}} +- **モード**: {{MODE}} + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から生成してください: + +### 設計結果(Phase 3 の出力。このファイルから `{{WEBTEST_PLAN_NAME}}` のセクションを探して使用する) + +{{DESIGN_RESULT_PATH}} + +### タスクサマリー + +{{TASK_SUMMARY_PATH}} + +### UI 要素情報(Phase 2b の結果、ない場合は「なし」) + +{{EXPLORE_CODE_RESULT_PATH}} + +### webtest plan 出力フォーマット + +{{WEBTEST_PLAN_FORMAT_PATH}} + +### acceptance-criteria.md(Full-spec 時のみ、Lightweight 時は「なし」) + +{{ACCEPTANCE_CRITERIA_PATH}} + +## 信号機ガイドライン + +{{SIGNAL_GUIDELINES}} + +## 生成ルール + +### 1. フロントマターの生成 + +設計結果のフロントマター定義をそのまま使用する。以下のフィールドが必須: + +- `name`: webtest plan 名 +- `target-url`: テスト対象 URL +- `status`: `pending`(初期値) +- `draft`: 設計の判定結果 +- `source-plan`: dev-plan 名 +- `source-tasks`: 関連タスク ID 配列 + +Full-spec 時は追加: +- `source-acs`: 関連 AC ID 配列 + +### 2. APIデータセットアップ/クリーンアップの生成 + +設計結果のAPIセットアップ/クリーンアップ定義に従い、以下の構造で生成する: + +```markdown +## APIデータセットアップ + +### ファイル共通 + +<!-- 🟡 source: task-001 Files(コード探索で確認) --> +```bash +# テストユーザー作成 +curl -X POST http://app:8080/api/users \ + -H 'Content-Type: application/json' \ + -d '{"email":"test@example.com","password":"Test1234!","role":"user"}' +``` + +### シナリオN固有 + +<!-- 🔵 source: AC-003 Given --> +```bash +# 注文データ作成(シナリオ3: 注文履歴表示 の前提) +curl -X POST http://app:8080/api/orders \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ${TOKEN}' \ + -d '{"item_id":1,"quantity":2}' +``` + +## APIクリーンアップ + +<!-- 🟡 source: task-001 Files(コード探索で確認) --> +```bash +# テストユーザー削除 +curl -X DELETE http://app:8080/api/users/test@example.com \ + -H 'Authorization: Bearer ${ADMIN_TOKEN}' +``` +``` + +#### curlコマンド生成ルール + +- HTTP メソッド、パス、ヘッダー、ボディを実行可能な形で記述する +- ベースURLは frontmatter の `target-url` のホスト部分に合わせる(例: `http://app:8080`) +- 認証トークンが必要な場合は `${TOKEN}` 等のプレースホルダを使用する +- トークン取得が必要な場合はファイル共通セットアップの最初にログインAPIを記述する: + ```bash + # ログインしてトークン取得 + TOKEN=$(curl -s -X POST http://app:8080/api/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"email":"test@example.com","password":"Test1234!"}' | jq -r '.token') + ``` +- draft: true 時は推定APIエンドポイントにコメントで `# (推定)エンドポイント未確認` を付記する +- クリーンアップはセットアップの逆順で記述する +- 各コマンドの直前に信号機コメントを付与する +- JSON ボディは最小限のフィールドとする + +### 3. シナリオの生成 + +設計結果のシナリオ詳細に従い、以下の構造で生成する: + +```markdown +<!-- 🔵 source: AC-001 --> +### シナリオN: <シナリオ名> + +**group**: <グループ名> +**depends**: [<依存シナリオ名>] + +**手順**: +1. <具体的な操作> +2. <具体的な操作> + +**期待結果**: +- [ ] <確認項目> +- [ ] <確認項目> + +**視覚チェックポイント**: +- [ ] <確認項目> +``` + +#### group / depends の設定ルール + +- 同一URLで状態を変更するシナリオ(ログイン→操作→確認)は同一 group にする +- 異なるURLを対象とする独立したシナリオは別 group にする(または group を省略して独立グループ扱い) +- 読み取り専用のシナリオ(表示確認のみ)は group を省略して並列化を最大化する +- depends には同一グループ内で先に完了すべきシナリオ名を配列で指定する +- depends が空の場合は `[]` と記述する + +#### 手順の記述ルール + +- 操作対象の要素は **UI に表示されるテキストや役割** で記述する +- CSS セレクタは使用しない +- 具体的なテストデータ(メールアドレス、パスワード等)を記載する +- draft: true 時、推定した UI 要素名には `(推定)` を付記する + +#### 期待結果の記述ルール + +- 具体的な表示テキストを記述する +- 状態の変化を明記する +- 「正しく動く」のような曖昧な表現は避ける +- チェックボックス形式 `- [ ]` で記述する + +#### 視覚チェックポイントの記述ルール + +- レイアウト崩れ、フォント、色、画像の表示を確認 +- API エンドポイントのテストの場合は「(JSON APIのためスキップ)」と記載 + +### 4. アクセシビリティ確認項目の生成 + +以下の標準項目を含める: + +```markdown +## アクセシビリティ確認項目 + +- [ ] 画像にalt属性が設定されている +- [ ] フォーム要素にlabelが紐づいている +- [ ] キーボードのみで操作可能 +- [ ] フォーカスが視覚的に分かる +- [ ] コントラスト比がWCAG AA基準を満たす +- [ ] heading要素が正しい階層構造になっている +``` + +画面に特有の要素がある場合は追加する。 + +### 5. レスポンシブ確認の生成 + +フロントマターの viewports に基づいて記述する: + +```markdown +## レスポンシブ確認 + +- [ ] モバイル (375x667): ナビゲーション、レイアウト、タッチターゲット +- [ ] タブレット (768x1024): グリッド、サイドバー +- [ ] デスクトップ (1280x800): フルレイアウト +``` + +### 6. フォームバリデーション確認の生成 + +設計結果のフォームバリデーション確認テーブルに従って生成する。 +フォームが存在しない場合はセクション自体を省略する。 + +### 7. トレーサビリティセクションの生成 + +全シナリオの信号機・ソース・根拠をテーブルにまとめる: + +```markdown +## トレーサビリティ + +| シナリオ | 信号 | ソース | 根拠 | +|---------|------|--------|------| +``` + +### 8. 行数チェック + +生成後、ファイルの行数を確認する: + +```bash +wc -l "$(git rev-parse --show-toplevel)/docs/dev/webtests/plans/{{WEBTEST_PLAN_NAME}}.md" +``` + +500行を超える場合はシナリオを分割して複数ファイルにする。 + +## ファイル出力 + +1. 出力ディレクトリの確認・作成: + ```bash + mkdir -p "$(git rev-parse --show-toplevel)/docs/dev/webtests/plans" + ``` + +2. Write ツールでファイルを生成する + +3. 行数を確認する + +## 結果マーカー + +**生成内容やファイルの中身は返さないこと。返却するのは以下のみ:** + +- 生成完了時: + ``` + 生成完了: docs/dev/webtests/plans/<name>.md (N行) + GENERATE_SUCCESS + ``` +- 生成失敗時: 理由と共に `GENERATE_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/lightweight-inference-guide.md b/skills/dev-webtest-plan/references/lightweight-inference-guide.md new file mode 100644 index 0000000..bf39657 --- /dev/null +++ b/skills/dev-webtest-plan/references/lightweight-inference-guide.md @@ -0,0 +1,202 @@ +# Lightweight モード シナリオ推論ガイド + +Lightweight モード(acceptance-criteria.md が存在しない場合)において、タスクファイルの情報から webtest シナリオを推論するためのガイド。 + +--- + +## 推論の情報源と優先順位 + +Lightweight モードでは以下の情報源を優先順位順に使用する: + +| 優先順位 | 情報源 | セクション | 信号 | +|---------|--------|-----------|------| +| 1 | タスクファイル | Test Strategy | 🟡 | +| 2 | タスクファイル | Goal | 🟡 | +| 3 | タスクファイル | Files | 🟡 | +| 4 | plan.md | Requirements Summary / Design Overview | 🟡 | +| 5 | 実装コード | HTML/テンプレート/ルーティング | 🟡(コード確認時) | +| 6 | Web テストベストプラクティス | — | 🔴 | + +**重要**: Lightweight モードでは 🔵 は付与しない(AC による直接的な根拠がないため)。 + +--- + +## タスクファイルからの推論ルール + +### Test Strategy → シナリオ + +タスクの Test Strategy の各項目を画面テストの観点に変換する: + +| Test Strategy の記述パターン | 推論するシナリオ | +|---------------------------|---------------| +| 「X を入力すると Y が返る」 | フォーム入力 → 結果表示のシナリオ | +| 「X のバリデーションエラー」 | フォームバリデーション確認テーブルに追加 | +| 「X ページが表示される」 | ページアクセス → 表示確認のシナリオ | +| 「X をクリックすると Y に遷移」 | ナビゲーション確認のシナリオ | +| 「X の一覧が表示される」 | 一覧表示 → データ確認のシナリオ | +| 「X を削除すると一覧から消える」 | 削除操作 → 一覧更新確認のシナリオ | +| 「認証エラー時に 401 が返る」 | 未認証アクセス → エラー画面表示のシナリオ | + +**変換例**: + +タスク Test Strategy: +``` +- [ ] 有効なメール+パスワードでログインするとAuthResultが返る +- [ ] 無効なパスワードでログインするとAuthErrorが投げられる +- [ ] 空文字のメールでログインするとValidationErrorが投げられる +``` + +推論シナリオ: +```markdown +<!-- 🟡 source: task-002 Test Strategy --> +### シナリオ1: 正常なログイン +**手順**: ... +**期待結果**: ログイン後の画面に遷移する + +<!-- 🟡 source: task-002 Test Strategy --> +### シナリオ2: パスワード誤りでログイン失敗 +**手順**: ... +**期待結果**: エラーメッセージが表示される + +<!-- 🟡 source: task-002 Test Strategy --> +### シナリオ3: メールアドレス空でバリデーションエラー +**手順**: ... +**期待結果**: バリデーションエラーが表示される +``` + +### Goal → シナリオの方向性 + +Goal が提供する情報は、シナリオ全体の方向性の決定に使う: + +| Goal の記述パターン | 推論方向 | +|------------------|---------| +| 「X 画面を実装する」 | その画面の表示・操作テスト | +| 「X 機能を追加する」 | 機能の正常系・異常系テスト | +| 「X を修正する」 | 修正後の動作確認テスト | +| 「X の API を実装する」 | API に対応する画面があればテスト、なければスキップ | + +### Files → target-url の推定 + +Files セクションから画面の URL を推定する: + +| Files のパターン | URL 推定 | +|----------------|---------| +| `internal/handler/auth.go` | `/login`, `/register`, `/logout` | +| `internal/handler/user.go` | `/users`, `/users/:id` | +| `templates/pages/dashboard.templ` | `/dashboard` | +| `templates/pages/settings.templ` | `/settings` | +| `static/js/form-validation.js` | フォームを含むページ | + +**推定ルール**: +1. ハンドラーファイルのルーティング定義を推定 +2. テンプレートファイル名からパスを推定 +3. 複数候補がある場合は最も一般的なパスを選択し `(推定)` を付記 + +--- + +## 画面が存在するかの判定 + +タスクが画面に関係するかを判定する基準: + +### 画面関連と判定するパターン + +- Files に `templates/`, `views/`, `pages/` を含むファイルがある +- Files に `static/css/`, `static/js/` を含むファイルがある +- Files に `handler/` を含むファイルがある(API専用ハンドラーを除く) +- Goal に「画面」「ページ」「フォーム」「表示」「UI」のキーワードがある +- Test Strategy に「表示される」「クリック」「入力」のキーワードがある + +### 画面関連でないと判定するパターン + +- Files が `internal/service/`, `internal/repository/` のみ +- Goal が「API」「バッチ」「マイグレーション」「CLI」に関するもの +- Test Strategy が「返る」「投げられる」のみで画面操作を含まない + +画面関連でないタスクは webtest plan の対象外としてスキップする。 + +--- + +## ベストプラクティスによる補完(🔴) + +前工程に根拠がない場合でも、Web テストとして推奨されるシナリオを 🔴 で追加する: + +### 追加を検討するシナリオ + +| カテゴリ | シナリオ | 追加条件 | +|---------|---------|---------| +| セキュリティ | XSS 入力テスト | フォームが存在する場合 | +| セキュリティ | 未認証アクセス拒否 | 認証が必要なページの場合 | +| エラーハンドリング | 404 ページ表示 | ルーティングが存在する場合 | +| エラーハンドリング | サーバーエラー時の表示 | フォーム送信がある場合 | +| アクセシビリティ | キーボード操作 | すべてのページ | +| レスポンシブ | モバイル表示 | すべてのページ | + +### 追加しないシナリオ + +- タスクのスコープ外の画面に関するテスト +- 他の webtest plan で既にカバーされているテスト +- インフラ・DB レベルの障害テスト + +--- + +## APIセットアップ/クリーンアップの推論 + +Lightweight モードでもタスク情報からAPIセットアップ/クリーンアップを推論する。 + +### 推論の情報源と優先順位 + +| 優先順位 | 情報源 | 推論内容 | 信号 | +|---------|--------|---------|------| +| 1 | タスクファイル Interfaces | API型定義からエンドポイント・ボディを推定 | 🔴 | +| 2 | タスクファイル Files | handler/route ファイルからエンドポイントを推定 | 🔴 | +| 3 | タスクファイル Test Strategy | テスト前提のデータ要件を推定 | 🔴 | +| 4 | 実装コード(Phase 2b) | ルーティング定義から確認済みエンドポイントを取得 | 🟡 | +| 5 | 既存API仕様(自動探索) | openapi.yaml等から確認済みエンドポイントを取得 | 🔵(仕様確認時のみ) | + +**重要**: Lightweight モードでは情報源 1-3 のみの場合は 🔴 が主体となる。コード探索やAPI仕様で確認できた場合のみ 🟡/🔵 に昇格する。 + +### タスク情報からのAPI推論パターン + +| タスク情報のパターン | 推論するAPIセットアップ | +|-------------------|---------------------| +| Goal「ユーザー管理画面を実装」+ Files に handler/user.go | POST /api/users でテストユーザー作成 | +| Test Strategy「一覧にデータが表示される」 | 対象リソースの作成APIで複数件データ登録 | +| Test Strategy「削除すると一覧から消える」 | 削除対象データの事前作成API | +| Goal「注文フローを実装」+ Interfaces に Order型 | POST /api/orders で注文データ作成 | +| Test Strategy「ログイン成功」+ Files に handler/auth.go | POST /api/users でテストユーザー作成(セットアップ)+ POST /api/auth/login でトークン取得 | + +### Files からのAPIエンドポイント推定 + +| Files のパターン | 推定エンドポイント | +|----------------|----------------| +| `internal/handler/user.go` | GET/POST/PUT/DELETE /api/users | +| `internal/handler/auth.go` | POST /api/auth/login, POST /api/auth/logout | +| `internal/handler/order.go` | GET/POST/PUT/DELETE /api/orders | +| `src/routes/api/products.ts` | GET/POST/PUT/DELETE /api/products | + +### クリーンアップの推論 + +セットアップで作成したリソースに対応するDELETEエンドポイントを推論する: + +- POST /api/users → DELETE /api/users/:id(or /api/users/:email) +- POST /api/orders → DELETE /api/orders/:id +- DELETEエンドポイントが不明な場合はコメントで `# TODO: 適切なクリーンアップAPIを確認` を記載 + +### API仕様の自動探索 + +以下のパスを自動探索し、存在する場合はAPI情報源として使用する: + +``` +openapi.yaml, openapi.json +swagger.yaml, swagger.json +docs/api/*, api-docs/* +*.openapi.yaml, *.swagger.json +``` + +## draft: true 時の注意事項 + +Lightweight モードかつ実装コード未確認の場合は `draft: true` となる: + +- UI 要素名は推定値を使用し `(推定)` を付記する +- URL は Files セクションからの推定値を使用する +- 「dev-impl 完了後に `/dev-webtest-plan` を再実行して draft: false に更新してください」と完了レポートに記載する diff --git a/skills/dev-webtest-plan/references/update-analyze-prompt-template.md b/skills/dev-webtest-plan/references/update-analyze-prompt-template.md new file mode 100644 index 0000000..59f40e7 --- /dev/null +++ b/skills/dev-webtest-plan/references/update-analyze-prompt-template.md @@ -0,0 +1,185 @@ +# 変更分析 サブエージェント プロンプトテンプレート + +dev-webtest-plan(差分更新モード)がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web テスト計画の変更分析アナリストです。画面仕様ドキュメント(Screen Spec)の変更と既存テスト計画を比較し、追加・修正・削除が必要なテストケースを特定してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- コード探索は Glob, Grep, Read を直接使用すること +- 分析結果はテキストで出力せず、**中間ファイルに Write** すること +- 結果として返すのは**マーカー+ファイルパス+行数のみ** + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から分析してください: + +### 既存テスト計画 + +{{WEBTEST_PLAN_PATH}} + +### 変更のあった画面仕様ファイル + +{{CHANGED_SCREEN_SPEC_PATHS}} + +### 画面一覧・フロー定義 + +{{SCREEN_SPEC_INDEX_PATH}} + +## 中間ファイル出力先 + +{{TMP_DIR}} + +## 分析タスク + +### Step 1: 既存テスト計画の構造把握 + +テスト計画ファイルを Read し、以下を把握する: + +- frontmatter の `target-url`, `screen_spec_commit` 等 +- 全シナリオの一覧(シナリオ番号、シナリオ名、信号機、ソース) +- フォームバリデーション確認テーブルの内容 +- トレーサビリティテーブルの内容 +- APIデータセットアップ/クリーンアップセクションの内容(存在する場合) + +### Step 2: 画面仕様の変更内容の把握 + +変更のあった画面仕様ファイルを Read し、以下のセクションごとに変更内容を特定する: + +- **画面項目**: 追加・変更・削除された項目 +- **バリデーション**: 追加・変更・削除されたルール +- **インタラクション**: 追加・変更・削除されたインタラクション +- **状態**: 追加・変更された状態定義 + +画面仕様の各セクションは独立しているため、セクション単位で変更を判定する。 + +### Step 3: フロー影響判定 + +`_index.md` を Read し、以下を判定する: + +1. 変更された画面が含まれるフローを特定する +2. そのフローに対応するE2Eシナリオが既存テスト計画にあるか確認する +3. フロー定義自体が変更されている場合(遷移先の変更、フロー追加・削除)も検出する +4. 到達不能画面チェックの結果も確認する + +### Step 4: テストケース変更の特定 + +画面仕様の変更内容とテスト計画を突き合わせ、以下の対応マッピングに基づいて変更を特定する: + +| 画面仕様セクション | テスト計画の更新対象 | +|------------------|-------------------| +| 画面項目(追加) | 新規シナリオ追加(要素の表示確認) | +| 画面項目(変更) | 既存シナリオの手順・期待結果を修正 | +| 画面項目(削除) | 該当シナリオを削除 | +| バリデーション(追加) | フォームバリデーション確認テーブルに行追加 + シナリオ追加 | +| バリデーション(変更) | フォームバリデーション確認テーブル更新 + シナリオ修正 | +| バリデーション(削除) | フォームバリデーション確認テーブルから行削除 + シナリオ削除 | +| インタラクション(追加) | 新規シナリオ追加 | +| インタラクション(変更) | 既存シナリオの手順・期待結果を修正 | +| インタラクション(削除) | 該当シナリオを削除 | +| 状態(追加/変更) | 状態遷移テストの追加・修正 | +| フロー定義(追加) | フロー全体のE2Eシナリオを新規追加 | +| フロー定義(変更) | 関連するE2Eシナリオを修正 | +| フロー定義(画面変更) | そのフローのE2Eシナリオ全体を更新対象とする | + +## 出力 + +分析結果を以下のフォーマットで中間ファイルに Write する: + +出力先: `{{TMP_DIR}}/analyze-<plan-name>.md` + +`<plan-name>` はテスト計画の frontmatter の `name` フィールドから取得する。 + +```markdown +# 変更分析: <plan-name> + +## 分析サマリー + +- テスト計画: <plan-name> +- 変更画面仕様: <変更のあった画面仕様ファイル名の一覧> +- 追加: N件 +- 修正: N件 +- 削除: N件 + +## 追加が必要なテストケース + +### 追加1 +- 根拠: <screen_id> の <セクション> に <項目> が追加 +- 提案シナリオ名: <シナリオ名> +- 提案シナリオ概要: <手順と期待結果の概要> +- 信号: 🟡 source: screen-spec update + +### 追加2 +... + +## 修正が必要なテストケース + +### 修正1 +- 対象: シナリオN「<シナリオ名>」 +- 根拠: <screen_id> の <セクション> で <項目> が変更 +- 変更内容: <変更概要(例: ルール変更 8文字→10文字)> + +### 修正2 +... + +## 削除が必要なテストケース + +### 削除1 +- 対象: シナリオN「<シナリオ名>」 +- 根拠: <screen_id> の <セクション> から <項目> が削除 + +### 削除2 +... + +## フォームバリデーション確認テーブルの変更 + +- 追加行: <フィールド名、ルール、テストパターン> +- 変更行: <フィールド名、変更内容> +- 削除行: <フィールド名> + +## フロー影響 + +- 影響のあるフロー: <フロー名の一覧> +- E2Eシナリオの更新: <更新が必要なE2Eシナリオ名の一覧> +- 到達不能画面の警告: <あれば記載> + +## APIセットアップ/クリーンアップの変更 + +画面仕様の変更がAPIセットアップ/クリーンアップに影響する場合を分析する: + +### セットアップの変更 +- 追加: <新しいシナリオに必要な前提データのAPIセットアップ> +- 修正: <既存セットアップのエンドポイント/ボディの変更> +- 削除: <削除されたシナリオに対応するセットアップ> + +### クリーンアップの変更 +- 追加: <新しいセットアップに対応するクリーンアップ> +- 修正: <既存クリーンアップのエンドポイント変更> +- 削除: <不要になったクリーンアップ> + +変更判定のルール: +- シナリオが追加される場合 → そのシナリオに必要な前提データのセットアップを追加提案 +- シナリオが削除される場合 → そのシナリオ固有のセットアップ/クリーンアップを削除提案 +- 画面項目の変更でAPIボディが変わる場合 → セットアップの修正提案 +- APIセットアップ/クリーンアップセクションが存在しない既存計画 → セクション追加を提案 +``` + +## 結果マーカー + +**すべての出力は中間ファイルに Write すること。返却するのは以下のみ:** + +- 分析完了時: + ``` + 中間ファイル出力完了: + - {{TMP_DIR}}/analyze-<plan-name>.md (N行) + UPDATE_ANALYZE_SUCCESS + ``` +- 分析失敗時: 理由と共に `UPDATE_ANALYZE_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/update-apply-prompt-template.md b/skills/dev-webtest-plan/references/update-apply-prompt-template.md new file mode 100644 index 0000000..251d5d7 --- /dev/null +++ b/skills/dev-webtest-plan/references/update-apply-prompt-template.md @@ -0,0 +1,181 @@ +# テスト計画更新適用 サブエージェント プロンプトテンプレート + +dev-webtest-plan(差分更新モード)がこのテンプレートの `{{PLACEHOLDER}}` を実行時に置換してサブエージェントプロンプトを構築する。 + +## テンプレート + +以下をサブエージェントのプロンプトとして使用する: + +--- + +あなたは Web テスト計画の更新エディターです。変更分析結果に基づいて、既存のテスト計画ファイルをテストケース単位で更新してください。 + +## 重要な制約 + +- **Task ツールは使用禁止**(サブエージェントを起動できません) +- **TodoWrite は使用禁止** +- 更新するファイルは **500行以内** に収めること +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 結果として返すのは**マーカー+ファイルパス+行数のみ**(更新内容は返さない) + +## 入力データ(ファイルパス) + +以下のファイルを **Read で読み込んで** から更新してください: + +### 既存テスト計画(更新対象) + +{{WEBTEST_PLAN_PATH}} + +### 変更分析結果(Phase 2 の出力) + +{{ANALYZE_RESULT_PATH}} + +### 変更のあった画面仕様ファイル(詳細参照用) + +{{CHANGED_SCREEN_SPEC_PATHS}} + +### webtest plan 出力フォーマット + +{{WEBTEST_PLAN_FORMAT_PATH}} + +## 更新ルール + +### 1. frontmatter の更新 + +既存の frontmatter に以下のフィールドを追加・更新する: + +```yaml +--- +# ... 既存フィールドはそのまま維持 ... +screen_spec_commit: <画面仕様の最新 last_synced_commit> +last_updated: "<本日の日付 YYYY-MM-DD>" +update_history: + - date: "<本日の日付>" + changes: "+N ~N -N" + source: "screen-spec update" + # 既存の履歴は直近3回まで保持(古いものから削除) +--- +``` + +### 2. シナリオの追加 + +分析結果の「追加が必要なテストケース」に従い、新しいシナリオを追加する: + +- シナリオ番号は既存の最後のシナリオの次番号から採番する +- 信号機コメントは `<!-- 🟡 source: screen-spec update -->` を付与する +- 手順・期待結果・視覚チェックポイントは画面仕様の該当セクションを参照して具体的に記述する +- 操作対象の要素は **UI に表示されるテキストや役割** で記述する(CSS セレクタは不要) +- 具体的なテストデータ(メールアドレス、パスワード等)を記載する + +```markdown +<!-- 🟡 source: screen-spec update --> +### シナリオN: <シナリオ名> + +**手順**: +1. <具体的な操作> +2. <具体的な操作> + +**期待結果**: +- [ ] <確認項目> + +**視覚チェックポイント**: +- [ ] <確認項目> +``` + +### 3. シナリオの修正 + +分析結果の「修正が必要なテストケース」に従い、既存シナリオを修正する: + +- シナリオ番号・名前は変更しない(変更内容が名前に影響する場合のみ名前を更新) +- 手順・期待結果・視覚チェックポイントを画面仕様の変更内容に合わせて更新する +- **既存の信号機コメントはそのまま維持する**(修正しても信号は変えない) +- 修正箇所の直後に以下のコメントを追加する: + ```markdown + <!-- updated: screen-spec update (<変更概要>) --> + ``` + +### 4. シナリオの削除 + +分析結果の「削除が必要なテストケース」に従い、該当シナリオを削除する: + +- シナリオ全体(信号機コメント、見出し、手順、期待結果、視覚チェックポイント)を削除する +- 削除後、残りのシナリオの番号は振り直さない(欠番を許容する) +- トレーサビリティテーブルからも該当行を削除する + +### 5. フォームバリデーション確認テーブルの更新 + +分析結果の「フォームバリデーション確認テーブルの変更」に従い、テーブルを更新する: + +- 追加行: 画面仕様のバリデーションセクションを参照して具体的に記述する +- 変更行: 既存の行を画面仕様の変更内容に合わせて更新する +- 削除行: 該当行を削除する + +### 6. APIセットアップ/クリーンアップの更新 + +分析結果の「APIセットアップ/クリーンアップの変更」に従い、セクションを更新する: + +#### セットアップの追加 +- 新しいシナリオ固有セットアップを「## APIデータセットアップ」セクション末尾に追加する +- 信号機コメントは `<!-- 🟡 source: screen-spec update -->` を付与する +- curl コマンドは実行可能な形で記述する + +#### セットアップの修正 +- 既存の curl コマンドのエンドポイント/ボディを更新する +- 修正箇所の直後に `<!-- updated: screen-spec update (<変更概要>) -->` コメントを追加する + +#### セットアップの削除 +- 削除されたシナリオに対応するシナリオ固有セットアップを削除する +- ファイル共通セットアップは、参照するシナリオが残っている限り削除しない + +#### クリーンアップの更新 +- セットアップの追加に対応するクリーンアップを追加する +- 削除されたセットアップに対応するクリーンアップを削除する +- 実行順序(依存関係の逆順)を維持する + +#### セクション新規追加 +- 既存計画にAPIセットアップ/クリーンアップセクションが存在しない場合で、分析結果に追加提案がある場合は、「## 前提条件」の直後に新しいセクションを追加する + +### 7. E2Eシナリオの更新 + +分析結果の「フロー影響」に記載がある場合: + +- フロー全体のE2Eシナリオを画面仕様のフロー定義に合わせて更新する +- フロー内の画面が変更された場合、その画面に関する手順・期待結果を更新する +- 新規フローがある場合はE2Eシナリオを追加する +- 削除されたフローがある場合は該当E2Eシナリオを削除する +- 到達不能画面の警告がある場合、該当シナリオに ⚠️ コメントを付与する + +### 8. トレーサビリティテーブルの更新 + +シナリオの追加・修正・削除に合わせてトレーサビリティテーブルも更新する: + +- 追加シナリオ: `🟡 | screen-spec update | <画面仕様セクション>の<変更種別>に対応` を追加 +- 修正シナリオ: 既存の行はそのまま維持(信号・ソースは変えない) +- 削除シナリオ: 該当行を削除 + +### 9. 行数チェック + +更新後、ファイルの行数を確認する: + +```bash +wc -l "{{WEBTEST_PLAN_PATH}}" +``` + +500行を超える場合はシナリオを分割して別ファイルにする。 + +## ファイル出力 + +1. 既存のテスト計画ファイルを上書き更新する(Edit ツールまたは Write ツールを使用) +2. 行数を確認する + +## 結果マーカー + +**更新内容やファイルの中身は返さないこと。返却するのは以下のみ:** + +- 更新完了時: + ``` + 更新完了: <webtest-plan-path> (N行) + 変更サマリー: +<追加数> ~<修正数> -<削除数> (合計シナリオ: N) + UPDATE_APPLY_SUCCESS + ``` +- 更新失敗時: 理由と共に `UPDATE_APPLY_FAILED` を出力する diff --git a/skills/dev-webtest-plan/references/webtest-plan-format.md b/skills/dev-webtest-plan/references/webtest-plan-format.md new file mode 100644 index 0000000..8082d3f --- /dev/null +++ b/skills/dev-webtest-plan/references/webtest-plan-format.md @@ -0,0 +1,299 @@ +# Webtest Plan 出力フォーマット定義 + +dev-webtest-plan が生成する webtest plan ファイルのフォーマット定義。 +dev-webtest の test-plan-template.md を基盤とし、トレーサビリティ情報を拡張する。 + +出力先: `docs/dev/webtests/plans/<webtest-plan-name>.md` + +--- + +## フロントマター + +```yaml +--- +name: <webtest-plan-name> +target-url: http://app:8080/<path> +status: pending +last-run: +draft: true +source-plan: <dev-plan-name> +source-acs: [AC-001, AC-002] +source-tasks: ["001", "003"] +viewports: + - 375x667 + - 768x1024 + - 1280x800 +--- +``` + +| フィールド | 必須 | 説明 | +|-----------|------|------| +| name | Yes | webtest plan の名前(ケバブケース) | +| target-url | Yes | テスト対象のベースURL | +| status | Yes | `pending` → `in_progress` → `done` | +| last-run | No | 最後に実行した日付(dev-webtest が自動更新) | +| draft | Yes | `true`: dev-impl前(UI要素未確定)、`false`: dev-impl後(実装コード確認済み) | +| source-plan | Yes | 生成元の dev-plan 名 | +| source-acs | No | Full-spec 時、対応する AC ID の配列(Lightweight 時は省略) | +| source-tasks | Yes | 対応するタスク ID の配列 | +| viewports | No | レスポンシブテストのビューポート(省略時はデフォルト3種) | + +### draft フラグの運用 + +- `draft: true`: dev-impl 前に生成。UI要素名・URL が推定ベース(🟡/🔴 が多い) +- `draft: false`: dev-impl 後に再生成または更新。実装コードから UI 要素を確認済み(🔵 が多い) +- dev-webtest-plan 再実行時に `draft: true` → `false` に更新可能 + +--- + +## 本文構造 + +```markdown +# <webtest-plan-name> + +<テスト計画の概要(1-2文)> + +## 前提条件 + +- [テスト前に必要な状態やデータの説明] +- [必要なログイン情報やテストデータ] +- [Docker環境の起動状態] + +## APIデータセットアップ + +テストシナリオ実行前に、API経由で前提データを登録する手順。 +dev-webtest がシナリオ実行前に自動的にこのセクションのコマンドを実行する。 + +### ファイル共通 + +全シナリオで共有する前提データの登録手順。シナリオ実行前に1回だけ実行される。 + +<!-- 🟡 source: task-001 Files(コード探索で確認) --> +```bash +# テストユーザー作成 +curl -X POST http://app:8080/api/users \ + -H 'Content-Type: application/json' \ + -d '{"email":"test@example.com","password":"Test1234!","role":"user"}' +``` + +### シナリオN固有 + +特定のシナリオでのみ必要な前提データ。該当シナリオの直前に実行される。 + +<!-- 🔵 source: AC-003 Given --> +```bash +# 注文データ作成(シナリオ3: 注文履歴表示 の前提) +curl -X POST http://app:8080/api/orders \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ${TOKEN}' \ + -d '{"item_id":1,"quantity":2}' +``` + +## APIクリーンアップ + +全シナリオ完了後に、テストで作成したデータを削除する手順。 +dev-webtest が全シナリオ完了後に自動的にこのセクションのコマンドを実行する。 +実行順序はセットアップの逆順(依存関係を考慮)。 + +<!-- 🟡 source: task-001 Files(コード探索で確認) --> +```bash +# テストユーザー削除 +curl -X DELETE http://app:8080/api/users/test@example.com \ + -H 'Authorization: Bearer ${ADMIN_TOKEN}' +``` + +## テストシナリオ + +<!-- 🔵 source: AC-001 --> +### シナリオ1: <シナリオ名> + +**group**: <グループ名> +**depends**: [] + +**手順**: +1. `<URL>` にアクセスする +2. `<要素の説明>` に `<値>` を入力する +3. `<ボタンの説明>` をクリックする +4. ページが遷移することを確認する + +**期待結果**: +- [ ] <画面に表示されるべきテキストや状態> +- [ ] <データの変更結果> +- [ ] <エラーメッセージ(エラーケースの場合)> + +**視覚チェックポイント**: +- [ ] レイアウトが崩れていないか +- [ ] フォントサイズ・色が適切か + +<!-- 🟡 source: task-003 Test Strategy --> +### シナリオ2: <エラーケース> + +**group**: <グループ名> +**depends**: [シナリオ1] + +**手順**: +1. ... + +**期待結果**: +- [ ] エラーメッセージが表示される + +## アクセシビリティ確認項目 + +- [ ] 画像にalt属性が設定されている +- [ ] フォーム要素にlabelが紐づいている +- [ ] キーボードのみで操作可能 +- [ ] フォーカスが視覚的に分かる +- [ ] コントラスト比がWCAG AA基準を満たす +- [ ] heading要素が正しい階層構造になっている + +## レスポンシブ確認 + +- [ ] モバイル (375x667): ナビゲーション、レイアウト、タッチターゲット +- [ ] タブレット (768x1024): グリッド、サイドバー +- [ ] デスクトップ (1280x800): フルレイアウト + +## フォームバリデーション確認 + +### <フォーム名> + +| フィールド | type | required | テストパターン | +|-----------|------|----------|-------------| +| メール | email | Yes | 空, 不正形式, 正常 | +| パスワード | password | Yes | 空, 短すぎ, 正常 | + +## トレーサビリティ + +| シナリオ | 信号 | ソース | 根拠 | +|---------|------|--------|------| +| シナリオ1 | 🔵 | AC-001 | Given/When/Then から直接変換 | +| シナリオ2 | 🟡 | task-003 | Test Strategy から推論 | +| シナリオ3 | 🔴 | — | Web テストベストプラクティス | +``` + +--- + +## APIセットアップ/クリーンアップの記述ルール + +### 情報源の優先順位 + +API エンドポイントの特定には以下の優先順位で情報源を使用する: + +| 優先順位 | 情報源 | 信号 | 説明 | +|---------|--------|------|------| +| 1 | dev-plan(タスクファイル) | 🔴 | Interfaces / Files / Test Strategy からエンドポイントを推定 | +| 2 | 実装コード探索 | 🟡 | ルーティング定義・ハンドラーからエンドポイントを確認 | +| 3 | 既存API仕様(OpenAPI等) | 🔵 | openapi.yaml / swagger.json 等で仕様を確認済み | + +### curlコマンドの記述規則 + +- HTTP メソッド、パス、ヘッダー、ボディを具体的に記述する(dev-webtest がそのまま実行可能) +- 認証トークンが必要な場合は `${TOKEN}` や `${ADMIN_TOKEN}` のプレースホルダを使用する +- トークン取得が必要な場合は、ファイル共通セットアップの最初にログインAPIを記述し、レスポンスからトークンを取得する手順を含める +- ベースURLは frontmatter の `target-url` のホスト部分と合わせる(例: `http://app:8080`) +- JSON ボディは最小限のフィールドで、テストに必要十分なデータとする +- `draft: true` 時は推定APIエンドポイントに `(推定)` をコメントで付記する + +### クリーンアップの記述規則 + +- セットアップで作成したデータを DELETE エンドポイントまたはリセット API で削除する +- 実行順序はセットアップの逆順を基本とする(依存関係を考慮) +- DELETE エンドポイントが存在しない場合は、利用可能なリセット手段を記述する +- クリーンアップに失敗しても後続のテストに影響しないよう、各コマンドは独立して実行可能にする + +### シナリオ固有セットアップの紐づけ + +- 「### シナリオN固有」の見出しで、対象シナリオ名をコメントで明記する +- 1つのセットアップが複数シナリオに必要な場合は「ファイル共通」に配置する +- シナリオ固有セットアップは該当シナリオの `depends` に影響しない(APIセットアップはシナリオ実行前に自動処理される) + +## トレーサビリティコメント + +各シナリオの直前に HTML コメントで信号機とソースを記載する: + +```markdown +<!-- 🔵 source: AC-001 --> +### シナリオ1: ログイン成功 + +<!-- 🟡 source: task-003 Test Strategy --> +### シナリオ2: 入力バリデーション + +<!-- 🔴 source: AI-inferred (form security) --> +### シナリオ3: XSS防御確認 +``` + +--- + +## 信号機基準 + +| 信号 | 基準 | 例 | +|------|------|-----| +| 🔵 | AC の Given/When/Then から直接変換、requirements.md の明示的要件に基づく | AC-001 の When を手順に、Then を期待結果にマッピング | +| 🟡 | タスクの Test Strategy から推論、一般的 Web テストベストプラクティス | タスクの「フォーム送信テスト」から画面テストシナリオを推論 | +| 🔴 | 前工程に根拠なし、AI が Web テストとして必要と判断した項目 | セキュリティテスト、エッジケースの追加 | + +--- + +## シナリオの書き方ルール + +### 手順の記述 + +- 操作対象の要素は **UI に表示されるテキストや役割** で記述する(CSS セレクタは不要) +- Playwright CLI が snapshot から自動的に要素を特定する +- 曖昧さを避けるため、ページ上の位置も補足する + +**良い例**: +``` +1. ページ上部の「ログイン」リンクをクリックする +2. 「メールアドレス」入力欄に "test@example.com" を入力する +3. 「ログイン」ボタンをクリックする +``` + +**悪い例**: +``` +1. #login-link をクリック +2. input[name=email] に入力 +``` + +### 期待結果の記述 + +- 具体的な表示テキストを記述する +- 状態の変化を明記する +- 「正しく動く」のような曖昧な表現は避ける + +**良い例**: +``` +- [ ] ダッシュボードページに遷移する +- [ ] 「ようこそ、テストユーザーさん」と表示される +``` + +**悪い例**: +``` +- [ ] ログインが成功する +- [ ] 正しいページが表示される +``` + +--- + +## 並列実行制御(group / depends) + +各シナリオに `group` と `depends` を指定し、dev-webtest の並列実行を最適化する。 + +| フィールド | 必須 | 説明 | +|-----------|------|------| +| group | No | シナリオのグループ名。同一グループ内は直列実行。異なるグループは並列実行可能。省略時はシナリオ単独で独立グループ扱い | +| depends | No | 同一グループ内で先に実行すべきシナリオ名の配列。省略時はグループ内の記述順 | + +**グループ設計の指針**: +- 同一URLで状態を変更するシナリオ(ログイン→操作→確認)は同一グループにする +- 異なるURLを対象とする独立したシナリオは別グループ(または group 省略)にする +- 読み取り専用のシナリオ(表示確認のみ)は group を省略して並列化を最大化する + +--- + +## 制約 + +- 1ファイル 500 行以内(超過時はシナリオを分割して別ファイルにする) +- フロントマターの `source-plan` は必ず設定する +- `draft: true` 時は UI 要素名に `(推定)` を付記し、dev-impl 後の更新を促す +- dev-webtest の test-plan-template.md と互換性を維持する(dev-webtest がそのまま実行可能) +- 各シナリオに `group` / `depends` を設定し、並列実行の最適化を考慮する diff --git a/skills/dev-webtest/SKILL.md b/skills/dev-webtest/SKILL.md new file mode 100644 index 0000000..f40e7e4 --- /dev/null +++ b/skills/dev-webtest/SKILL.md @@ -0,0 +1,551 @@ +--- +name: dev-webtest +description: This skill should be used when the user asks to "dev-webtest", "Webテスト", "画面の動作確認", "E2Eテスト", "web test", "visual check", "モンキーテスト", "アクセシビリティチェック", "レスポンシブテスト", "フォームテスト". Playwright CLIを使ってWebアプリの動作確認・視覚テスト・アクセシビリティ・レスポンシブ・フォームバリデーションを実行し、問題を検出・記録する。 +argument-hint: '<plan-name> [--parallel N] | monkey <url> | check <url> | retest' +--- + +# Dev Webtest + +Playwright CLI (`@playwright/cli`) を使ったWebアプリケーションの動作確認・視覚テスト・記録スキル。計画テスト、モンキーテスト、視覚チェック、アクセシビリティ、レスポンシブ、フォームバリデーションの6種類のテストを実行し、検出した問題をエラーディレクトリに記録する。修正は dev-debug 等の別スキルに委譲する。 + +## 前提知識 + +### dev-*スキルフロー内の位置 + +``` +dev-context → dev-plan → dev-impl → dev-verify + ↓ + [dev-webtest] + ↓ + dev-debug (問題修正) +``` + +dev-verify でユニットテスト/ビルド/Lintが通った後にWeb画面の動作確認として使用する。単独での使用も可能。 + +### 実行モード + +| モード | 引数 | 用途 | +|-------|------|------| +| 計画テスト | `<plan-name> [--parallel N]` | Markdownテスト計画に沿って自動テスト | +| モンキーテスト | `monkey <url>` | ランダム操作でエラー・崩れを検出 | +| クイックチェック | `check <url>` | 単一ページの視覚・アクセシビリティ確認 | +| プラン選択 | (引数なし) | 利用可能なプラン一覧から選択して実行 | +| 再テスト | `retest` | 未解決エラーの再現手順を再実行し、修正済みなら fixed に更新 | + +### 並列実行オプション + +| オプション | デフォルト | 説明 | +|-----------|-----------|------| +| `--parallel N` | 2 | シナリオグループの最大並列実行数(1〜5) | + +- `--parallel 1` で従来通りの完全直列実行 +- シナリオの `group` フィールドに基づいてグループ化し、異なるグループを並列実行する +- 同一グループ内のシナリオは `depends` 順に直列実行する + +### ツール構成 + +- **メイン**: Playwright CLI — Bash経由でコマンド実行。スナップショット(YAML)とスクリーンショット(PNG)はディスク保存 +- **代替**: Playwright MCP (`@playwright/mcp`) — CLI が利用できない場合のフォールバック。MCP プロトコル経由でブラウザ操作(詳細は `references/mcp-workflow.md`) +- **補助**: Chrome DevTools MCP — パフォーマンストレース、Lighthouse監査、ネットワーク分析(利用可能時のみ) + +## ワークフロー + +### Step 1: 環境準備 + +``` +Step 1 開始 + | +[1-0] docs/dev/webtests/env-knowledge.md を Read(存在する場合) + | → 過去のトラブルシュートを把握し、同じ問題発生時に即座に適用する + | +[1-1] docker compose ps + | + +-- Playwright コンテナ Running --> [1-5] CLI動作確認・モード判定 + | + +-- 未起動 / docker compose 自体が使えない + | +[1-2] docker-compose.yaml の存在 + playwright サービスの定義を確認 + | + +-- yaml あり & playwright サービス定義済み → AskUserQuestion (A0, C, D) + +-- yaml あり & playwright サービス未定義 → AskUserQuestion (A1, C, D) + +-- yaml なし → AskUserQuestion (B, C, D) +``` + +**1-0. 過去の環境セットアップ知見を読み込む** + +`docs/dev/webtests/env-knowledge.md` が存在する場合、Read して内容を把握する。過去のトラブルシュートを参考に、同じ問題が起きた場合は記録済みの解決策を即座に適用する。 + +**1-1. Docker Compose の状態を確認する** + +```bash +docker compose ps +``` + +Playwright コンテナが Running なら **1-5** へ進む。未起動またはコマンド自体が使えない場合は **1-2** へ。 + +**1-2. docker-compose.yaml の存在と playwright サービスの定義を確認する** + +確認結果に応じて AskUserQuestion で環境セットアップ方法を選択してもらう。各状況で **Recommended 付きの選択肢1つ + C + D の3択** になる。 + +| 選択肢 | 表示条件 | 処理 | +|--------|----------|------| +| A0) Playwright コンテナを起動する (Recommended) | yaml あり & playwright 定義済み | `docker compose up -d playwright` → `npm install -g @playwright/cli@latest` → **1-5** へ | +| A1) 既存の docker-compose.yaml に Playwright サービスを追加する (Recommended) | yaml あり & playwright 未定義 | `docker-setup.md` を参照して yaml 編集 → `docker compose up -d playwright` → `npm install -g @playwright/cli@latest` → **1-5** へ | +| B) 新しい docker-compose.yaml を作成する (Recommended) | yaml なし | `docker-setup.md` を参照して yaml 新規作成 → `docker compose up -d playwright` → `npm install -g @playwright/cli@latest` → **1-5** へ | +| C) 手動でセットアップする | 常に表示 | `docker-setup.md` を案内 → ユーザーに完了確認 → **1-5** へ | +| D) Docker を使わずローカル MCP で実行する | 常に表示 | `docker-setup.md` の「ローカル MCP セットアップ」を参照して `.mcp.json` に playwright 設定追加 → `mkdir -p tmp/webtest/screenshots` → `.gitignore` 追記 → **MCP モード確定** → Step 2 へ | + +※ A0/A1/B は排他(状況に応じて1つだけ表示)。 + +**1-5. CLI 動作確認・モード判定**(A0/A1/B/C 選択時のみ) + +```bash +docker compose exec playwright playwright-cli --version +``` + +- 成功 → **CLI モード**(本ドキュメントの手順に従う) +- 失敗 → **MCP モード**(Docker MCP)へフォールバック(`references/mcp-workflow.md` の手順に従う) + +**1-6. 環境セットアップ知見を記録する** + +Step 1 完了時に `docs/dev/webtests/env-knowledge.md` に今回の知見を追記する。 + +- ファイルが存在しない場合は新規作成する(下記フォーマットに従う) +- **成功手順**: 今回実行した環境構築の手順を簡潔に記録する(選択した方式、実行コマンド、確定モード) +- **トラブルシュート**: Step 1 中にエラーが発生し解決した場合、症状・原因・解決策を記録する +- 既に同じ内容が記録済みの場合は追記しない(重複防止) +- 問題なくスムーズに完了した場合、トラブルシュートの追記は不要 + +**env-knowledge.md フォーマット**: + +```markdown +# Webtest 環境セットアップ知見 + +## 成功手順 + +### <YYYY-MM-DD> <モード名>モード確立 +- <実行した手順の要約> +- 所要ステップ: <通過したステップ> + +## トラブルシュート + +### <YYYY-MM-DD> <問題の概要> +- 症状: <エラーメッセージや観察された挙動> +- 原因: <特定された原因> +- 解決: <実行した解決策> +``` + +### Step 2: 引数解析とプラン解決 + +引数に応じてテストモードを切り替える。 + +**引数解析フロー:** + +``` +引数あり? + +-- "retest" → 2d へ + +-- "monkey <url>" → 2b へ + +-- "check <url>" → 2c へ + +-- その他の文字列 → plan-name として解釈 → プラン解決へ + +-- 引数なし → プラン一覧表示へ + +--parallel N が含まれる場合: + → N を抽出し maxParallel に設定(デフォルト: 2、範囲: 1〜5) + → --parallel 部分を引数から除去して上記フローを継続 +``` + +**プラン解決:** + +1. `docs/dev/webtests/plans/` ディレクトリを Glob で走査し、利用可能な `.md` ファイルを一覧取得する +2. 引数が plan-name の場合: + - `docs/dev/webtests/plans/<plan-name>.md` が存在する → 2a へ進む + - 存在しない → 利用可能なプラン一覧を表示し、AskUserQuestion で「実行するプランを選択してください」と提示する(複数選択可)。選択されたプランを 2a で順番に実行する +3. 引数なしの場合: + - プランが1件以上ある → AskUserQuestion でプラン一覧を表示し選択させる(複数選択可)。選択されたプランを 2a で順番に実行する + - プランが0件 → 「`docs/dev/webtests/plans/` にテスト計画がありません。`dev-webtest-plan` でテスト計画を生成するか、`monkey <url>` または `check <url>` で直接テストしてください」と案内する +4. 複数プランが選択された場合、各プランを順番に 2a で実行する。最後に Step 8 で全プランの統合レポートを出力する + +#### 2a: 計画テスト(plan-name 解決済み) + +1. `docs/dev/webtests/plans/<plan-name>.md` を読み込む +2. テスト計画のフォーマットは `references/test-plan-template.md` を参照 +3. テスト計画ファイルの frontmatter を更新する: + - `status` → `in_progress` + - `last-run` → 当日の日付(`YYYY-MM-DD`) +4. `mkdir -p tmp/webtest/results/<plan-name>` で中間結果ディレクトリを作成する +4-1. **APIデータセットアップの実行**(「## APIデータセットアップ」セクションが存在する場合): + +##### ファイル共通セットアップの実行 + +テスト計画の「### ファイル共通」セクション内の curl コマンドを上から順に Docker コンテナ内で実行する: + +```bash +docker compose exec playwright bash -c '<curl コマンド>' +``` + +- トークン取得コマンドがある場合は、レスポンスからトークンを抽出して後続コマンドの `${TOKEN}` 等に展開する +- 各コマンドの実行結果(HTTP ステータスコード)を確認する +- 失敗した場合はエラーを記録し、ユーザーに警告を表示する(テスト自体は継続する) +- セットアップ結果のサマリーを `tmp/webtest/results/<plan-name>/api-setup.md` に記録する + +##### シナリオ固有セットアップの事前パース + +「### シナリオN固有」セクションの内容をパースし、シナリオ名と curl コマンドの対応を記録する。実際の実行は各シナリオの直前に行う(Step 5-3 の Agent 委譲時にシナリオ固有セットアップも渡す)。 + +5. **シナリオをグループ化し、グループ単位で並列実行する**: + +##### 5-1. グループ化 + +シナリオの `group` フィールドに基づいてグループ分けする: +- `group` が同じシナリオは同一グループ(グループ内は `depends` 順に直列実行) +- `group` が未指定のシナリオはそれぞれ独立グループとして扱う(他と並列実行可能) +- `depends` が未指定のシナリオはグループ内の記述順に実行する + +``` +例: 4シナリオ(group: auth×2, group: products×1, group未指定×1) + → グループ: [auth], [products], [シナリオ4] + → maxParallel=2 の場合: [auth] と [products] を並列 → 完了後 [シナリオ4] +``` + +##### 5-2. 並列実行制御 + +- `maxParallel`(デフォルト: 2)に基づき、同時実行するグループ数を制限する +- グループのキューを作成し、空きスロットができたら次のグループを開始する +- 具体的には: maxParallel 個のグループを Agent tool で **同時に起動**(`run_in_background: true`)し、完了通知を受けたら次のグループの Agent を起動する +- `maxParallel: 1` の場合は従来通りの完全直列実行となる + +##### 5-3. Agent 委譲(グループ単位) + +1グループにつき1つの Agent を起動する。Agent にはグループ内の全シナリオを渡し、**グループ内のシナリオは depends 順に直列実行** させる: + + - Agent には以下を伝える: + - 実行モード(CLI / MCP)とセッション情報 + - グループ内の全シナリオの手順・期待結果・視覚チェックポイント(テスト計画から該当部分を抽出) + - 各シナリオのAPIシナリオ固有セットアップ(curl コマンド、存在する場合のみ) + - ファイル共通セットアップで取得したトークン(`${TOKEN}` 等の値) + - 各シナリオの結果の書き出し先: `tmp/webtest/results/<plan-name>/<scenario-index>-<scenario-name>.md` + - エラー時の error.md 作成先: `docs/dev/webtests/errors/` + - snapshot・screenshot の取り扱いルール(後述の「ルール・制約」を参照) + - Agent はグループ内の各シナリオについて以下を実行する: + a-0. シナリオ固有セットアップがある場合、curl コマンドを Docker 内で実行する: + ```bash + docker compose exec playwright bash -c '<curl コマンド>' + ``` + - `${TOKEN}` 等のプレースホルダはファイル共通セットアップで取得した値に展開する + - 失敗した場合はエラーを記録し、シナリオを `skipped` として結果に記録する(次のシナリオに進む) + a. シナリオの手順を実行(Step 2a 操作) + b. Step 3 + Step 4: 視覚チェック + アクセシビリティチェック(**同時実行可能** — どちらも読み取り専用のため。snapshot を取得した時点で Step 3 は screenshot を Read して判定、Step 4 は snapshot を分析。ただし Tab キーボードテストは Step 3 完了後に実行する) + c. Step 5: レスポンシブテスト(viewport 変更を伴うため単独実行) + d. Step 6: フォームバリデーションテスト(ページ状態を変更するため最後に実行) + e. 問題検出時は error.md を作成 + f. 結果を scenario 中間ファイルに書き出す(フォーマットは後述) + - Agent の返却値は「完了。passed/failed(N件中M件成功)。結果ファイルパス一覧」程度の短い文字列とする + - **シナリオが failed でも中断せず、グループ内の次のシナリオを継続する** + +6. 全グループ完了後、**APIクリーンアップを実行する**(「## APIクリーンアップ」セクションが存在する場合): + + テスト計画の「## APIクリーンアップ」セクション内の curl コマンドを上から順に Docker コンテナ内で実行する: + + ```bash + docker compose exec playwright bash -c '<curl コマンド>' + ``` + + - `${TOKEN}` / `${ADMIN_TOKEN}` 等のプレースホルダはセットアップ時に取得した値に展開する + - 各コマンドの実行結果を確認するが、クリーンアップ失敗はエラーとして記録するのみでテスト結果には影響しない + - クリーンアップ結果のサマリーを `tmp/webtest/results/<plan-name>/api-cleanup.md` に記録する + +7. テスト計画ファイルの frontmatter `status` を更新する: + - 全シナリオが passed → `status: done` + - 1つでも failed がある → `status: in_progress` +8. Step 7 → Step 8 に進む + +##### scenario 中間ファイルフォーマット + +Agent が `tmp/webtest/results/<plan-name>/<scenario-index>-<scenario-name>.md` に書き出す: + +```markdown +--- +scenario: "<シナリオ名>" +url: "<テスト対象URL>" +result: passed | failed | skipped +--- +## APIセットアップ: <成功/失敗/なし> +- <セットアップの実行結果(1行。なしの場合は「シナリオ固有セットアップなし」)> + +## シナリオ結果: <passed/failed/skipped> +- <結果の要約(1-2行)> + +## 視覚チェック: <判定> +- <所見(1-2行)> + +## アクセシビリティ: <判定> +- 画像alt: <判定> (N/M) +- フォームラベル: <判定> (N/M) +- Heading階層: <判定> +- キーボード: <判定> Tab到達率 N% (N/M) +- ARIA: <判定> +- ランドマーク: <判定> + +## レスポンシブ: <判定> +- mobile: <判定> <所見> +- tablet: <判定> <所見> +- desktop: <判定> <所見> + +## フォームバリデーション: <判定> +- <パターン>: <判定> | ... + +## 検出エラー +- <error.md へのパス>(エラーがない場合は「なし」) +``` + +#### 2b: モンキーテスト(monkey 指定時) + +1. 指定URLにアクセスする +2. `snapshot` でページ構造を把握する +3. 以下のアクションをランダムに実行する(最大20アクション): + - リンクのクリック + - ボタンのクリック + - フォームへのランダム入力(正常値・異常値・空値・境界値) + - ナビゲーション(戻る・進む) +4. 各アクション後に以下を確認する: + - `snapshot` でページ状態を取得 + - `console` でJavaScriptエラーを確認 + - `network` でHTTPエラー(4xx/5xx)を確認 +5. 問題検出時は `screenshot` を取得する +6. 問題検出時はエラーディレクトリを作成する: + - `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成 + - `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` にスクリーンショットを保存 +7. 同一ドメイン内のみ遷移する。外部リンクはスキップする + +#### 2c: クイックチェック(check 指定時) + +1. 指定URLにアクセスする +2. `screenshot` + `snapshot` を取得する +3. Step 3(視覚チェック)と Step 4(アクセシビリティ)のみ実行する +4. 結果を直接ユーザーに報告する(レポートファイルは作成しない) + +#### 2d: 再テスト(retest 指定時) + +`docs/dev/webtests/errors/` の未解決エラーについて、再現手順を再実行して修正を確認する。 + +1. `docs/dev/webtests/errors/` を Glob で走査し、全 `error.md` を取得する +2. 各 error.md を Read し、frontmatter の `status: open` のものだけ収集する +3. 0件の場合 →「未解決の webtest エラーはありません」と報告して終了 +4. 各エラーを順次再テストする: + a. error.md の `url` にアクセスする + b. 「再現手順」に記載された操作を Playwright で実行する + c. 「期待される状態」と実際の状態を比較する + d. 判定: + - 問題が解消 → error.md の `status` を `open` → `fixed` に更新し、`fixedDate: YYYY-MM-DD` を追記する + - 問題が残存 → `status: open` のまま維持する +5. 全エラーの再テスト完了後、結果を報告する(レポートファイルは作成しない): + - fixed に変更されたエラー一覧 + - まだ open のエラー一覧(あれば) + +### Step 3: 視覚チェック(サブAgent内で実行) + +スクリーンショットを Read tool で読み取り、Claude が視覚的に判断する。判定完了後は画像の内容をテキスト要約に変換し、以降はテキスト要約のみ保持する(画像データはコンテキストから自然に流れる)。 + +**チェック項目**(詳細は `references/visual-check-criteria.md` 参照): +- レイアウト崩れ(要素の重なり、はみ出し、意図しない配置) +- 文字化け・フォント異常 +- 色の異常(コントラスト不足、意図しない色) +- 画像の表示異常(破損、アスペクト比崩れ) +- 余白・マージンの異常 +- ボタン・リンクの視認性 + +**判定**: +- ✅ 問題なし +- ⚠️ 軽微な問題(改善推奨) +- ❌ 重大な問題(修正必須) + +**エラー記録**: ⚠️ または ❌ 判定時はエラーディレクトリを作成する: +- `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成 +- `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` にスクリーンショットを保存 + +### Step 4: アクセシビリティチェック(サブAgent内で実行) + +`snapshot` のアクセシビリティツリーを分析する(詳細は `references/accessibility-checklist.md` 参照): + +1. `img` 要素の `alt` 属性の有無 +2. `form` 要素と `label` の紐づけ +3. ARIA属性の適切な使用 +4. heading要素(h1-h6)の階層構造 +5. キーボード操作可能かを `press Tab` で確認 +6. フォーカスの視認性 + +Chrome DevTools MCP が利用可能な場合は `lighthouse_audit` でスコアを取得する。 + +**エラー記録**: 問題検出時はエラーディレクトリを作成する: +- `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成 +- `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` にスクリーンショットを保存 + +### Step 5: レスポンシブテスト(サブAgent内で実行) + +シナリオのURLについて3つのビューポートでスクリーンショットを取得し、AIで確認する。判定完了後は画像の内容をテキスト要約に変換し、以降はテキスト要約のみ保持する: + +```bash +# モバイル +docker compose exec playwright playwright-cli open <url> --headless --viewport 375x667 +docker compose exec playwright playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/mobile.png + +# タブレット +docker compose exec playwright playwright-cli open <url> --headless --viewport 768x1024 +docker compose exec playwright playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/tablet.png + +# デスクトップ +docker compose exec playwright playwright-cli open <url> --headless --viewport 1280x800 +docker compose exec playwright playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/desktop.png +``` + +**確認項目**: +- ナビゲーションの表示切り替え(ハンバーガーメニュー等) +- グリッドレイアウトの列数変化 +- テキストの折り返し +- 水平スクロールの有無(モバイルで不要な横スクロールは ❌) +- タッチターゲットのサイズ(モバイル時 44px 以上推奨) + +**エラー記録**: 問題検出時はエラーディレクトリを作成する: +- `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成 +- `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` にスクリーンショットを保存 + +### Step 6: フォームバリデーションテスト(サブAgent内で実行) + +ページ内のフォームを `snapshot` から自動検出し、以下のパターンでテストする: + +| パターン | 入力値 | 期待 | +|---------|-------|------| +| 空送信 | 全フィールド空 | バリデーションエラー | +| 必須チェック | 必須フィールドのみ空 | 該当フィールドにエラー | +| 型チェック | email欄に非email文字列 | 型エラー表示 | +| 最大長 | 1000文字の文字列 | 切り詰めまたはエラー | +| XSS | `<script>alert(1)</script>` | スクリプトが実行されない | +| SQLi | `'; DROP TABLE users; --` | SQLエラーが発生しない | +| 正常値 | 適切な値 | 成功 | + +セキュリティ上の問題(XSS, SQLi)は ❌ として即時報告する。 + +**エラー記録**: 問題検出時はエラーディレクトリを作成する: +- `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成 +- `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` にスクリーンショットを保存 + +### Step 7: エラー記録の確認 + +検出された問題は `docs/dev/webtests/errors/` に error.md として記録済みである。 + +- 修正は **dev-debug** 等の別スキルで対応する(本スキルでは修正を行わない) +- 各エラーの `error.md` の `status` フィールドを `open` → `fixed` に更新して対応状況を管理する + +### Step 8: レポート出力 + +計画テスト・モンキーテストの場合、`docs/dev/webtests/reports/YYYY-MM-DD-<plan-name>.md` にレポートを出力する。 + +**計画テストの場合**(サブAgent結果を集約): +1. `tmp/webtest/results/<plan-name>/` 配下の全 scenario 中間ファイルを Read する +2. 中間ファイルの内容を集約してレポートを生成する +3. レポート生成後、`rm -rf tmp/webtest/results/<plan-name>/` で中間ファイルを削除する + +レポートには以下を含める: +- Summary(テスト種別ごとの結果概要テーブル) +- APIセットアップ結果(実行したセットアップコマンドの成否。`api-setup.md` から集約) +- シナリオテスト結果(各シナリオの passed/failed と詳細) +- 視覚チェック結果(判定と所見) +- アクセシビリティ結果(チェック項目ごとの結果テーブル) +- レスポンシブ結果(ビューポートごとの結果テーブル) +- フォームバリデーション結果(パターンごとの結果テーブル) +- 検出されたエラー一覧(severity, step, 概要, error.md へのリンクのテーブル) +- APIクリーンアップ結果(実行したクリーンアップコマンドの成否。`api-cleanup.md` から集約) +- 未対応のエラー(status: open のエラー数) +- Recommendations + +## ルール・制約 + +### コンテキスト管理(重要) + +サブAgent内でのコンテキスト蓄積を抑制するため、以下のルールを遵守する。 + +**snapshot の取り扱い**: +- snapshot の YAML 全体をそのまま保持しない +- 判定に必要な要素(確認対象の要素名・状態・ref ID)のみ抽出して記録する +- 判定完了後は次の操作に必要な情報のみ保持し、不要な snapshot データは破棄する意識で進める +- Step 4 の Tab キーボードテストでは、各 Tab 後のフォーカス要素名のみをリスト形式で記録する: + - 良い例: 「Tab 1: "Email input" → Tab 2: "Password input" → Tab 3: "Login button"」 + - 悪い例: Tab ごとに snapshot YAML 全体を逐次保持 + +**screenshot の取り扱い**: +- CLI モード: screenshot はファイルに保存し、視覚判定が必要な時点でのみ Read する +- 判定完了後は画像の内容をテキスト要約に変換し、以降はテキスト要約のみ参照する + - 例: 「mobile.png: レイアウト正常、ナビゲーションがハンバーガーメニューに切り替わっている」 +- 同じ画像を複数 Step で重複して Read しない +- Step 8 レポートでは画像ファイルへのパスのみ記載し、画像自体は Read しない +- MCP モード: `browser_take_screenshot` の base64 が直接返るため、判定後すぐにテキスト要約に変換して以降は要約のみ使用する + +**scenario 中間ファイル**: +- 各シナリオの結果は `tmp/webtest/results/<plan-name>/` にファイルとして書き出す +- メインAgentは中間ファイルを Read して統合レポートを生成する +- レポート生成後、中間ファイルは削除する + +### 一般ルール + +- スクリーンショットは `tmp/webtest/screenshots/` に保存する(git管理しない) +- エラー検出時は `docs/dev/webtests/errors/<YYYY-MM-DD>-<NNN>-<概要>/error.md` を作成する +- エラーのスクリーンショットは `tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png` に保存する(git管理しない) +- 連番 NNN は日付ごとに 001 からリスタートする。同日再実行時は既存の最大連番の次から採番する +- 概要部分は英数字ケバブケースで記述する +- エラー検出後も全テストを最後まで継続する(中断しない) +- CLI モードの場合、Playwright CLI コマンドは `docker compose exec playwright` 経由で実行する +- コマンドの詳細は `references/playwright-cli-reference.md` を参照する +- モンキーテストのアクション数上限は20。タイムアウトはアクションあたり10秒 +- 同一ドメイン外への遷移はしない +- Chrome DevTools MCP は optional。利用できない場合はスキップする +- `@playwright/cli` が利用できない場合は `references/mcp-workflow.md` に従って MCP モードで実行する +- 環境が未セットアップの場合は Step 1 の AskUserQuestion で選択してもらう +- Bash コマンドはプロジェクトルートの **絶対パス** を使用する(`$(git rev-parse --show-toplevel)` でルートを取得) +- 500行ルール: 修正によりファイルが500行を超える場合は分割する + +### error.md テンプレート + +```markdown +--- +severity: critical | major | minor +step: "2a-scenario | 2b-monkey | 3-visual | 4-a11y | 5-responsive | 6-form" +status: open | fixed +detected: YYYY-MM-DD +fixedDate: +scenario: "シナリオ名またはテスト概要" +url: "テスト対象URL" +--- + +## 検出内容 + +(何が問題だったかの説明) + +## 再現手順 + +1. (手順1) +2. (手順2) +3. ... + +## 期待される状態 + +(正しい動作の説明) + +## スクリーンショット + +![エラースクリーンショット](../../../../../tmp/webtest/errors/<YYYY-MM-DD>-<NNN>-<概要>/screenshot.png) +``` + +## 追加リソース + +### リファレンスファイル + +- **`references/playwright-cli-reference.md`** — Playwright CLI コマンド一覧と使用例 +- **`references/test-plan-template.md`** — テスト計画の書き方テンプレート +- **`references/visual-check-criteria.md`** — 視覚チェックの判定基準と具体例 +- **`references/accessibility-checklist.md`** — アクセシビリティチェック項目の詳細 +- **`references/docker-setup.md`** — Docker環境のセットアップ手順 +- **`references/mcp-workflow.md`** — MCP モードのワークフローとツール対応表 + +### サンプルファイル + +- **`examples/sample-test-plan.md`** — サンプルテスト計画(Go+Echo+templアプリ向け) diff --git a/skills/dev-webtest/examples/sample-test-plan.md b/skills/dev-webtest/examples/sample-test-plan.md new file mode 100644 index 0000000..182f449 --- /dev/null +++ b/skills/dev-webtest/examples/sample-test-plan.md @@ -0,0 +1,94 @@ +--- +name: health-and-top +target-url: http://app:8080 +status: pending +last-run: +--- + +# ヘルスチェック & トップページ テスト + +Go + Echo + templ アプリケーションの基本動作確認テスト計画。 + +## 前提条件 + +- `docker compose up -d` でアプリとDBが起動済み +- Playwright コンテナが起動済み +- マイグレーションが適用済み + +## テストシナリオ + +### シナリオ1: ヘルスチェックエンドポイント + +**group**: api + +**手順**: +1. `http://app:8080/health` にアクセスする +2. レスポンスの内容を確認する + +**期待結果**: +- [ ] HTTPステータスコード 200 が返る +- [ ] レスポンスにヘルスステータスの情報が含まれる + +**視覚チェックポイント**: +- [ ] (JSON APIのためスキップ) + +### シナリオ2: トップページの表示 + +**group**: top-page + +**手順**: +1. `http://app:8080/` にアクセスする +2. ページが完全に読み込まれることを確認する + +**期待結果**: +- [ ] ページタイトルが適切に設定されている +- [ ] ナビゲーションメニューが表示される +- [ ] メインコンテンツ領域が表示される +- [ ] フッターが表示される + +**視覚チェックポイント**: +- [ ] レイアウトが崩れていないか +- [ ] フォントが正しく表示されているか +- [ ] 画像が正しく読み込まれているか +- [ ] 余白やマージンが適切か + +### シナリオ3: 存在しないページへのアクセス + +**group**: error-page + +**手順**: +1. `http://app:8080/nonexistent-page-12345` にアクセスする + +**期待結果**: +- [ ] 404エラーページが表示される +- [ ] エラーメッセージがユーザーフレンドリーである +- [ ] トップページへのリンクが表示される + +**視覚チェックポイント**: +- [ ] エラーページのレイアウトが崩れていないか +- [ ] エラーメッセージのフォントサイズが適切か + +## アクセシビリティ確認項目 + +- [ ] 画像にalt属性が設定されている +- [ ] フォーム要素にlabelが紐づいている(フォームがある場合) +- [ ] キーボードのみで操作可能 +- [ ] フォーカスが視覚的に分かる +- [ ] heading要素が正しい階層構造(h1 → h2 → h3) +- [ ] ランドマーク要素(header, nav, main, footer)が存在する + +## レスポンシブ確認 + +- [ ] モバイル (375x667): ナビゲーション、テキストの折り返し、タッチターゲット +- [ ] タブレット (768x1024): レイアウトの列数、サイドバー表示 +- [ ] デスクトップ (1280x800): フルレイアウト表示 + +## フォームバリデーション確認 + +(トップページにフォームがある場合のみ) + +### 検索フォーム(存在する場合) + +| フィールド | type | required | テストパターン | +|-----------|------|----------|-------------| +| 検索ワード | text | ❌ | 空, 正常文字列, 特殊文字, 長い文字列 | diff --git a/skills/dev-webtest/references/accessibility-checklist.md b/skills/dev-webtest/references/accessibility-checklist.md new file mode 100644 index 0000000..19dcdb6 --- /dev/null +++ b/skills/dev-webtest/references/accessibility-checklist.md @@ -0,0 +1,152 @@ +# アクセシビリティチェックリスト + +Playwright CLI の snapshot(アクセシビリティツリー)を使用して確認する項目。 + +## チェック項目 + +### 1. 画像の代替テキスト + +**確認方法**: snapshot 内の `img` ロールの要素に `name` プロパティ(alt 相当)があるか。 + +**✅ 合格**: +- すべての意味のある画像に alt 属性がある +- 装飾的な画像は `alt=""` または `role="presentation"` が設定されている +- alt テキストが画像の内容を適切に説明している + +**❌ 不合格**: +- 意味のある画像に alt がない +- alt テキストが「画像」「image」等の無意味な値 + +**修正例** (templ): +```go +// Before +<img src="/static/logo.png"> + +// After +<img src="/static/logo.png" alt="サイトロゴ"> +``` + +### 2. フォームラベル + +**確認方法**: snapshot 内の input/select/textarea 要素に `name` プロパティ(label 相当)があるか。 + +**✅ 合格**: +- すべてのフォーム要素に `<label>` が紐づいている(`for` 属性、またはラベル要素でラップ) +- placeholder だけでなく label がある + +**❌ 不合格**: +- input に label が紐づいていない +- placeholder のみで label がない + +**修正例** (templ): +```go +// Before +<input type="email" placeholder="メールアドレス"> + +// After +<label for="email">メールアドレス</label> +<input type="email" id="email" placeholder="メールアドレス"> +``` + +### 3. Heading 階層 + +**確認方法**: snapshot 内の heading ロール要素の `level` を確認。 + +**✅ 合格**: +- ページに h1 が1つある +- h1 → h2 → h3 のように順番にネストしている +- レベルのスキップがない(h1 の次に h3 はNG) + +**❌ 不合格**: +- h1 がない、または複数ある +- heading レベルがスキップされている(h1 → h3) +- 見た目のために heading レベルを誤用している + +### 4. キーボード操作 + +**確認方法**: `playwright-cli press Tab` を繰り返してフォーカス移動を確認。 + +**✅ 合格**: +- すべてのインタラクティブ要素(リンク、ボタン、フォーム)にフォーカスが到達する +- フォーカス順序が論理的(左上から右下へ) +- フォーカストラップがない(モーダル内は例外) +- Enterキーでボタン/リンクを実行できる + +**❌ 不合格**: +- フォーカスが到達しない要素がある +- フォーカスが見えない(outline: none で消されている) +- Tab キーでフォーカスが巡回しない + +**確認手順**: +```bash +playwright-cli press Tab # 最初のフォーカス可能要素 +playwright-cli snapshot # フォーカス位置を確認 +playwright-cli press Tab # 次の要素 +playwright-cli snapshot # フォーカス位置を確認 +# 繰り返す +``` + +### 5. ARIA 属性 + +**確認方法**: snapshot 内の要素の role と ARIA プロパティを確認。 + +**✅ 合格**: +- カスタムウィジェットに適切な role が設定されている +- `aria-label` や `aria-describedby` が必要な箇所に設定されている +- `aria-hidden="true"` が装飾的な要素にのみ使用されている +- ライブリージョン(`aria-live`)が動的コンテンツに設定されている + +**❌ 不合格**: +- インタラクティブなカスタム要素に role がない +- `aria-hidden="true"` がインタラクティブ要素に設定されている +- 不適切な role の使用 + +### 6. コントラスト比 + +**確認方法**: スクリーンショットの視覚的確認 + Lighthouse 監査(DevTools MCP 利用時)。 + +**WCAG AA 基準**: +- 通常テキスト: 4.5:1 以上 +- 大きなテキスト(18px以上、または14px太字以上): 3:1 以上 +- UIコンポーネント・グラフィカルオブジェクト: 3:1 以上 + +### 7. ランドマーク + +**確認方法**: snapshot 内の `navigation`, `main`, `banner`, `contentinfo` ロールを確認。 + +**✅ 合格**: +- `<header>` (banner) が存在する +- `<nav>` (navigation) が存在する +- `<main>` (main) が存在する +- `<footer>` (contentinfo) が存在する + +**❌ 不合格**: +- ランドマーク要素が一切ない(全てが `<div>` で構成) +- `<main>` がない + +## Lighthouse 監査(Chrome DevTools MCP 利用時) + +Chrome DevTools MCP が利用可能な場合、`lighthouse_audit` でアクセシビリティスコアを取得する。 + +``` +スコア 90-100: ✅ 良好 +スコア 70-89: ⚠️ 改善推奨 +スコア 0-69: ❌ 要修正 +``` + +## 報告フォーマット + +```markdown +## アクセシビリティ結果 + +| チェック項目 | 結果 | 詳細 | +|------------|------|------| +| 画像alt属性 | ✅/❌ | N個中M個にalt設定済み | +| フォームラベル | ✅/❌ | N個中M個にlabel設定済み | +| Heading階層 | ✅/❌ | h1→h2→h3 の順序が正しい/不正 | +| キーボード操作 | ✅/❌ | N個中M個にフォーカス到達 | +| ARIA属性 | ✅/❌ | 不適切な使用N箇所 | +| コントラスト | ✅/⚠️/❌ | 問題のある箇所の説明 | +| ランドマーク | ✅/❌ | 存在するランドマーク一覧 | +| Lighthouse | XX/100 | (DevTools MCP利用時のみ) | +``` diff --git a/skills/dev-webtest/references/docker-setup.md b/skills/dev-webtest/references/docker-setup.md new file mode 100644 index 0000000..d990c5d --- /dev/null +++ b/skills/dev-webtest/references/docker-setup.md @@ -0,0 +1,244 @@ +# Docker 環境セットアップ + +dev-webtest スキル用の Playwright 実行環境をセットアップする手順。 + +## 前提 + +- Docker Compose でアプリケーションが動作していること +- `docker compose up -d` でアプリが起動済みであること + +## セットアップ手順 + +### Step 1: docker-compose.yaml に Playwright サービスを追加 + +```yaml + playwright: + image: mcr.microsoft.com/playwright:v1.50.0-noble + working_dir: /work + volumes: + - .:/work + depends_on: + - app + command: ["tail", "-f", "/dev/null"] + environment: + - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright +``` + +**ポイント**: +- `mcr.microsoft.com/playwright` は Chromium/Firefox/WebKit がプリインストールされた公式イメージ +- `volumes: .:/work` でプロジェクトルートをマウント(スクリーンショットの共有用) +- `command: tail -f /dev/null` でコンテナを起動状態に保つ +- `depends_on: app` でアプリ起動後に Playwright コンテナが起動する + +### Step 2: Playwright CLI のインストール + +```bash +docker compose up -d playwright +docker compose exec playwright npm install -g @playwright/cli@latest +``` + +### Step 3: 動作確認 + +```bash +# バージョン確認 +docker compose exec playwright playwright-cli --version + +# アプリへのアクセス確認 +docker compose exec playwright playwright-cli open http://app:8080 --headless +docker compose exec playwright playwright-cli snapshot +docker compose exec playwright playwright-cli close +``` + +### Step 4: スクリーンショット保存先の作成 + +```bash +mkdir -p tmp/webtest/screenshots +``` + +`tmp/webtest/` を `.gitignore` に追加する(まだの場合): +``` +tmp/webtest/ +``` + +## Chrome DevTools MCP の設定(オプション) + +Chrome DevTools MCP を使用する場合、CDP ポートを公開する。 + +### docker-compose.yaml の修正 + +```yaml + playwright: + image: mcr.microsoft.com/playwright:v1.50.0-noble + working_dir: /work + volumes: + - .:/work + depends_on: + - app + command: ["tail", "-f", "/dev/null"] + ports: + - "9222:9222" # Chrome DevTools Protocol + environment: + - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright +``` + +### .mcp.json への追加 + +```json +{ + "mcpServers": { + "chrome-devtools": { + "command": "npx", + "args": ["-y", "chrome-devtools-mcp@latest", "--browserUrl", "http://localhost:9222"] + } + } +} +``` + +**注意**: Chrome DevTools MCP の接続は Playwright CLI で開いたブラウザインスタンスとの共存に制約がある場合がある。動作しない場合は Playwright CLI 単体で運用する。 + +## カスタム Dockerfile(オプション) + +`@playwright/cli` を毎回インストールする手間を省くため、カスタムイメージを作成する案。 + +```dockerfile +# Dockerfile.playwright +FROM mcr.microsoft.com/playwright:v1.50.0-noble + +RUN npm install -g @playwright/cli@latest + +WORKDIR /work +CMD ["tail", "-f", "/dev/null"] +``` + +```yaml +# docker-compose.yaml + playwright: + build: + context: . + dockerfile: Dockerfile.playwright + working_dir: /work + volumes: + - .:/work + depends_on: + - app +``` + +## トラブルシューティング + +### `playwright-cli` が見つからない + +```bash +# Node.js のグローバルパスを確認 +docker compose exec playwright npm root -g + +# 直接パスで実行 +docker compose exec playwright npx @playwright/cli --version +``` + +### アプリに接続できない + +```bash +# コンテナ間のネットワークを確認 +docker compose exec playwright ping app + +# アプリのポートを確認 +docker compose exec playwright curl -s http://app:8080/health +``` + +### スクリーンショットが保存されない + +```bash +# 保存先ディレクトリの権限を確認 +docker compose exec playwright ls -la /work/tmp/webtest/screenshots/ + +# 手動でディレクトリ作成 +docker compose exec playwright mkdir -p /work/tmp/webtest/screenshots +``` + +### `@playwright/cli` が存在しない場合のフォールバック + +`@playwright/cli` が npm で利用できない場合(パッケージが新しいため): + +1. `@playwright/mcp` を MCP サーバーとして設定する +2. docker-compose.yaml を修正: + ```yaml + playwright: + image: mcr.microsoft.com/playwright:v1.50.0-noble + working_dir: /work + volumes: + - .:/work + depends_on: + - app + command: ["npx", "@playwright/mcp@latest", "--headless", "--port", "8931", "--host", "0.0.0.0"] + ports: + - "8931:8931" + ``` +3. `.mcp.json` に追加: + ```json + { + "mcpServers": { + "playwright": { + "type": "sse", + "url": "http://localhost:8931/sse" + } + } + } + ``` + +## ローカル MCP セットアップ + +Docker を使わずにローカル環境で `@playwright/mcp` を直接実行する方法。 + +### 前提 + +- Node.js v18 以上がインストールされていること + +### Step 1: `.mcp.json` に Playwright MCP を設定 + +プロジェクトルートの `.mcp.json` に以下を追加する: + +```json +{ + "mcpServers": { + "playwright": { + "command": "npx", + "args": ["@playwright/mcp@latest", "--headless"] + } + } +} +``` + +### Step 2: スクリーンショット保存先の作成 + +```bash +mkdir -p tmp/webtest/screenshots +``` + +`tmp/webtest/` を `.gitignore` に追加する(まだの場合): +``` +tmp/webtest/ +``` + +### Step 3: テスト対象 URL + +ローカル MCP モードでは Docker ネットワーク内のホスト名(`http://app:<port>`)は使えない。テスト対象 URL には `http://localhost:<port>` を使用する。 + +### トラブルシューティング + +#### npx で `@playwright/mcp` が実行できない + +```bash +# npx のキャッシュをクリアして再実行 +npx --yes @playwright/mcp@latest --headless --help + +# グローバルインストールで試す +npm install -g @playwright/mcp@latest +``` + +#### ブラウザが見つからない + +`@playwright/mcp` は初回実行時にブラウザを自動ダウンロードする。手動でインストールする場合: + +```bash +npx playwright install chromium +``` diff --git a/skills/dev-webtest/references/mcp-workflow.md b/skills/dev-webtest/references/mcp-workflow.md new file mode 100644 index 0000000..8161185 --- /dev/null +++ b/skills/dev-webtest/references/mcp-workflow.md @@ -0,0 +1,213 @@ +# MCP モードワークフロー + +`@playwright/mcp` を MCP サーバーとして利用する場合のワークフロー。`@playwright/cli` が利用できない場合のフォールバック手段。 + +## CLI → MCP ツール対応表 + +| CLI コマンド | MCP ツール | 備考 | +|-------------|-----------|------| +| `open <url> --headless` | `browser_navigate` | URL遷移。ブラウザは自動起動 | +| `close` | `browser_close` | ブラウザを閉じる | +| `goto <url>` | `browser_navigate` | `open` と同じツール | +| `go-back` | `browser_go_back` | | +| `go-forward` | `browser_go_forward` | | +| `reload` | — | `browser_navigate` で同一URLを再指定 | +| `click <ref>` | `browser_click` | `element` パラメータに説明テキストを指定 | +| `hover <ref>` | `browser_hover` | | +| `fill <ref> "value"` | `browser_type` | `text` パラメータに入力値を指定 | +| `type "text"` | `browser_type` | | +| `press <key>` | `browser_press_key` | `key` パラメータにキー名を指定 | +| `drag <from> <to>` | `browser_drag` | | +| `select <ref> "value"` | `browser_select_option` | | +| `upload <ref> <file>` | `browser_file_upload` | `paths` パラメータにファイルパス配列 | +| `snapshot` | `browser_snapshot` | レスポンスに直接アクセシビリティツリーが返る | +| `screenshot` | `browser_take_screenshot` | base64 画像が直接返る(ファイル保存なし) | +| `pdf` | `browser_pdf_save` | | +| `eval "js"` | `browser_evaluate` | JavaScript 実行 | +| `console` | `browser_console_messages` | | +| `network` | `browser_network_requests` | | +| `tab-list` | `browser_tab_list` | | +| `tab-new <url>` | `browser_tab_new` | | +| `tab-close` | `browser_tab_close` | | +| `tab-select <id>` | `browser_tab_select` | | +| `dialog-accept` | `browser_handle_dialog` | `accept: true` | +| `dialog-dismiss` | `browser_handle_dialog` | `accept: false` | +| `open ... --viewport WxH` | `browser_resize` | navigate 後に別途リサイズ | + +## CLI との主な違い + +| 項目 | CLI モード | MCP モード | +|------|-----------|-----------| +| **実行方式** | `docker compose exec` + Bash | MCP プロトコル経由のツール呼び出し | +| **スクリーンショット** | ファイル保存 → Read tool で読み取り | base64 が直接レスポンスに含まれる | +| **スナップショット** | YAML ファイル保存 + stdout | レスポンスにアクセシビリティツリーが直接返る | +| **ビューポート制御** | `--viewport WxH` フラグで open 時に指定 | `browser_resize` で navigate 後に変更 | +| **要素指定** | ref ID(`e15` 等) | 要素の説明テキスト(`"Login button"` 等) | +| **セッション管理** | `-s=name` で名前付きセッション | 単一セッション(複数セッション非対応) | +| **ブラウザ起動** | `open` で明示的に起動 | 初回 navigate 時に自動起動 | + +### 重要な注意点 + +- **要素指定方法が異なる**: CLI では `snapshot` の ref ID(例: `e15`)を使うが、MCP では要素の説明テキスト(例: `"Email input field"`)を使う。`browser_snapshot` の結果から適切な説明を読み取ること +- **スクリーンショットはファイル保存されない**: `browser_take_screenshot` は base64 を返すため、Read tool での読み取りは不要。Claude が直接画像を解析する +- **ビューポート変更は2ステップ**: まず `browser_navigate` でページを開き、次に `browser_resize` でサイズを変更する + +## MCP 版ワークフロー + +SKILL.md の各 Step を MCP ツールで実行する手順。 + +### Step 1: 環境準備 + +MCP モードには Docker MCP とローカル MCP の2形態がある。SKILL.md の Step 1 で選択された形態に従う。 + +| 形態 | MCP サーバーの起動方法 | テスト対象 URL | +|------|----------------------|---------------| +| Docker MCP | コンテナ内で `@playwright/mcp` を起動、SSE 接続 | `http://app:<port>` | +| ローカル MCP | npx 経由でローカル起動(`.mcp.json`) | `http://localhost:<port>` | + +1. MCP サーバーの接続を確認する + - `browser_navigate` で対象 URL にアクセスし、正常にレスポンスが返ることを確認 +2. 接続できない場合: + - Docker MCP → `references/docker-setup.md` の「`@playwright/cli` が存在しない場合のフォールバック」セクションを確認 + - ローカル MCP → `references/docker-setup.md` の「ローカル MCP セットアップ」セクションを確認 + +### Step 2: テスト実行 + +#### 2a: 計画テスト + +1. テスト計画ファイルを読み込む +2. 各シナリオを順番に実行: + - `browser_navigate` で URL にアクセス + - `browser_snapshot` で要素を確認 + - `browser_click`, `browser_type` 等で操作 + - 各ステップで `browser_snapshot` を取得して状態確認 + - 視覚チェックポイントで `browser_take_screenshot` を取得 +3. 結果を記録する + +#### 2b: モンキーテスト + +1. `browser_navigate` で指定 URL にアクセス +2. `browser_snapshot` でページ構造を把握 +3. ランダムアクションを実行(最大20回): + - `browser_click` でリンク・ボタンをクリック + - `browser_type` でフォームにランダム入力 + - `browser_go_back` / `browser_go_forward` でナビゲーション +4. 各アクション後: + - `browser_snapshot` でページ状態を取得 + - `browser_console_messages` で JS エラーを確認 + - `browser_network_requests` で HTTP エラーを確認 +5. 問題検出時は `browser_take_screenshot` を取得 + +#### 2c: クイックチェック + +1. `browser_navigate` で指定 URL にアクセス +2. `browser_take_screenshot` + `browser_snapshot` を取得 +3. 視覚チェックとアクセシビリティチェックのみ実行 + +### Step 3: 視覚チェック + +`browser_take_screenshot` の base64 画像を Claude が直接解析する。ファイル保存・Read tool は不要。**判定完了後は画像の内容をテキスト要約に変換し、以降はテキスト要約のみ保持する**(SKILL.md のコンテキスト管理ルール参照)。 + +### Step 4: アクセシビリティチェック + +`browser_snapshot` のレスポンスを直接分析する。CLI と同じチェック項目を適用。**snapshot の YAML 全体を保持せず、判定に必要な要素のみ抽出する**(SKILL.md のコンテキスト管理ルール参照)。 + +キーボード操作テストは `browser_press_key` で `Tab` キーを押下して確認する。各 Tab 後はフォーカス要素名のみを記録する。 + +### Step 5: レスポンシブテスト + +``` +# モバイル +browser_navigate → <url> +browser_resize → width: 375, height: 667 +browser_take_screenshot → 判定後テキスト要約に変換 + +# タブレット +browser_resize → width: 768, height: 1024 +browser_take_screenshot → 判定後テキスト要約に変換 + +# デスクトップ +browser_resize → width: 1280, height: 800 +browser_take_screenshot → 判定後テキスト要約に変換 +``` + +**注意**: MCP モードでは同一セッションで `browser_resize` を使いビューポートを切り替える。CLI のように毎回 open/close する必要はない。各スクリーンショットの判定完了後は base64 画像を保持せず、テキスト要約のみ保持する。 + +### Step 6: フォームバリデーションテスト + +CLI モードと同じテストパターンを適用。操作コマンドのみ MCP ツールに置き換える: + +- `fill` → `browser_type` +- `click` → `browser_click` +- `snapshot` → `browser_snapshot` +- `screenshot` → `browser_take_screenshot` + +### Step 7: 問題の修正 + +CLI モードと同じ。修正対象はソースコードなので差異なし。 + +### Step 8: レポート出力 + +CLI モードと同じ。レポートフォーマットに差異なし。 + +## よく使うパターン + +### ログインフロー + +``` +browser_navigate → url: "http://localhost:8080/login" +browser_snapshot # フォーム要素を確認 +browser_type → element: "Email input", text: "user@example.com" +browser_type → element: "Password input", text: "password123" +browser_click → element: "Login button" +browser_snapshot # ログイン後の状態確認 +browser_take_screenshot # スクリーンショット取得 +``` + +### レスポンシブ確認 + +``` +browser_navigate → url: "http://localhost:8080" + +# モバイル +browser_resize → width: 375, height: 667 +browser_take_screenshot + +# タブレット +browser_resize → width: 768, height: 1024 +browser_take_screenshot + +# デスクトップ +browser_resize → width: 1280, height: 800 +browser_take_screenshot +``` + +### フォームバリデーション確認 + +``` +browser_navigate → url: "http://localhost:8080/form" +browser_snapshot # フォーム構造確認 +browser_click → element: "Submit button" # 空のまま送信 +browser_snapshot # バリデーションエラー確認 +browser_take_screenshot +``` + +## 未対応コマンド + +以下の CLI コマンドは MCP モードに対応するツールがない。これらの機能が必要な場合は CLI モードを使用する。 + +| CLI コマンド | 用途 | 代替手段 | +|-------------|------|---------| +| `tracing-start` / `tracing-stop` | パフォーマンストレース | Chrome DevTools MCP の利用を検討 | +| `video-start` / `video-stop` | 動画録画 | スクリーンショットの連続取得で代替 | +| `cookie-list` / `cookie-set` / `cookie-clear` | Cookie 操作 | `browser_evaluate` で `document.cookie` を操作 | +| `localstorage-get` / `localstorage-set` / `localstorage-clear` | localStorage 操作 | `browser_evaluate` で `localStorage` API を操作 | +| `state-save` / `state-load` | ブラウザ状態の保存・復元 | なし | +| `route` / `unroute` / `route-list` | ネットワークインターセプト | なし | +| `list` / `close-all` | セッション管理 | MCP は単一セッション | +| `-s=name` | 名前付きセッション | MCP は単一セッション | +| `dblclick` | ダブルクリック | `browser_click` を2回実行(完全な代替ではない) | +| `check` / `uncheck` | チェックボックス操作 | `browser_click` で代替 | +| `keydown` / `keyup` | キー押下・解放 | `browser_press_key` で代替(修飾キーの保持は不可) | +| `mousewheel` | スクロール | `browser_evaluate` で `window.scrollBy()` を実行 | +| `mousemove` | マウス移動 | なし | diff --git a/skills/dev-webtest/references/playwright-cli-reference.md b/skills/dev-webtest/references/playwright-cli-reference.md new file mode 100644 index 0000000..a1924e7 --- /dev/null +++ b/skills/dev-webtest/references/playwright-cli-reference.md @@ -0,0 +1,264 @@ +# Playwright CLI コマンドリファレンス + +`@playwright/cli` (npm) の公式コマンド一覧。Docker 経由で実行する場合のプレフィックス: + +```bash +docker compose exec playwright playwright-cli <command> [options] +``` + +ローカル実行の場合は `playwright-cli <command>` または `npx playwright-cli <command>`。 + +## open コマンド(起動) + +```bash +playwright-cli open [url] # ブラウザを開く(ヘッドレス) +playwright-cli open <url> --headed # ヘッド付きで開く(デフォルトはヘッドレス) +playwright-cli open --browser=chrome # ブラウザ指定(chrome/firefox/webkit/msedge) +playwright-cli open --persistent # 永続プロファイルを使用 +playwright-cli open --profile=<path> # カスタムプロファイルディレクトリ +playwright-cli open --extension # ブラウザ拡張経由で接続 +playwright-cli open --config=file.json # 設定ファイルを使用 +``` + +## セッション管理 + +```bash +playwright-cli -s=<name> <command> # 名前付きセッションでコマンド実行 +playwright-cli list # 全セッション一覧 +playwright-cli close # 現在のページを閉じる +playwright-cli close-all # 全ブラウザを閉じる +playwright-cli kill-all # 全ブラウザプロセスを強制終了 +playwright-cli delete-data # デフォルトセッションのユーザーデータ削除 +playwright-cli -s=<name> delete-data # 名前付きセッションのデータ削除 +playwright-cli show # ビジュアルダッシュボードを開く +``` + +環境変数 `PLAYWRIGHT_CLI_SESSION=<name>` でデフォルトセッション名を指定可能。 + +## ページ遷移 + +```bash +playwright-cli goto <url> # URL に遷移 +playwright-cli go-back # 前のページに戻る +playwright-cli go-forward # 次のページに進む +playwright-cli reload # ページをリロード +``` + +## 要素操作 + +`<ref>` は snapshot の YAML に含まれる要素リファレンス ID(例: `e15`, `e21`)。 + +```bash +playwright-cli click <ref> [button] # クリック(button: left/right/middle) +playwright-cli dblclick <ref> [button] # ダブルクリック +playwright-cli hover <ref> # ホバー +playwright-cli fill <ref> <text> # 入力欄にテキストを設定(既存値をクリア) +playwright-cli type <text> # フォーカス中の要素にキーストローク入力 +playwright-cli select <ref> <value> # ドロップダウンの選択 +playwright-cli check <ref> # チェックボックス/ラジオボタン ON +playwright-cli uncheck <ref> # チェックボックス OFF +playwright-cli upload <file> # ファイルアップロード +playwright-cli drag <startRef> <endRef> # ドラッグ&ドロップ +playwright-cli resize <width> <height> # ブラウザウィンドウのリサイズ +``` + +## キーボード + +```bash +playwright-cli press <key> # キー押下(例: Enter, Tab, Escape, ArrowLeft) +playwright-cli keydown <key> # キーダウン +playwright-cli keyup <key> # キーアップ +``` + +## マウス + +```bash +playwright-cli mousemove <x> <y> # マウス移動 +playwright-cli mousedown [button] # マウスボタンダウン +playwright-cli mouseup [button] # マウスボタンアップ +playwright-cli mousewheel <dx> <dy> # スクロール(正:下/右、負:上/左) +``` + +## スナップショット・スクリーンショット + +各コマンド実行後、自動的にスナップショット(アクセシビリティツリーYAML)が出力される。 + +```bash +playwright-cli snapshot # スナップショットを取得(自動ファイル名) +playwright-cli snapshot --filename=<path> # 指定パスに保存 +playwright-cli screenshot # スクリーンショット(自動ファイル名) +playwright-cli screenshot [ref] # 特定要素のスクリーンショット +playwright-cli screenshot --filename=<path> # 指定パスに保存 +playwright-cli pdf # PDF出力(自動ファイル名) +playwright-cli pdf --filename=<path> # 指定パスに保存 +``` + +スナップショットは `.playwright-cli/` ディレクトリに YAML ファイルとして保存される。`--filename` 未指定時はタイムスタンプ付き自動命名。 + +## JavaScript 実行 + +```bash +playwright-cli eval <expression> # JS式を評価(ページ上) +playwright-cli eval <expression> <ref> # 特定要素上で JS 式を評価 +playwright-cli run-code <code> # Playwright コードスニペットを実行 +``` + +## コンソール・ネットワーク + +```bash +playwright-cli console # コンソールメッセージ一覧 +playwright-cli console error # エラーレベル以上のみ(error/warning/info/debug) +playwright-cli network # ページ読み込み以降の全ネットワークリクエスト一覧 +``` + +## タブ管理 + +```bash +playwright-cli tab-list # タブ一覧 +playwright-cli tab-new [url] # 新しいタブを開く +playwright-cli tab-close [index] # タブを閉じる(インデックス指定可) +playwright-cli tab-select <index> # タブを切り替え +``` + +## ダイアログ処理 + +```bash +playwright-cli dialog-accept [prompt] # ダイアログを承認(prompt 入力テキスト指定可) +playwright-cli dialog-dismiss # ダイアログを拒否 +``` + +## ストレージ操作 + +```bash +# ブラウザ状態 +playwright-cli state-save [filename] # ストレージ状態を保存 +playwright-cli state-load <filename> # ストレージ状態を読み込み + +# Cookie +playwright-cli cookie-list [--domain] # Cookie 一覧(ドメインでフィルタ可) +playwright-cli cookie-get <name> # Cookie 取得 +playwright-cli cookie-set <name> <value> # Cookie 設定 +playwright-cli cookie-delete <name> # Cookie 削除 +playwright-cli cookie-clear # 全 Cookie クリア + +# localStorage +playwright-cli localstorage-list # 一覧 +playwright-cli localstorage-get <key> # 取得 +playwright-cli localstorage-set <key> <val> # 設定 +playwright-cli localstorage-delete <key> # 削除 +playwright-cli localstorage-clear # 全クリア + +# sessionStorage +playwright-cli sessionstorage-list # 一覧 +playwright-cli sessionstorage-get <key> # 取得 +playwright-cli sessionstorage-set <key> <val> # 設定 +playwright-cli sessionstorage-delete <key> # 削除 +playwright-cli sessionstorage-clear # 全クリア +``` + +## ネットワーク制御 + +```bash +playwright-cli route <pattern> [opts] # リクエストモック(パターンマッチ) +playwright-cli route-list # アクティブなルート一覧 +playwright-cli unroute [pattern] # ルート解除 +``` + +## トレース・録画 + +```bash +playwright-cli tracing-start # トレース記録開始 +playwright-cli tracing-stop # トレース記録停止(出力ディレクトリに保存) +playwright-cli video-start # 動画録画開始 +playwright-cli video-stop [filename] # 動画録画停止(ファイル名指定可) +``` + +## 設定ファイル + +`.playwright/cli.config.json` に配置すると自動読み込みされる。`--config` で明示指定も可能。 + +```json +{ + "browser": { + "browserName": "chromium", + "isolated": true, + "launchOptions": { "headless": true }, + "contextOptions": { "viewport": { "width": 1280, "height": 720 } } + }, + "outputDir": "./tmp/webtest", + "outputMode": "file", + "console": { "level": "error" }, + "network": { + "allowedOrigins": ["https://myapp.example.com"], + "blockedOrigins": [] + }, + "timeouts": { + "action": 5000, + "navigation": 60000 + } +} +``` + +## dev-webtest で使う主要パターン + +### ページアクセスとスナップショット取得 + +```bash +playwright-cli open http://app:8080/login +playwright-cli snapshot +``` + +### ログインフロー + +```bash +playwright-cli open http://app:8080/login +playwright-cli snapshot # ref ID を確認 +playwright-cli fill e15 "user@example.com" +playwright-cli fill e18 "password123" +playwright-cli click e21 +playwright-cli snapshot # ログイン後の状態確認 +``` + +### レスポンシブ確認 + +```bash +# モバイル +playwright-cli open http://app:8080 --config=mobile.json +playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/mobile.png + +# タブレット(resize で切り替え) +playwright-cli resize 768 1024 +playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/tablet.png + +# デスクトップ +playwright-cli resize 1280 800 +playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/desktop.png +``` + +### フォームバリデーション確認 + +```bash +playwright-cli open http://app:8080/form +playwright-cli snapshot # フォーム構造と ref 確認 +playwright-cli click e30 # 空のまま送信 +playwright-cli snapshot # バリデーションエラー確認 +playwright-cli console error # JS エラー確認 +``` + +### エラー検出(モンキーテスト向け) + +```bash +playwright-cli snapshot # 操作対象を把握 +playwright-cli click e12 # ランダム操作 +playwright-cli console error # JS エラー確認 +playwright-cli network # HTTP エラー確認 +playwright-cli screenshot --filename=/work/tmp/webtest/screenshots/error.png +``` + +## 注意事項 + +- `<ref>` は snapshot YAML 内の要素 ID。操作前に必ず `snapshot` で最新の ref を取得する +- Docker 内ではヘッドレスがデフォルト。`--headed` はローカル確認用 +- スクリーンショットのパスは Docker ボリュームマウント先(`/work/` 配下)を指定する +- 各コマンド実行後に自動でスナップショットが返される(コンテキスト管理に注意) +- セッション名 (`-s=name`) で複数ブラウザを並行操作可能 diff --git a/skills/dev-webtest/references/test-plan-template.md b/skills/dev-webtest/references/test-plan-template.md new file mode 100644 index 0000000..3d21c10 --- /dev/null +++ b/skills/dev-webtest/references/test-plan-template.md @@ -0,0 +1,207 @@ +# テスト計画テンプレート + +テスト計画ファイルは `docs/dev/webtests/plans/` に Markdown 形式で配置する。 + +## フロントマター + +```yaml +--- +name: <テスト計画名> +target-url: http://app:8080/<path> +status: pending | in_progress | done +last-run: YYYY-MM-DD +viewports: + - 375x667 # モバイル(省略時はデフォルト3種を使用) + - 768x1024 # タブレット + - 1280x800 # デスクトップ +--- +``` + +| フィールド | 必須 | 説明 | +|-----------|------|------| +| name | ✅ | テスト計画の名前 | +| target-url | ✅ | テスト対象のベースURL | +| status | ✅ | `pending` → `in_progress` → `done` | +| last-run | ❌ | 最後に実行した日付(自動更新) | +| viewports | ❌ | レスポンシブテストのビューポート(省略時デフォルト) | + +## 本文構造 + +```markdown +# <テスト計画名> + +## 前提条件 + +- [テスト前に必要な状態やデータの説明] +- [必要なログイン情報やテストデータ] + +## APIデータセットアップ + +テストシナリオ実行前に、API経由で前提データを登録する手順。 +dev-webtest がシナリオ実行前に自動的にこのセクションのコマンドを実行する。 + +### ファイル共通 + +```bash +# ログインしてトークン取得 +TOKEN=$(curl -s -X POST http://app:8080/api/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"email":"admin@test.com","password":"Test1234!"}' | jq -r '.token') + +# テストユーザー作成 +curl -X POST http://app:8080/api/users \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer ${TOKEN}" \ + -d '{"email":"test@example.com","password":"Test1234!","role":"user"}' +``` + +### シナリオ2固有 + +```bash +# テスト用データ作成(シナリオ2: データ一覧表示 の前提) +curl -X POST http://app:8080/api/items \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer ${TOKEN}" \ + -d '{"name":"テストアイテム","price":1000}' +``` + +## APIクリーンアップ + +全シナリオ完了後に、テストで作成したデータを削除する手順。 +dev-webtest が全シナリオ完了後に自動的にこのセクションのコマンドを実行する。 + +```bash +# テストユーザー削除 +curl -X DELETE http://app:8080/api/users/test@example.com \ + -H "Authorization: Bearer ${TOKEN}" +``` + +## テストシナリオ + +### シナリオ1: <シナリオ名> + +**group**: general +**depends**: [] + +**手順**: +1. `<URL>` にアクセスする +2. `<要素の説明>` に `<値>` を入力する +3. `<ボタンの説明>` をクリックする +4. ページが遷移することを確認する + +**期待結果**: +- [ ] <画面に表示されるべきテキストや状態> +- [ ] <データの変更結果> +- [ ] <エラーメッセージ(エラーケースの場合)> + +**視覚チェックポイント**: +- [ ] レイアウトが崩れていないか +- [ ] フォントサイズ・色が適切か +- [ ] 画像が正しく表示されているか + +### シナリオ2: <エラーケース> + +**group**: general +**depends**: [シナリオ1] + +**手順**: +1. ... + +**期待結果**: +- [ ] エラーメッセージが表示される +- [ ] フォームの入力値が保持されている + +## アクセシビリティ確認項目 + +- [ ] 画像にalt属性が設定されている +- [ ] フォーム要素にlabelが紐づいている +- [ ] キーボードのみで操作可能 +- [ ] フォーカスが視覚的に分かる +- [ ] コントラスト比がWCAG AA基準を満たす +- [ ] heading要素が正しい階層構造になっている + +## レスポンシブ確認 + +- [ ] モバイル (375x667): ナビゲーション、レイアウト、タッチターゲット +- [ ] タブレット (768x1024): グリッド、サイドバー +- [ ] デスクトップ (1280x800): フルレイアウト + +## フォームバリデーション確認 + +### <フォーム名> + +| フィールド | type | required | テストパターン | +|-----------|------|----------|-------------| +| メール | email | ✅ | 空, 不正形式, 正常 | +| パスワード | password | ✅ | 空, 短すぎ, 正常 | +| 名前 | text | ❌ | 空, 長すぎ, 特殊文字, 正常 | +``` + +## シナリオの並列実行制御 + +各シナリオに `group` と `depends` を指定することで、並列実行の制御を行う。 + +| フィールド | 必須 | 説明 | +|-----------|------|------| +| group | ❌ | シナリオのグループ名。同一グループ内は直列実行。異なるグループは並列実行可能。省略時はシナリオ単独で独立グループ扱い(他と並列可能) | +| depends | ❌ | 同一グループ内で先に実行すべきシナリオ名の配列。省略時はグループ内の記述順に実行 | + +**グループ設計の指針**: +- 同一URLで状態を変更するシナリオ(ログイン→操作→確認)は同一グループにする +- 異なるURLを対象とする独立したシナリオは別グループ(または group 省略)にする +- 読み取り専用のシナリオ(表示確認のみ)は group を省略して並列化を最大化する + +**例**: +```markdown +### シナリオ1: ログイン画面表示 +**group**: auth +**depends**: [] + +### シナリオ2: ログイン成功フロー +**group**: auth +**depends**: [ログイン画面表示] + +### シナリオ3: 商品一覧表示 +(group 省略 → 独立グループ、auth グループと並列実行可能) +``` + +## シナリオの書き方ガイド + +### 手順の記述ルール + +- 操作対象の要素は **UIに表示されるテキストや役割** で記述する(CSSセレクタは不要) +- Playwright CLI が snapshot から自動的に要素を特定する +- 曖昧さを避けるため、ページ上の位置も補足する + +**良い例**: +``` +1. ページ上部の「ログイン」リンクをクリックする +2. 「メールアドレス」入力欄に "test@example.com" を入力する +3. 「パスワード」入力欄に "Test1234!" を入力する +4. 「ログイン」ボタンをクリックする +``` + +**悪い例**: +``` +1. #login-link をクリック +2. input[name=email] に入力 +``` + +### 期待結果の記述ルール + +- 具体的な表示テキストを記述する +- 状態の変化を明記する +- 「正しく動く」のような曖昧な表現は避ける + +**良い例**: +``` +- [ ] ダッシュボードページに遷移する +- [ ] 「ようこそ、テストユーザーさん」と表示される +- [ ] ナビゲーションに「ログアウト」リンクが表示される +``` + +**悪い例**: +``` +- [ ] ログインが成功する +- [ ] 正しいページが表示される +``` diff --git a/skills/dev-webtest/references/visual-check-criteria.md b/skills/dev-webtest/references/visual-check-criteria.md new file mode 100644 index 0000000..987e8eb --- /dev/null +++ b/skills/dev-webtest/references/visual-check-criteria.md @@ -0,0 +1,144 @@ +# 視覚チェック判定基準 + +スクリーンショットをAI(Claude)が確認する際の判定基準。 + +## 判定レベル + +| レベル | 意味 | アクション | +|-------|------|----------| +| ✅ 問題なし | 視覚的に正常 | なし | +| ⚠️ 軽微な問題 | 機能に影響しないが改善推奨 | 自動修正可能 | +| ❌ 重大な問題 | ユーザー体験に大きく影響 | ユーザー承認後に修正 | + +## チェック項目と具体例 + +### 1. レイアウト崩れ + +**✅ 正常**: +- 要素が意図した位置に配置されている +- カラム構造が保たれている +- フッターがページ下部にある + +**⚠️ 軽微**: +- 要素間の余白が不均一だが読みやすさに影響なし +- 微妙な位置ずれ(数ピクセル程度) + +**❌ 重大**: +- 要素が重なって表示されている +- コンテンツがコンテナからはみ出している +- ナビゲーションが表示されない +- フッターがコンテンツに重なっている +- 意図しない横スクロールが発生している + +### 2. テキスト表示 + +**✅ 正常**: +- テキストが読みやすい +- 適切なフォントサイズ +- 行間が十分 + +**⚠️ 軽微**: +- フォントサイズがやや小さい(12px未満) +- 行間がやや狭い +- テキストの切り詰め(ellipsis)が意図しない場所で発生 + +**❌ 重大**: +- 文字化け(□、?、意味不明な文字の羅列) +- テキストが見えない(背景色と同色) +- テキストがコンテナからはみ出して読めない +- フォントが完全に崩壊している + +### 3. 色・コントラスト + +**✅ 正常**: +- テキストと背景のコントラスト比が十分(WCAG AA: 4.5:1以上) +- ボタンの状態が色で区別できる +- リンクが識別可能 + +**⚠️ 軽微**: +- コントラスト比がギリギリ(4.5:1 前後) +- プレースホルダーテキストが薄すぎる + +**❌ 重大**: +- テキストと背景が同系色で読めない +- ボタンが背景に溶け込んでクリックできる場所が分からない +- エラーメッセージが目立たない(赤背景に赤文字等) + +### 4. 画像 + +**✅ 正常**: +- 画像が正しいサイズで表示 +- アスペクト比が保たれている +- alt属性が設定されている + +**⚠️ 軽微**: +- 画像の解像度がやや低い +- サムネイルの切り取りが最適でない + +**❌ 重大**: +- 画像が表示されない(壊れたアイコンが表示) +- アスペクト比が崩れて歪んでいる +- 画像がページ全体を覆っている +- alt属性がなく画像内容が不明 + +### 5. フォーム要素 + +**✅ 正常**: +- 入力欄が適切なサイズ +- ラベルが入力欄と紐づいている +- ボタンのテキストが読みやすい + +**⚠️ 軽微**: +- 入力欄の高さが不均一 +- ボタンのパディングが狭い + +**❌ 重大**: +- 入力欄が極端に狭い/広い +- ボタンが小さすぎてクリックしにくい +- フォーム要素が重なっている +- ドロップダウンが画面外にはみ出す + +### 6. ナビゲーション + +**✅ 正常**: +- メニュー項目が整列している +- 現在のページがハイライトされている +- リンクが機能している + +**⚠️ 軽微**: +- アクティブ状態のスタイルが分かりにくい +- メニュー項目の間隔が不均一 + +**❌ 重大**: +- ナビゲーション全体が表示されない +- メニュー項目が重なっている +- ドロップダウンメニューが開かない/閉じない + +### 7. レスポンシブ固有 + +**✅ 正常**: +- ビューポートに応じたレイアウト切り替え +- タッチターゲットが44px以上(モバイル) +- 横スクロールなし + +**⚠️ 軽微**: +- ブレークポイント付近で若干のずれ +- タッチターゲットがやや小さい(32-44px) + +**❌ 重大**: +- モバイルで横スクロールが必要 +- タッチターゲットが小さすぎる(32px未満) +- ナビゲーションがモバイルで操作不能 +- コンテンツが画面幅を超えている + +## 報告フォーマット + +```markdown +### ページ: <URL> +- **判定**: ✅ / ⚠️ / ❌ +- **スクリーンショット**: `screenshots/YYYY-MM-DD/<filename>.png` +- **所見**: + - [具体的な問題の説明] + - [問題の場所(ページ上のどこか)] + - [推奨する修正方法] +```