【AI駆動開発】ソースコードから仕様書をリバースエンジニアリングする方法
はじめに
最近、大規模システムの引き継ぎ案件を受けました。という経緯のもと、少し前に【AI駆動開発】100ページ超のPDFをMarkdownに変換してAIに読ませる方法という記事を掲載しました。
前回は資料のほとんどがPDFやら、エクセルやらで作成されているということを書きましたが、そんな状態のプロジェクトですので、もちろん"仕様書"なんてものはありません笑
なので、今回もLLM大先生を利用して、ソースコードからの仕様書のリバースをしていきたいと思います(エクセルをAIが読みやすい形式に変換する方法については引き続き調査中なので、完成したら共有します)。
前回の記事と同じく、この記事の最後に「ワークフロー」と「Pythonスクリプト」を載せています。
AntigravityやCursorをお使いの方は、それをコピペしてAIに「これで仕様書を作って」と伝えるだけで、あとはAIが勝手にやってくれます。人間がやることは、コーヒーを飲みながら進捗を眺めることくらいです☕
最終的な出来上がり品
今回の検証に使わせていただいたアプリ:DroidKaigi 2025 Conference App
今回このワークフローの検証に使わせていただいたのは、DroidKaigi 2025の公式カンファレンスアプリ(conference-app-2025)です。
DroidKaigiは今年で11回目を迎える、Android開発者のための国内最大級カンファレンスです。2025年9月10日〜12日の3日間開催予定で、その公式アプリがオープンソースで公開されています。
アプリの主な機能
- タイムテーブル(Timetable): セッション一覧の表示、ブックマーク機能
- プロフィールカード(Profile Cards): 参加者プロフィールの作成・共有
- コントリビューター一覧: アプリ開発に貢献した人たちの紹介
- フロアマップ: 会場案内
- スポンサー情報: 協賛企業の紹介
なぜこのアプリを選んだか
- Kotlin Multiplatform(KMP)+ Compose Multiplatform という最新技術スタックで、実務で見かける典型的なモバイルアプリ構成
- 約13画面と適度な規模感で、ワークフローの検証に最適
- オープンソースなので記事で堂々と紹介できる(DroidKaigiコミュニティに感謝です🙇)
この記事では、このアプリのソースコードを題材に「AIに仕様書を書かせる」ワークフローを解説していきます。
今回の引き継ぎ案件の問題:仕様書がない
PMが欲しいもの
引き継ぎ案件でPMが最初にぶつかる壁は「このシステム、結局何ができるの?」という問いです。
欲しいのはシンプル。「どの画面に何があって、ボタンを押すと何が起きるか」。エンドユーザーに説明できるレベルの仕様書です。
でも今回の現実
- ソースコードはある
- 仕様書はない(「コードが仕様書です」というパワーワード)
- 中身を理解している人が誰もいない
「そんなんエンジニアに聞けばいいじゃん」....と思うじゃないですか。
そんなことしたら多分エンジニアに睨まれます笑
そもそも引き継ぎ案件なので、全体像を把握しているエンジニアなんて誰もいないんですよ。仮にいたとしても、彼らもソースコードから自分の担当範囲、かつ読んだところを把握という感じです。大規模プロジェクトの仕様を全て把握するなんて土台無理な話な訳ですが。
だからAIに頼ってみた
PMやディレクターが欲しいのは、人間が読める仕様書です。ソースコードだけではどうしようもありません。
と、言うことで、AIにソースコードを読ませて、仕様書を書かせればいい!!!
最近のAIの有能性を見れば朝飯前だろ。
...と、最初は簡単に考えていました笑
丸投げしたら「感想文」が返ってきた
最初は素直にAIに「このKotlinソースコードを読んで、仕様書を書いて」と頼みました。
期待に胸を膨らませてAIに頼むと、こんな無慈悲な回答が返ってきます。
- タイムテーブル:セッションの表示
- セッション詳細:詳細情報の表示
- プロフィール:カードの作成
…馬鹿野郎、それは仕様書じゃない。ただの「感想文」だ。
PMやディレクターが必要なのは「エッセンス」ではありません。血の通った「詳細」です。
- ブックマークボタンを押したとき、状態がどう変わり、アイコンは即座に切り替わるのか
- プロフィール作成の入力欄は必須なのか、URL形式チェックはあるのか
- セッション詳細からカレンダー登録ボタンを押すと、OSのどのAPIを叩くのか
これらを全部「いい感じに要約」して削ぎ落とすAIの特性は、仕様書作成においては最大の障害となります。
なぜこんなことになるのか?
何度もAIを使い倒した結果、ある法則を発見しました。
AIが必ずやらかす「3つの悪癖」を発見した
AIを限界まで使い倒してわかった、仕様書作成を破壊する**「AIの三大悪癖」**がこれです。
悪癖1:推測する(読んだふり)
ファイル名が TimetableScreen.kt だから、きっとタイムテーブル画面だろう。セッション一覧があって、検索ボタンがあって……。
AIは「ありそうな機能」を脳内で捏造します。実在しない機能をさも事実のように書く。これは仕様書として致命的です。
実例:
feature/ ディレクトリの羅列だけ見て「この9つが全部だろう」と推測した結果、ボトムナビの5つ目のタブ(Profile)が丸ごと漏れていたのです。
悪癖2:省略する(中だるみ)
最初の数ページは丁寧に書く。しかし、中盤から急に飽き始める。
「以下同様の処理」「詳細はソースコード参照」。
省略するなら、お前の存在意義は何だ? と問い詰めたくなる瞬間です。
実例:
TimetableScreen.kt において、「タイムテーブルを表示する」と記述され、内部の一覧形式切り替え(Grid/List)、日付タブ(Day1/Day2)、ブックマークボタンの即時反映等が全て欠落。
悪癖3:曖昧に逃げる(責任回避)
「適切なメッセージを表示」「正しく処理する」。
「適切」って具体的に何だ? 200文字制限なのか、特殊文字不可なのか。そこを書かないAIは、ただの要領のいい部下と同じです。
都度修正は「モグラ叩き地獄」だった
悪癖がわかったなら、直せばいい。
最初は、AIが変な出力を出すたびに「そこ違う、直して」「いや、もっと詳しく」とプロンプトを修正していました。
でもこれ、地獄なんですよ。
- 「ここ省略しないで」→ 別の場所で省略する
- 「技術用語を使わないで」→ 違う技術用語を使う
- 「推測しないで」→ 別の箇所で推測する
まるでモグラ叩きです。
1回の仕様書生成で、平均10〜20回の修正指示を出していました。しかも、次の仕様書を作るときには同じ問題がまた発生する。
「これ、毎回やってられるか?」と思ったのが正直なところです。
そこで発想を転換しました。
「その場で修正する」のではなく、「最初からやらかせない」ようにルールで縛ればいいんじゃないか?
「9つのルール」でAIを檻に入れる
自由を与えるとAIはサボる。ならば、徹底的な制約で縛り上げるしかありません。
試行錯誤の末に辿り着いた、AIの悪癖を封じ込める**「9つの鉄則」**がこれです。
| No. | ルール | 解決する悪癖 |
|---|---|---|
| 1 | ボタンには「結果」を強制する(遷移先やAPIを明記) | 曖昧な逃げ |
| 2 | ※印(注釈)の1対1対応(孤立した※を許さない) | 省略 |
| 3 | 1機能=1行の徹底(ダイアログやモーダルを独立させる) | 粒度の崩壊 |
| 4 | 未実装は🚧、バグは⚠️で晒し出す(美化を禁止する) | 推測・捏造 |
| 5 | 【最重要】「推測」の禁止とツール実行の強制(ログがなければ認めない) | 推測・捏造 |
| 6 | 「要約・省略」の完全禁止(長い出力を分割してでも守らせる) | 省略 |
| 7 | 技術用語(コンポーネント名)の混入禁止(ユーザー視点を維持) | エンジニア視点 |
| 8 | 曖昧語の禁止と実装値(文字数・正規表現)の記載 | 曖昧な逃げ |
| 9 | 4つのUIステート(Loading/Empty/Error/Success)の網羅 | 省略 |
特に効果があった3つのルール
ルール5:「推測」の禁止とツール実行の強制
これが最も重要。**「ファイルの中身を見ずに推測して書くことは『捏造』であり、固くこれを禁ずる」**と明記しました。
具体的には:
- 仕様書を作成する際は、必ず
view_fileツールを使用してソースコードを実際に開いて読むこと - ファイル名やディレクトリ構造だけで中身を推測してはならない
- 「読みました」という虚偽の報告も禁止(ツール実行ログが必要)
これを入れてから、「パスワードリセット機能」みたいな幻覚が激減しました。
ルール6:「要約・省略」の完全禁止
**「どんなに行数が長くなっても、品質を下げるくらいなら分割せよ」**と明記。
AIは出力が長くなると途中で「以下同様」と逃げたがるので、「一度の出力で収まらない場合は分割して出力すること」と逃げ道を塞ぎました。
ルール8:曖昧語の禁止と実装値の記載
「適切な形式」「いい感じに」といった表現を禁止し、コードにある「値」を書けと強制。
- ❌ NG:
♦︎メールアドレス入力欄(適切な形式で入力) - ✅ OK:
♦︎メールアドレス入力欄(必須、Regexチェックあり、最大255文字)
バリデーションライブラリや定数ファイルを読ませて、そこにある数値・正規表現・文言を仕様書に反映させることで、「曖昧な逃げ」を封じました。
1ファイル主義が大惨事を招いた
9つのルールを作った!これで完璧だ!
...と思ったのも束の間、次の問題が発生しました。
最初、すべてのルールと手順を1つのMarkdownファイルに詰め込んでいたんです。
するとどうなったか?
問題1:AIが途中でルールを忘れる
ファイルが長くなりすぎて、AIが最初の方に書いたルールを途中で忘れてしまう。
「ルール5(推測禁止)に従って...」と最初は言っていたのに、中盤では平気で推測し始める。
問題2:どこまで進んだかわからなくなる
1ファイルに全工程を書いているので、「今どのフェーズにいるのか」が曖昧になる。
結果、同じ作業を2回やったり、必要な作業をスキップしたり。
問題3:ルールの衝突
これが一番ヤバい。
**「ルール3:1機能=1行」と「リスト・入力画面は詳細リスト形式で」**というルールを併記していたら、AIは「1機能=1行」を優先してしまって、タイムテーブル画面を細かく刻んで提出してきた。
結局、**「結局この画面に何が表示されてるの?」**という一覧性が死んでしまいました。
「4フェーズ分離」で迷子を防ぐ
そこで、ワークフローを4つのフェーズに分離して、別ファイルに分けることにしました。
【ここにディレクトリ構成図を貼る】
.agent/workflows/
├── spec-from-source/
│ ├── 00_master.md # マスターワークフロー(全体制御)
│ ├── 01_rules.md # 9つの必須ルール ← 常に参照
│ ├── 02_planning.md # Phase 1: 計画立案
│ ├── 03_code-analysis.md # Phase 2: コード精読
│ ├── 04_csv-writing.md # Phase 3: CSV作成
│ ├── 05_verification.md # Phase 4: 検証
│ └── 06_checklist.md # セルフチェックリスト
└── create-spec-from-source.md # エントリーポイント
ポイント1:ルールファイルは独立させて「常に参照」
01_rules.md にルールをまとめて、各フェーズのファイルから「必ず01_rules.mdを先に読んでから作業すること」と指定。
これで、ルールを忘れる問題が解決しました。
ポイント2:フェーズを明確に分離
Phase 1: 計画立案(Planning)
├─ ソースコードのディレクトリ構造を確認
├─ 機能カテゴリに分割
└─ 作業計画を立てて「承認」を得る
Phase 2: コード精読(Code Analysis)
├─ 【Step 0】アプリ全体構成の確認(必須)
├─ view_file で1ファイルずつ泥臭く読む
├─ UI要素・アクション・API・バリデーションを抽出
└─ 未実装・バグを特定
Phase 3: CSV作成(CSV Writing)
├─ 参照CSVのフォーマットに従って記述
├─ 9つのルールを厳守
└─ 詳細リスト形式で網羅的に記載
Phase 4: 検証(Verification)
├─ HTMLプレビュー生成
├─ セルフチェックリストで品質確認
└─ 報告
ポイント3:後から追加した「Step 0」
運用中に**「トップレベル画面の見落とし」**という問題が発生しました。
具体的には、feature/ ディレクトリの一覧だけを見て解析対象を決めていたところ、ボトムナビゲーションの5つのタブのうち1つ(Profile)を見落とすという事態が発生。
そこで、Phase 2の冒頭に**「Step 0: アプリ全体構成の確認」**を追加しました。
#### 0-1. エントリーポイントの特定
以下のファイル/ディレクトリを探して `view_file` で確認する:
- ナビゲーショングラフ(AppGraph, NavGraph, Router等)
- メイン画面のScaffold(MainScreen, RootScreen等)
- ボトムナビゲーション/タブ定義
#### 0-2. 画面一覧の抽出と照合
上記から「トップレベル画面」のリストを作成し、feature/ ディレクトリと照合する。
完成したワークフローの成果
ここまで読んでくださった方は、「結局、人間が何度もフィードバックを与えて修正させるんでしょ?」と思うかもしれません。
違います。
最終的に完成したワークフローでは、「計画承認」と「最終確認」以外の人間の介入が不要になりました。
つまり、途中で「ここが違う」「ここを直して」といった修正指示を出す必要がなくなったのです。
なぜか?
9つのルールとフェーズ分けが、AIの「やらかし」を事前に封じ込めているからです。
- ルール5(推測禁止)があるから、AIは存在しない機能を捏造しない
- ルール6(省略禁止)があるから、AIは途中で「以下同様」と逃げない
- Step 0(アプリ全体構成確認)があるから、AIは画面を見落とさない
- フェーズ分離があるから、AIは今何をすべきか迷わない
**「やってはいけないこと」を先に明文化しておく。**これが、プロンプトエンジニアリングの本質です。
Before/After
Before:
- ソースコード:Kotlin Multiplatformで13画面
- 仕様書:なし
- 状況:「この画面には何があるの?」→ ソースコードを読むしかない
After:
- 仕様書:CSV + HTMLプレビューで作成完了
- 所要時間:約10分(人間の介入は計画承認と最終確認のみ)
- 状況:ブラウザで一覧確認可能
正直、人間が手作業でやったら丸一日かかる作業が、10分(規模によります)で終わります。しかも、途中で修正指示を出す必要もありません。
最終的にできた成果物と業務での成果について
最終的にはCSVファイルと、見やすいようにHTMLに変換するようにしています。
ワークフローやスクリプトは最後に付録として入れています!
CSVファイル

ポイント:
- ✅ ボタンには全て「押したら何が起きるか」が書かれている(ルール1)
- ✅ ※印と備考が1対1で対応している(ルール2)
- ✅ 技術用語は備考に追いやり、機能内容はエンドユーザー視点で記述(ルール7)
忘れてたけど:
記事の中では紹介できませんでしたが、コードを読み取ってボタンはあるけど未実装だったり、不整合や不具合などがあると見つけてくれてこんな感じで「コメントアウトされているよ」と言ったことも教えてくれます。

業務での検証結果
記事には載せられませんが、今回のワークフローを使って件の大規模システムの引き継ぎプロジェクトでも本スクリプトを利用しました。生成された仕様書を片手に、実際にアプリや管理画面を操作して画面遷移や挙動を一つひとつ突き合わせた結果、ボタンの名称など細かい違いはありましたが、ハルシネーション(存在しない機能の捏造)は見受けられませんでした。また、挙動や処理に関してもほぼほぼ仕様書の記載の通りとなっており、出来上がった仕様書をそのまま流用することができています。
推奨環境
検証にはオープンソースを扱えるAntigravityを使いましたが、業務での実戦投入には、よりセキュアで高機能なCursor + Claude Opus 3.5の環境を推奨します。
なお、Antigravityを個人アカウントで利用する場合、データが学習に使われる可能性があります。業務のソースコードを扱う場合は、会社契約のアカウントか、Cursorなど別のツールをお使いください。
他にも使える場面
今回は「引き継ぎ案件で仕様書がない」という文脈でしたが、このワークフローは他の場面でも有効です:
- レガシーシステムのモダナイズ: 古いシステムの仕様を可視化してからリファクタリング
- 新メンバーのオンボーディング: 実装済みの機能を網羅した資料として活用
- 品質保証のベースライン作成: テストケース作成の元ネタとして
- クライアントへの説明資料: 「今何ができるのか」を可視化
まとめ:AIを「サボらせない」ための3つの心得
-
プロンプトで逐一修正 → ルールで事前に縛る
- 毎回修正するのはモグラ叩き地獄
- 「やってはいけないこと」を明文化しておく
-
1ファイルに全部詰め込み → フェーズ分離してディレクトリ構成に
- AIが途中でルールを忘れる問題を解決
- 各フェーズで「やること」を明確に
-
結果を見てから確認 → Step 0で全体構成を先に把握
- 見落としを防ぐには「地図」を先に読む
- featureフォルダの羅列だけで判断しない
AIは優秀な部下ですが、放置するとすぐにサボります。
「厳格なルール」と「段階的なフェーズ分け」の組み合わせで初めて、実務に耐える成果物が手に入るのです。
おわりに
「AIにソースコードを読ませれば仕様書が出てくる」なんて甘い幻想でした。
現実は、AIの悪癖と戦い、ルールで縛り、フェーズを分けて整理する泥仕合です。
でも、そこを乗り越えた先には、人間だけでは到達できない品質と速度があります。
そして、こうして完成したワークフローを冒頭の引き継ぎ案件に投入した結果、無事に仕様のブラックボックス化を解消できました。 今まで「この画面、何があるんだっけ?」と迷子になっていた状態から、プロジェクトを引き継いだ担当者が「このボタンを押すとこの画面に遷移する」と説明できるようになったのです。
このワークフローが、皆さんのプロジェクトの一助となれば幸いです。
また、私個人としてはこのようにAIで今までできなかったことができるようになる、ということがとても楽しく、いとまがあればAIを利用してこのような効率化をしているくらいです笑
なので、みなさんの中で「こんな課題があるんだけど解決できないかな」といったことをお持ちでしたらぜひご連絡ください!お約束はできませんが、私の方で可能な限り対応してみたいと思います(なお、対応した場合には記事に投稿させていただきますのでその点はご容赦ください)。
こちら私のXアカウントです。
付録:ワークフローとスクリプト
以下のファイルを .agent/workflows/spec-from-source/ に配置してください。
ワークフロー構成
.agent/workflows/
└── spec-from-source/
├── 00_master.md # マスターワークフロー(全体制御)
├── 01_rules.md # 9つの必須ルール
├── 02_planning.md # Phase 1: 計画立案
├── 03_code-analysis.md # Phase 2: コード精読
├── 04_csv-writing.md # Phase 3: CSV作成
├── 05_verification.md # Phase 4: 検証
└── 06_checklist.md # セルフチェックリスト
使い方
/create-spec-from-source
と入力するだけで、AIがワークフローを読み込んで作業を開始します。
ワークフローファイル
00_master.md - マスターワークフロー
ワークフロー全体を制御するエントリーポイントです。4つのPhaseの流れと完了条件を定義しています。
ファイル内容を見る
---
Discription:ソースコードから機能仕様書を作成する(分割版マスター)
---
# create-spec-from-source(分割版)
## 概要
このワークフローは、ソースコードを精読し、参照CSV準拠の機能仕様書をリバースエンジニアリングで作成するための**マスターワークフロー**です。
> [!CAUTION]
> **このワークフローは4つのPhaseで構成されています。各Phaseの完了条件を満たさない限り、次のPhaseに進むことは禁止されています。**
---
## Phase構成
| Phase | ファイル | 内容 | 完了条件 |
|-------|----------|------|----------|
| **1** | [02_planning.md](./02_planning.md) | 計画立案・承認取得 | ユーザーから計画承認を得る |
| **2** | [03_code-analysis.md](./03_code-analysis.md) | ソースコード精読 | 全対象ファイルをview_fileで読む |
| **3** | [04_csv-writing.md](./04_csv-writing.md) | CSV仕様書作成 | 6列フォーマットでCSV完成 |
| **4** | [05_verification.md](./05_verification.md) | 検証・HTML生成 | csv_to_html.py実行完了 |
---
## 共通リファレンス
- **[01_rules.md](./01_rules.md)** - 9つの必須ルール(全Phase共通)
- **[06_checklist.md](./06_checklist.md)** - セルフチェックリスト
---
## 実行フロー
```
[ユーザー依頼]
↓
[Phase 1: 計画] → 02_planning.md を読む
↓ ※計画承認がないと先に進めない
[Phase 2: 精読] → 03_code-analysis.md を読む
↓ ※view_fileでコードを読まないと先に進めない
[Phase 3: CSV作成] → 04_csv-writing.md を読む
↓ ※12列CSVが完成しないと先に進めない
[Phase 4: 検証] → 05_verification.md を読む
↓
[完了: CSV + HTML を納品]
```
---
## 禁止事項(絶対厳守)
1. **Phase 1を飛ばしてコードを読み始めること**
2. **計画承認なしにCSV作成を開始すること**
3. **view_fileを使わずに機能を推測すること**
4. **csv_to_html.py以外でHTMLを生成すること**
5. **1回の出力で全てを終わらせようとすること**(品質低下の原因)
---
## 次のステップ
**まず [02_planning.md](./02_planning.md) を読んでPhase 1を開始してください。**
01_rules.md - 9つの必須ルール
AIが仕様書を作成する際に絶対に守るべき9つのルールを定義しています。これが品質の要です。
ファイル内容を見る
---
description: 9つの必須ルール(spec-from-source共通リファレンス)
---
# 必須ルール(厳守)
以下の9ルールは**絶対に守る**こと。違反すると仕様書の品質が著しく低下する。
---
## ルール1: ボタン・アクションには「押下後の結果」を必ず書く
**■のアクション要素には、押下後に何が起きるかを必ず記載する。**
- **NG**: `■登録ボタン` のみ
- **OK (単一)**: `■登録ボタン※3※4\n 入力内容を検証しAPIで登録処理を実行。成功時は一覧画面へ遷移する`
**分岐がある場合(Confirm、モーダル等)は、各分岐を「・〇〇選択時:」で列挙すること。**
- **OK (分岐)**:
```
■以下のIDを削除しますか?(confirm)※2
・OK選択時: POST /api/account/deleteを実行し、一覧を再取得する
・キャンセル選択時: ダイアログを閉じ、何もしない
```
記載すべき内容の例:
- 遷移先(〇〇画面へ遷移する)
- 実行処理(APIをコールする、DBを更新する)
- 表示の変化(モーダルを閉じる、一覧を再取得する)
- エラー時(PageErrorMessageで表示する)
---
## ルール2: ※印は機能内容と備考で1対1対応させる
**機能内容で使った※番号と、備考の※番号は必ず1対1で対応させる。**
- 機能内容に `※3` があれば、備考に必ず `※3 [説明]` を書く
- 備考に `※3` を書いたら、機能内容の該当箇所に `※3` を付ける
- ※番号は機能内容内の登場順に振る(※1, ※2, ※3...)
- **孤立した※を作らない**(機能内容にない※を備考に書かない、備考にない※を機能内容に付けない)
---
## ルール3: 粒度は「1機能 = 1行」とする
**1行 = 1つの機能単位。1画面に複数機能がある場合は行を分ける。**
- メイン画面、サブ機能、ダイアログ、モーダル、確認画面は**それぞれ別行**にする
- 例: 「ログイン画面」「ログイン画面_WebView」「設定確認ダイアログ(カメラ許可)」「設定確認ダイアログ(カメラ不可)」→ 4行
- 参照CSVの粒度に合わせる(1画面を複数行に分解する)
---
## ルール4: 未実装・バグは「ダブルアイコン」で記述する(推測禁止)
**コードの実装状況を優先し、機能を捏造してはならない。不完全な項目は、要素アイコン(■/♦︎)の前に状態アイコン(🚧/⚠️)を付与して「併記」すること。**
- `🚧` (**未実装**): ボタンはあるが中身が空、反応しない関数など。
- 例: `🚧■プロフィール編集ボタン\n (反応なし・未実装)`
- `⚠️` (**不整合・バグ**): UI表記と実際の挙動が矛盾している、または明らかな実装ミス。
- 例: `⚠️■アカウント設定ボタン\n デザイン設定画面へ遷移する(表記と遷移先の不一致)`
---
## ルール5: ファイル読み込みツールの使用義務(推測厳禁)
**ファイルの中身を見ずに推測して書くことは「捏造」であり、固くこれを禁ずる。**
- 仕様書を作成する際は、必ず `view_file`(または環境で利用可能なファイル読み込みツール)を使用して、対象のソースコードを**「実際に」開いて読むこと**。
- ファイル名やディレクトリ構造だけで中身を推測してはならない。
- 「読みました」という虚偽の報告も禁止する。実際にツールが実行されたログ(Action)が必要である。
- **読み込み手順**: 主要ファイルを1つずつ、泥臭く開いて中身を確認するプロセスを経ること。
---
## ルール6: 「要約・省略」の完全禁止(詳細度の維持)
**対象範囲が広くても、記述を簡略化(サマリー化)してはならない。**
- **NG**: `■各種設定 ... 設定画面へ遷移(詳細は省略)` のようにまとめること。
- **NG**: `※` の紐付けを省略し、単に「未実装」とだけ書くこと。
- **OK**: どんなに行数が長くなっても、**ルール1〜4(グループ分け、1要素1行、詳細な備考)を維持する**。
- 一度の出力で収まらない場合は、分割して出力すること。品質を下げるくらいなら分割せよ。
---
## ルール7: 技術用語(コンポーネント名)の混入禁止
**機能内容(ユーザーに見える部分)に、実装レベルのコンポーネント名を含めてはならない。**
- **NG**: `♦︎明細一覧(TableView)`、`♦︎入力欄(v-text-field)`
- **OK**: `♦︎明細一覧`、`♦︎入力欄`
- `TableView` や `RecyclerView` などの技術的な情報は、必要であれば**【備考】**に記載すること。
---
## ルール8: 「曖昧語」の禁止と「実装値」の記載(定義の具体化)
**コード上に具体的な定義がある場合、「適切な形式」「いい感じに」といった曖昧な表現を禁止し、実装されている「値」や「ロジック」を正確に記載すること。**
- **NG**: `♦︎メールアドレス入力欄(適切な形式で入力)`
- **OK**: `♦︎メールアドレス入力欄(必須、Regexチェックあり、最大255文字)`
- **NG**: `■保存ボタン(エラー時はメッセージを表示)`
- **OK**: `■保存ボタン(400系エラー時はトーストで"保存に失敗しました"を表示、500系はダイアログ表示)`
> [!IMPORTANT]
> バリデーションライブラリ(Zod, Yup等)や型定義、定数ファイルを読み込み、そこにある「数値」「正規表現」「文言」を仕様書に反映させること。
---
## ルール9: 4つの「UIステート」の網羅(状態の完全性)
**画面には必ず複数の状態がある。単に「表示する」と書くのではなく、以下の4状態についてコードを確認し、実装が存在する場合は記述すること。**
| ステート | 説明 |
|----------|------|
| **Loading** | 読み込み中の表示(スケルトン、スピナー、ボタン非活性化など) |
| **Empty** | データが0件の場合の表示(「データがありません」の表示やイラスト) |
| **Error** | 通信エラーやバリデーションエラー時の挙動 |
| **Success** | 処理成功時のフィードバック(トースト、遷移、完了画面) |
**記述例:**
- `※3 データ取得中はスピナーを表示し、完了まで全入力欄を非活性(disabled)にする`
- `※4 0件時は「投稿がありません」とイラストを表示`
- `※5 通信エラー時はトースト"接続に失敗しました"を3秒間表示`
02_planning.md - Phase 1: 計画立案
対象ファイルを洗い出し、カテゴリ分割を計画し、ユーザー承認を得るまでの手順です。
ファイル内容を見る
---
Discription:Phase 1 - 計画立案とユーザー承認取得
---
# Phase 1: 計画(Planning)
> [!CAUTION]
> **このPhaseを完了しない限り、Phase 2(コード精読)に進むことは禁止されています。**
---
## ★ 最初に読むこと(必須)
**計画を立てる前に、必ず [01_rules.md](./01_rules.md) を読んで9ルールを把握すること。**
これを飛ばすと、計画段階でルール違反が発生し、手戻りの原因となる。
---
## 背景・目的
既存のソースコードを精読し、**参照CSV(プロジェクト管理表・フロントエンド機能仕様書)の粒度・書き方に準拠した**機能仕様書をリバースエンジニアリングで作成することを目的としています。
> [!WARNING]
> あなたは過去に何度も失敗を繰り返しているため、以下を必ず推敲するようにユーザから命令を受けています。命令に背くことは許されることではないため、以下を精読し必ず約束を守るようにし、ユーザからの信頼を集めてください。ユーザは事実のみを望んでいるため、あなたの解釈はやめ、不明があればユーザに相談するようにして進めてください。
**必須:** コードにバグや未実装(中身が空の関数など)がある場合、**AI側で補完・修正せず、その「不完全な状態」をありのまま記述してください。**「あるべき姿」ではなく「現在の姿」を記録することが目的です。
> [!CAUTION]
> まずはいきなり作り始めるのではなく、ワークフローを完全に理解した後に、このルールを完全に準拠するための計画を日本語で作成し、ユーザに計画を承認してもらうようにしてください。また、チェックリストを用いて、タスクが完了するごとにチェックリストにチェックをすることで、正確にタスクを完了し切るようにしてください。**このフローを飛ばすことを宗教に誓って禁じます。**
また、時間をいくらかけてもいいので、最高品質を優先するようにお願いします。
---
## 入力
- **ソースコード**(画面コンポーネント、API、ルーティング等)
- **既存の仕様書CSV**(修正・更新の場合)
- **保存先の指定**(ユーザー指定があれば優先)
## 出力
- CSV形式の機能仕様書(参照CSVと同じヘッダー構成)
- **HTMLプレビュー**(同じフォルダに保存)
> [!CAUTION]
> **HTMLプレビューは必ず `csv_to_html.py` を使って生成すること。手動でHTMLを作成してはならない。これは絶対ルールである。**
## デフォルト保存先
```
[ユーザー指定フォルダ] / 機能一覧_[対象名]_verX.X.csv
[ユーザー指定フォルダ] / 機能一覧_[対象名]_verX.X.html
```
※ユーザーから別の保存先を指定された場合は、そちらを優先する。
---
## 目的
1. ユーザーからの入力(対象ソースコード・参照CSV・保存先)を確認する
2. 対象ファイルを洗い出す
3. 分析計画を立てる
4. **ユーザーから計画の承認を得る**
---
## 手順
### Step 1: 入力の確認
ユーザーから以下を受け取る(または確認する):
| 項目 | 内容 |
|------|------|
| ソースコード | 画面コンポーネント、API、ルーティング等のパス |
| 参照CSV | 粒度・書き方のサンプル(既存の機能仕様書等) |
| 既存仕様書 | 修正・更新の場合 |
| 保存先 | ユーザー指定があれば優先 |
### Step 2: 対象ファイルの洗い出し
`find_by_name` または `list_dir` を使用して、対象となるファイルを列挙する。
**例:**
```
[対象ディレクトリ]
└── View/
├── Login/
│ ├── LoginViewController.swift
│ └── ...
├── Main/
│ ├── HomeViewController.swift
│ └── ...
```
### Step 3: カテゴリ分割の計画
> [!IMPORTANT]
> **全画面を一度に出力すると品質が低下する。カテゴリごとに分割して作成・出力し、最後に統合すること。**
対象ファイルを以下のようにカテゴリ分けする:
| カテゴリ | 対象画面例 |
|----------|------------|
| 認証・ログイン系 | Start, Login, Tos, Auth |
| メイン画面系 | Home, Timeline, Notifications |
| 投稿・詳細系 | Post, PostDetail, Profile |
| 設定・その他 | Settings, DesignSettings, License |
### Step 4: 計画書の作成
以下の形式で計画書を作成する:
```markdown
# [対象名] 機能仕様書作成計画
## 対象ファイル
- [ファイル一覧]
## カテゴリ分割
- Phase 2-A: [カテゴリ1]
- Phase 2-B: [カテゴリ2]
- ...
## 出力ファイル
- CSV: [パス]
- HTML: [パス]
## 参照ルール
- [01_rules.md](./01_rules.md) の9ルールを遵守する
```
### Step 5: ユーザー承認の取得
計画書をユーザーに提示し、承認を得る。
> [!CAUTION]
> **承認なしにPhase 2に進むことは絶対に禁止。**
---
## 完了条件
- [ ] 対象ファイルを列挙した
- [ ] カテゴリ分割を決定した
- [ ] 計画書を作成した
- [ ] **ユーザーから承認を得た**
---
## 次のステップ
承認を得たら、[03_code-analysis.md](./03_code-analysis.md) を読んでPhase 2を開始する。
03_code-analysis.md - Phase 2: コード精読
view_fileでソースコードを実際に読み、UI要素・アクション・API呼び出し等を抽出する手順です。
ファイル内容を見る
---
Discription:Phase 2 - ソースコード精読
---
# Phase 2: コード精読(Code Analysis)
> [!CAUTION]
> **Phase 1の計画承認なしにこのPhaseを開始することは禁止されています。**
---
## 目的
1. `view_file` を使って対象ソースコードを**実際に読む**
2. 各画面の機能・要素・遷移・ロジックを抽出する
3. 分析メモを作成する
---
## 絶対ルール
### ルール5の遵守(推測厳禁)
> **ファイルの中身を見ずに推測して書くことは「捏造」であり、固くこれを禁ずる。**
- 必ず `view_file` を使用してソースコードを開く
- ファイル名やディレクトリ構造だけで中身を推測してはならない
- 「読みました」という虚偽の報告は禁止
### 泥臭く読む
主要ファイルを**1つずつ**開いて中身を確認する。ショートカットはない。
---
## 手順
### Step 0: アプリ全体構成の確認(必須)
> [!CAUTION]
> 個別機能の解析に入る**前に**、以下を必ず確認すること。このステップを飛ばすと主要機能の見落としが発生する。
#### 0-1. エントリーポイントの特定
以下のファイル/ディレクトリを探して `view_file` で確認する:
| 探すもの | 典型的なファイル名 |
|----------|-------------------|
| **ナビゲーショングラフ** | `AppGraph`, `NavGraph`, `Router`, `RootNavigation` |
| **メイン画面のScaffold** | `MainScreen`, `KaigiApp`, `RootScreen`, `TabBarController` |
| **ボトムナビゲーション/タブ定義** | `MainScreenTab`, `BottomNav`, `TabItem`, `MainTabBarController` |
#### 0-2. 画面一覧の抽出と照合
上記から「トップレベル画面」のリストを作成し、`feature/` ディレクトリと照合する:
```markdown
| トップレベル画面 | 対応feature | Phase 1計画に含む |
|------------------|-------------|-------------------|
| Timetable | sessions | [x] |
| EventMap | eventmap | [x] |
| Favorites | favorites | [x] |
| About | about | [x] |
| **Profile** | **profile** | **[ ] ← 漏れ!** |
```
**不一致がある場合は、Phase 1の計画を修正してから次へ進むこと。**
---
### Step 1: カテゴリごとにファイルを読む
Phase 1で決めたカテゴリ分割に従い、1カテゴリずつ読む。
**例: 認証系**
```
view_file: StartViewController.swift
view_file: TosViewController.swift
view_file: AuthWebViewController.swift
```
### Step 2: 各ファイルから情報を抽出
以下の観点でコードを読む:
| 観点 | 確認内容 |
|------|----------|
| **UI要素** | ボタン、入力欄、ラベル、リスト、画像 |
| **アクション** | ボタン押下時の処理、遷移先 |
| **API呼び出し** | エンドポイント、メソッド、レスポンス処理 |
| **バリデーション** | 必須チェック、文字数制限、正規表現 |
| **エラー処理** | エラー時の表示、トースト、ダイアログ |
| **状態管理** | Loading/Empty/Error/Success の実装 |
> [!TIP]
> **API呼び出しについて:** 従来のREST APIだけでなく、GraphQL、SWR系ライブラリ(Soil, React Query等)、gRPCなども含む。データ取得・送信を行うコードは全て記録対象とする。
### ソースコード精読の7観点(詳細)
以下のファイル・情報を精読し、実装から正確に機能を抽出する:
1. **画面コンポーネント** (page.tsx, *.swift, *.kt): 表示項目、ボタン、入力欄、遷移先
2. **API呼び出し** (API.call, fetch, URLSession): エンドポイント、メソッド、リクエスト/レスポンス
3. **ルーティング** (router.push, Link href, pushViewController): 遷移先パス
4. **権限・表示制御** (roleId, isAdmin等): 権限による表示の有無
5. **バリデーション** (required, maxLength, preProcessEditCellProps等): 入力制約
6. **エラー処理** (setError, PageErrorMessage, alert, showToast): エラー時の表示
7. **確認ダイアログ** (confirm, UIAlertController): 確認画面の有無と文言
### Step 3: 分析メモの作成
> [!TIP]
> このメモはCSVに直接転記しない。頭の中(またはメモ)で整理するためのもの。
**バリデーション・制約リスト:**
```
- メールアドレス: 必須、Regex、最大255文字
- パスワード: 必須、8-30文字、半角英数字
```
**ステート変化表:**
```
- ログインボタン押下 → isLoading = true → API呼び出し → 成功/失敗
```
**例外処理フロー:**
```
- 400エラー: トースト「認証に失敗しました」
- 500エラー: ダイアログ「サーバーエラー」
- ネットワークエラー: トースト「接続に失敗しました」
```
### Step 4: 未実装・バグの特定
コードを読む際、以下を特定しておく:
| 状態 | 判別方法 |
|------|----------|
| 🚧 未実装 | 関数の中身が空、TODO/FIXMEコメント、反応しないボタン |
| ⚠️ バグ・不整合 | UI表記と遷移先の不一致、明らかなロジックエラー |
---
## 完了条件
- [ ] 対象カテゴリの全ファイルを `view_file` で読んだ
- [ ] 各画面のUI要素・アクション・遷移を把握した
- [ ] バリデーション・ステート・エラー処理を確認した
- [ ] 未実装・バグを特定した
---
## 次のステップ
全カテゴリの精読が完了したら、[04_csv-writing.md](./04_csv-writing.md) を読んでPhase 3を開始する。
> [!TIP]
> カテゴリごとにPhase 2→3を繰り返し、最後に統合する方法も有効。
04_csv-writing.md - Phase 3: CSV作成
抽出した情報を6列CSVフォーマットに変換するルールと書き方を定義しています。
ファイル内容を見る
---
Discription:Phase 3 - CSV仕様書作成
---
# Phase 3: CSV作成(CSV Writing)
> [!CAUTION]
> **Phase 2のコード精読が完了していない状態でこのPhaseを開始することは禁止されています。**
---
## ★ 最初に読むこと(必須)
**CSVを書き始める前に、必ず [01_rules.md](./01_rules.md) を再読して9ルールを再確認すること。**
特に以下のルールは違反しやすい:
- ルール1: アクションには「結果」を書く
- ルール2: ※印は1対1対応
- ルール4: 未実装/バグは🚧/⚠️で記述
---
## 目的
1. Phase 2で抽出した情報を6列CSVフォーマットに変換する
2. 9つのルールを遵守してCSVを作成する
---
## CSVフォーマット(6列)
```
#,機能カテゴリ,画面名,機能内容,備考,対象API
```
| 列 | 内容 |
|----|------|
| **#** | 連番 |
| **機能カテゴリ** | 機能の分類(認証, アカウント, 共通管理, etc.) |
| **画面名** | 画面ID + 画面名(例: CMS0010 ログイン) |
| **機能内容** | UI要素・アクション・表示の詳細 |
| **備考** | ※番号に対応する詳細説明 |
| **対象API** | 使用するAPIエンドポイント |
---
## 機能内容の書き方
### 基本構造
```
[画面概要]※1
[入力/表示項目の導入文]※2
【グループ名】
♦︎項目1(補足)
♦︎項目2(補足)
■アクションボタン※3※4
押下後の結果を記述する
```
### 要素の種類
| アイコン | 種類 | 用途 |
|----------|------|------|
| **■** | アクション | ボタン、リンク、選択操作 |
| **♦︎** | 表示/入力 | ラベル、テキスト、入力欄 |
| **🚧** | 未実装 | 中身が空の関数、反応なし |
| **⚠️** | バグ/不整合 | 表記と挙動の不一致 |
### ルール1: アクションには「結果」を必ず書く
```
■登録ボタン※3※4
入力内容を検証しAPIで登録処理を実行。成功時は一覧画面へ遷移する
```
**分岐がある場合:**
```
■削除確認ダイアログ※2
・OK選択時: DELETE /api/itemを実行し、一覧を再取得する
・キャンセル選択時: ダイアログを閉じる
```
### ルール4: 未実装・バグにはダブルアイコン
```
🚧■プロフィール編集ボタン
(反応なし・未実装)
⚠️■アカウント設定ボタン
デザイン設定画面へ遷移する(表記と遷移先の不一致)
```
---
## 備考の書き方
### ルール2: ※印は1対1対応
機能内容の※と備考の※は必ず対応させる。
```
機能内容:
♦︎メールアドレス入力欄※2
■ログインボタン※3※4※5
備考:
※2 必須入力。空の場合はログインボタンが非活性となる
※3 POST /api/login
※4 成功時Cookie保存、24時間有効
※5 失敗時PageErrorMessageでerror表示
```
### ルール9: 4ステートを記述
```
※3 データ取得中はスピナーを表示
※4 0件時は「データがありません」を表示
※5 通信エラー時はトースト表示
※6 成功時は一覧画面へ遷移
```
---
## 入力項目・一覧列の記述形式
### 入力画面の場合
```
ユーザーのプロフィール編集画面を表示する※1
入力する情報は以下とする※2
【基本情報】
♦︎ニックネーム(必須20文字)
♦︎生年月日
♦︎居住地
【詳細プロフィール】
♦︎身長
♦︎体型
■保存ボタン※3※4
POST /api/user/profileを実行し、成功時はマイページへ遷移する
```
### 一覧画面の場合
```
会員ユーザーの一覧を表示する※1
表示する列は以下とする※2
【基本情報】
♦︎ユーザーID
♦︎ニックネーム
♦︎年齢
【ステータス】
♦︎本人確認状況
♦︎課金プラン
■詳細ボタン※3
各行からユーザー詳細画面へ遷移する
```
---
## 禁止事項(ルール6, 7, 8)
| 禁止 | 正しい書き方 |
|------|--------------|
| `♦︎明細一覧(TableView)` | `♦︎明細一覧` |
| `適切な形式で入力` | `必須、最大255文字、Regexチェックあり` |
| 詳細は省略 | 全て列挙する |
---
## 要素の判別
- **アクション要素(`■`)**: ユーザーが操作して何かが起きるもの。ボタン、リンク、プルダウン、セル編集、ファイル選択など
- **表示・静的要素(`♦︎`)**: 情報の表示、入力欄(操作結果が伴わないもの)
- **不整合・バグ(`⚠️`)**: 実装と仕様の不一致、遷移先ミス、明らかなロジックエラー
- **未実装(`🚧`)**: UIはあるが処理が空(empty)であるもの
迷ったら「アクション(■)」を優先するが、バグや未実装が明確な場合は `⚠️` や `🚧` を**先頭に付与**する。
---
## 複数のロジックがある場合
1つのUI要素に対して、裏側の処理が複数ある場合は、`※1※2※3` のように複数の参照番号を付与する。
**良い例:**
- 機能内容: `■ログインボタン※2※3※4\n 認証を行いダッシュボードへ遷移する`
- 備考: `※2 必須入力時はボタン非活性\n※3 POST /api/login、Cookie保存\n※4 認証失敗時PageErrorMessageで表示`
---
## 項目・列の記述ルール(統一フォーマット)
**入力項目**または**一覧リストの表示列**が存在する画面では、項目の多少に関わらず**必ず以下の詳細形式**を用いる。(略称表記は禁止)
### 記述フォーマット
1. **導入文**: 「入力する情報は以下とする」または「表示する列は以下とする」を追加する
2. **グループ見出し**: 関連する項目を【グループ名】でまとめる(項目数が少ない場合は【基本】などで1つにまとめる)
3. **1項目1行**: 各項目を `[状態]♦︎項目名(補足)` で1行ずつ列挙する
**補足(カッコ書き)のルール:**
- 含めてよいもの: バリデーション(必須、文字数)、単位、初期値
- 含めてはいけないもの: コンポーネント名(TableView, Grid等)、変数名
**【最重要】リスト内のアクション要素について(魔の省略トラップ回避)**
リスト形式の中であっても、`■`(アクション)が含まれる場合は、**必ず改行して「押下後の挙動」を記述すること(ルール1の厳守)。**
「リストの一部だから」と油断して、単なるデータ項目と同じように1行で終わらせてはならない。
- **NG**: `■デザイン設定` (1行で終了・挙動不明)
- **OK**:
```
■デザイン設定
デザイン設定画面へ遷移する
```
---
## 変換サンプル(ソースコードから)
**ソースコードの例(ログイン画面):**
- パス: /auth/login
- userId, password 入力欄、空時ボタン非活性
- ログインボタン: POST /api/login、成功時 /dashboard へ push、失敗時 setError
- 日本語入力時はパスワードを空にする
**出力:**
```csv
#,機能カテゴリ,画面名,機能内容,備考,対象API
1,認証,CMS0010 ログイン,"CMS管理者の認証画面を表示する※1
♦︎ログインID入力欄※2
1〜10文字、半角英数字を入力する
♦︎パスワード入力欄※2※3
8〜30文字、半角英数字を入力する。マスク表示(●)
■ログインボタン※4※5※6
認証APIを実行し、成功時はダッシュボードへ遷移する。失敗時はエラーメッセージを表示する","※1 パス: /auth/login
※2 必須入力。空の場合はログインボタンが非活性となる
※3 日本語入力時は入力を空にする
※4 POST /api/login
※5 成功時Cookie(authToken, roleId)保存、24時間有効。localStorageにroleId, displayName保存
※6 失敗時PageErrorMessageでerror表示、ネットワークエラー時は""Failed to login""",POST /api/login
```
---
## 修正・更新時のルール
1. **完全な再出力**: 差分だけでなく、修正箇所を含んだ全ての行を出力する
2. **整合性の維持**: 追加・削除でNoや※番号がずれる場合は、整合性が取れるように振り直す
3. **※の対応確認**: 修正後、機能内容の※と備考の※が1対1で対応しているか必ず確認する
---
## 完了条件
- [ ] 全画面を6列CSVで記述した
- [ ] 全■アクションに「押下後の結果」を書いた
- [ ] ※印が機能内容と備考で1対1対応している
- [ ] 🚧/⚠️で未実装・バグを明記した
- [ ] 技術用語を機能内容に含めていない
---
## 次のステップ
CSVが完成したら、[05_verification.md](./05_verification.md) を読んでPhase 4を開始する。
05_verification.md - Phase 4: 検証
セルフチェックとHTMLプレビュー生成、バージョン管理の手順です。
ファイル内容を見る
---
Discription:Phase 4 - 検証・HTML生成
---
# Phase 4: 検証(Verification)
> [!CAUTION]
> **Phase 3のCSV作成が完了していない状態でこのPhaseを開始することは禁止されています。**
---
## 目的
1. セルフチェックリストで品質確認
2. `csv_to_html.py` でHTMLプレビューを生成
3. バージョン管理ルールに従ってファイルを保存
---
## Step 1: セルフチェック
[06_checklist.md](./06_checklist.md) を開き、全項目をチェックする。
**重点確認項目:**
- [ ] `view_file` 等を使って実際にコードを読み込んだか
- [ ] すべての■ボタンに「押下後の結果」が書かれているか
- [ ] 分岐処理がある場合「・〇〇選択時:」で列挙されているか
- [ ] 未実装/バグを 🚧/⚠️ で記述しているか
- [ ] ※印が機能内容と備考で1対1対応しているか
- [ ] 技術用語が機能内容に含まれていないか
- [ ] 曖昧語を使わず具体的な値を記載しているか
- [ ] Loading/Empty/Error/Success の4ステートを確認したか
---
## Step 2: HTMLプレビュー生成
> [!CAUTION]
> **csv_to_html.py 以外でHTMLを生成することは禁止。手動でHTMLを記述してはならない。**
### 実行コマンド
```bash
python3 csv_to_html.py "<入力CSV>" "<出力HTML>"
```
### csv_to_html.py の場所
プロジェクトルートまたは `97_スクリプト/` フォルダに存在する。
---
## Step 3: バージョン管理
**上書き禁止。常に新規バージョンで保存する。**
| 現在 | 次 |
|------|-----|
| 1.0 | 1.1 |
| 1.9 | 2.0 |
**ファイル命名規則:**
```
機能一覧_[対象名]_ver1.0.csv
機能一覧_[対象名]_ver1.0.html
```
---
## Step 4: 改行コードの確認
**CSVファイルの改行コードは必ずLF(Unix形式)を使用する。**
Google Drive経由でファイルを同期すると、Windows形式のCRLF(`\r\n`)に変換されることがあります。
CRLF形式のCSVは差分ツールやパターンマッチで問題を引き起こすため、以下のルールを守ってください。
### CSVを作成・編集する場合
- Pythonスクリプトで生成する場合: `newline=''` オプションを使用(標準のcsvモジュールが自動的にLFで出力)
- 手動で編集する場合: VS Codeなどのエディタで「LF」改行を選択
### 既存のCRLFファイルをLFに変換する場合
```bash
# 方法1: trコマンド
tr -d '\r' < input.csv > output.csv
# 方法2: sedコマンド(macOS)
sed -i '' 's/\r$//' file.csv
# 方法3: dos2unixコマンド(要インストール)
dos2unix file.csv
```
---
## 完了条件
- [ ] セルフチェックリストの全項目を確認した
- [ ] `csv_to_html.py` でHTMLを生成した
- [ ] バージョン管理ルールに従ってファイル名を付けた
- [ ] 改行コードがLFであることを確認した
---
## 納品物
| ファイル | 用途 |
|----------|------|
| `機能一覧_[対象名]_verX.X.csv` | 機能仕様書本体 |
| `機能一覧_[対象名]_verX.X.html` | ブラウザ表示用プレビュー |
---
## 完了
お疲れ様でした。全Phaseが完了しました。
06_checklist.md - セルフチェックリスト
9ルールが守られているか確認するためのチェックリストです。Phase 4で使用します。
ファイル内容を見る
---
Discription:セルフチェックリスト(Phase 4で使用)
---
# セルフチェックリスト
> **Phase 4 の開始時に、以下の全項目をチェックすること。**
---
## 精読(Phase 2)の確認
- [ ] `view_file` 等を使って実際にコードを読み込んだか(ログに残っているか)
- [ ] 対象ファイルを1つずつ開いて中身を確認したか(推測していないか)
---
## アクション記述(ルール1)の確認
- [ ] すべての■ボタンに「押下後の結果」が書かれているか
- [ ] 分岐処理(Confirm等)がある場合、「・〇〇選択時:」で列挙されているか
- [ ] 遷移先・実行処理・表示変化・エラー時の挙動が明記されているか
---
## 未実装・バグ(ルール4)の確認
- [ ] 未実装(空の関数)を `🚧` で記述しているか
- [ ] バグ(遷移先矛盾)を `⚠️` で記述しているか
- [ ] 推測で補完していないか(「あるべき姿」ではなく「現在の姿」を記録しているか)
---
## ※印対応(ルール2)の確認
- [ ] 機能内容の※と備考の※が1対1で対応しているか
- [ ] 孤立した※がないか(機能内容にない※を備考に書いていないか)
---
## 粒度(ルール3)の確認
- [ ] 1行に複数機能が混在していないか
- [ ] ダイアログ・モーダル・確認画面は別行になっているか
---
## 省略禁止(ルール6)の確認
- [ ] 機能内容や備考が簡略化(要約)されていないか
- [ ] 「詳細は省略」のような表現がないか
---
## 技術用語禁止(ルール7)の確認
- [ ] 一覧リストなどの技術用語(TableView, RecyclerView等)が機能内容に含まれていないか
---
## 曖昧語禁止(ルール8)の確認
- [ ] 「適切に」「正しく」等の曖昧語を使わず、具体的な値・ロジックを記載しているか
- [ ] バリデーション(必須、文字数、正規表現)を具体的に記載しているか
---
## 4ステート(ルール9)の確認
- [ ] Loading(読み込み中表示)の実装を確認したか
- [ ] Empty(0件時表示)の実装を確認したか
- [ ] Error(エラー時挙動)の実装を確認したか
- [ ] Success(成功時フィードバック)の実装を確認したか
---
## 入力項目・一覧列の記述形式の確認
- [ ] 入力項目が10個以上の画面で、グループ分け形式を適用しているか
- [ ] 一覧リストの表示列が10個以上の画面で、グループ分け形式を適用しているか
- [ ] リスト内の■アクションにも「押下後の挙動」を記述しているか
---
## HTML生成の確認
- [ ] **【最重要】`csv_to_html.py` を実行してHTMLプレビューを生成したか**
- [ ] 手動でHTMLを作成していないか
---
## すべてのチェックが完了したら
Phase 4完了。納品物(CSV + HTML)をユーザーに提出する。
CSV→HTML変換スクリプト
仕様書CSVをHTMLプレビューに変換するPythonスクリプトです。
Phase 4(検証)でAIがこのスクリプトを実行してHTMLプレビューを生成します。
csv_to_html.py - CSV→HTML変換スクリプト
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""CSVをHTMLに変換するスクリプト(新記号対応・完全版)"""
import csv
import html
import re
from pathlib import Path
import hashlib
def escape_html(text):
"""HTMLエスケープ"""
if not text:
return ""
return html.escape(text)
def format_content(text):
"""機能内容・備考をHTML用にフォーマット"""
if not text:
return ""
# CR/CRLFをLFに統一
text = text.replace('\r\n', '\n').replace('\r', '\n')
# 1. プレースホルダーに置換(HTMLエスケープで壊れないように)
text = re.sub(r'♦︎', '\x00DISPLAY\x00', text)
text = re.sub(r'■', '\x00ACTION\x00', text)
text = re.sub(r'⚠️', '\x00WARN\x00', text)
text = re.sub(r'🚧', '\x00TODO\x00', text)
# 2. HTMLエスケープ
lines = text.split('\n')
escaped = [escape_html(line) for line in lines]
joined = '\n'.join(escaped)
# 3. タグに戻す
joined = joined.replace('\x00DISPLAY\x00', '<span class="display">♦︎</span>')
joined = joined.replace('\x00ACTION\x00', '<span class="action">■</span>')
joined = joined.replace('\x00WARN\x00', '<span class="warning">⚠️</span>')
joined = joined.replace('\x00TODO\x00', '<span class="todo">🚧</span>')
return joined
def format_api(api_text):
"""対象APIを改行で結合"""
if not api_text:
return ""
return escape_html(api_text.replace('\n', ' ').strip())
def get_category_color_class(category_name):
"""カテゴリ名からハッシュで色クラスを決定"""
if not category_name:
return "cat-0"
hash_val = int(hashlib.md5(category_name.encode('utf-8')).hexdigest(), 16)
color_index = hash_val % 8
return f"cat-{color_index}"
def main():
import argparse
parser = argparse.ArgumentParser(description='CSVをHTMLに変換する')
parser.add_argument('csv_path', nargs='?', help='入力CSVファイルのパス')
parser.add_argument('-o', '--output', help='出力HTMLファイルのパス')
args = parser.parse_args()
base_dir = Path(__file__).parent
if args.csv_path:
csv_path = Path(args.csv_path)
else:
csv_files = list(base_dir.glob("*.csv"))
if csv_files:
csv_path = csv_files[0]
print(f"Input file not specified. Using: {csv_path.name}")
else:
print("Error: No CSV file found.")
return
if args.output:
html_path = Path(args.output)
else:
html_path = csv_path.with_suffix('.html')
if not csv_path.exists():
print(f"Error: CSV file not found: {csv_path}")
return
rows_by_cat = {}
categories_order = []
try:
with open(csv_path, 'r', encoding='utf-8-sig') as f:
reader = csv.DictReader(f)
for row in reader:
cat = row.get('機能カテゴリ', row.get('カテゴリ', '未分類')) or '未分類'
if cat not in rows_by_cat:
rows_by_cat[cat] = []
categories_order.append(cat)
rows_by_cat[cat].append(row)
except Exception as e:
print(f"Error reading CSV: {e}")
return
csv_filename = csv_path.stem # ファイル名(拡張子なし)
# CSSスタイル
css_style = """
<style>
body{font-family:"Hiragino Sans","Meiryo",sans-serif;margin:20px;background:#f5f5f5}
h1{color:#333}
.legend{margin-bottom:20px;padding:10px;background:white;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.1)}
.legend span{margin-right:15px;padding:4px 8px;border-radius:4px;display:inline-block;margin-bottom:4px}
.legend .action-badge{background:#f8d7da;color:#721c24}
.legend .display-badge{background:#d4edda;color:#155724}
.legend .warning-badge{background:#fff3cd;color:#856404;font-weight:bold}
.legend .todo-badge{background:#e2e3e5;color:#383d41;font-weight:bold}
table{width:100%;border-collapse:collapse;background:white;margin-bottom:40px;box-shadow:0 2px 8px rgba(0,0,0,0.1);table-layout:fixed}
th,td{padding:10px;border:1px solid #ddd;vertical-align:top;word-wrap:break-word;font-size:13px}
th{background:#4a90d9;color:white;text-align:left;position:sticky;top:0}
th:nth-child(1) { width: 40px; text-align: center; }
th:nth-child(2) { width: 140px; font-weight: bold; }
th:nth-child(3) { width: 40%; }
th:nth-child(4) { width: 30%; }
td.cell-content, td.cell-notes { white-space: pre-line; line-height: 1.6; }
.action{color:#d9534f;font-weight:bold}
.display{color:#5cb85c;font-weight:bold}
.warning{color:#e67e22;font-weight:bold;background-color:#fff3cd;padding:0 3px;border-radius:3px}
.todo{color:#6c757d;font-weight:bold;background-color:#e9ecef;padding:0 3px;border-radius:3px}
h2{color:#333;border-bottom:2px solid #ccc;padding-bottom:5px;margin-top:40px}
.cat-0 { border-bottom-color: #0d6efd; color: #0d6efd; }
.cat-1 { border-bottom-color: #6610f2; color: #6610f2; }
.cat-2 { border-bottom-color: #6f42c1; color: #6f42c1; }
.cat-3 { border-bottom-color: #d63384; color: #d63384; }
.cat-4 { border-bottom-color: #dc3545; color: #dc3545; }
.cat-5 { border-bottom-color: #fd7e14; color: #fd7e14; }
.cat-6 { border-bottom-color: #198754; color: #198754; }
.cat-7 { border-bottom-color: #20c997; color: #20c997; }
</style>
"""
html_parts = []
html_parts.append(f'''<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>機能一覧 - {escape_html(csv_filename)}</title>
{css_style}
</head>
<body>
<h1>📋 {escape_html(csv_filename)}</h1>
<div class="legend"><strong>凡例:</strong>
<span class="action-badge">■ アクション要素</span>
<span class="display-badge">♦︎ 表示・静的要素</span>
<span class="warning-badge">⚠️ 不整合・バグ</span>
<span class="todo-badge">🚧 未実装</span>
</div>''')
for cat in categories_order:
rows = rows_by_cat[cat]
first_row = rows[0]
no_key = '#' if '#' in first_row else 'No'
no_start = rows[0].get(no_key, '')
no_end = rows[-1].get(no_key, '')
cat_class = get_category_color_class(cat)
html_parts.append(f'<h2 class="{cat_class}">{escape_html(cat)} ({no_key}.{no_start}〜{no_end})</h2>')
html_parts.append('<table><thead><tr><th>#</th><th>画面名</th><th>機能内容</th><th>備考</th><th>API / その他</th></tr></thead><tbody>')
for r in rows:
no = r.get(no_key, '')
name = escape_html(r.get('画面名', ''))
content = format_content(r.get('機能内容', ''))
notes = format_content(r.get('備考', ''))
api = format_api(r.get('対象API', ''))
if not api:
extra = []
if r.get('Figmaリンク'): extra.append(f"Figma: {r.get('Figmaリンク')}")
api = "<br>".join(escape_html(x) for x in extra)
html_parts.append(f'<tr><td align="center">{no}</td><td>{name}</td><td class="cell-content">{content}</td><td class="cell-notes">{notes}</td><td>{api}</td></tr>')
html_parts.append('</tbody></table>')
html_parts.append('</body></html>')
with open(html_path, 'w', encoding='utf-8') as f:
f.write('\n'.join(html_parts))
print(f"Generated: {html_path}")
if __name__ == '__main__':
main()