1.初めに:SDDやってますか?
こんにちは。最近個人開発でSDD(仕様駆動開発)を使って仕様書を作ることが増えました。
ただ作ってもらうのは楽しいけどその後読むのが億劫になったりします。
また仕事でSDDを行う方は仕様書がマークダウンで読みずらいと言われることもあるかもしれません。
そこで今回は、Markdownを投げるだけで“見やすいHTML+Mermaid図”にして返すGemini Gemsを作ってみた話です。
2. 課題:Markdown読みたくない問題
個人開発で仕様書を作らせたとき、みなさん毎回ちゃんと全文読んでますか?
(自分は正直、見出しだけ見て「まぁOKでしょ」で進める日があります)
Markdownは軽くてAIもちゃんと読めて最高なんですが、読み慣れていない人からしたら嬉しくないかもしれません。
特にSDDでありがちな書き方として、EARS(Easy Approach to Requirements Syntax)のように
- When(いつ)
- If(条件)
- Then(振る舞い)
で仕様を書くケースがあります。
これは 「曖昧さを減らせる」 のでコードを書く側にはかなり強い一方で、読む側からすると
- When/If/Then が連続して目が滑る
- 分岐の全体像が頭に入りづらい
- 結局「この機能って何が起きるの?」が追いづらい
という状態になりがちです。
## 機能:会員登録フロー
### ストーリー
ユーザーは素早く登録を完了したい。
### 要求(EARS)
When ユーザーが「登録する」ボタンを押したとき
Then システムは入力値を検証する
When 入力不備がある場合
Then システムはエラーメッセージを表示する
When 入力がすべて正しい場合
Then システムは確認メールを送信する
And 完了画面へ遷移する
When 確認メールのリンクが期限切れの場合
Then システムは再送導線を表示する
なので今回は、この EARSで書かれたMarkdown仕様を “図と表” に変換して読める形にする ことを目標にしました。
3.解決:GemでHTML化
今回はGeminiのGemsを使って、Markdown仕様書を 「見やすいHTML+Mermaid図」 に変換するGemを作りました。
プロンプト全文は 5. Gemのプロンプト に載せています。
3.1 なぜGemsにしたのか?
最初はCLIツールやWebアプリとして作るのも考えたんですが、今回の目的は 「仕様書をPO向けに見やすくする」 ことです。
この目的だけ見ると、Gemsがちょうど良かったです。
- インストール不要(Gemini上で完結)
- プロンプトの改善が最速(修正してすぐ試せる)
-
出力がHTML1枚なので共有がラク(チャットでも送れる)
プロンプト考えるだけだからサボれる!
3.2 何を入力して、何が返るのか?
入力はいつも通りのMarkdownです。
特にEARS(When/If/Then)で書かれた仕様をそのまま投げます。
出力は 「見やすいHTML」 で、主に以下を自動で生成します。
- 仕様のタイトル/概要
- Mermaidで描いたフローチャート(全体像)
- EARSをテーブル化した「条件 → 振る舞い」一覧
- 注意点・例外(あれば)
つまり 読む側が欲しい “図と表” に変換してくれる という感じです。
4.デモ
今回デモで使用する仕様書はCC-SDDを用いて適当な題材で作成してもらいました
長すぎるので以下に折りたたみしてます
■■■■■■■■■■■■■■■■■■■■■■■
デモ用requirements.mdを表示(折りたたみ)
■■■■■■■■■■■■■■■■■■■■■■■■
# 要件定義書
## イントロダクション
本機能は、ユーザーが画像または動画ファイルをアップロードし、AI解析を非同期で実行して結果を表示するシステムです。ユーザーは解析の進行状況をリアルタイムで確認でき、解析完了後は結果画面へ自動遷移します。解析が失敗した場合は再実行が可能です。
### ビジネス価値
- ユーザーはメディアファイルのAI解析を簡単に実行できる
- 非同期処理により、ユーザーは解析完了を待たずに他の操作が可能
- 同時実行制限により、システムリソースを適切に管理
- エラーハンドリングにより、失敗時の再試行が容易
## 要件
### 要件1: メディアファイルアップロード
**ユーザーストーリー:** ユーザーとして、画像または動画ファイルをアップロードしてAI解析を実行したい
#### 受入基準
1. WHEN ユーザーがファイル選択ダイアログを開く THEN システムは画像形式(JPEG、PNG、GIF、WebP)および動画形式(MP4、MOV、AVI、WebM)のファイル選択を許可する
2. WHEN ユーザーがサポートされていないファイル形式を選択 THEN システムは「サポートされていないファイル形式です」というエラーメッセージを表示する
3. WHEN ユーザーがファイルサイズが100MBを超えるファイルを選択 THEN システムは「ファイルサイズが上限を超えています(最大100MB)」というエラーメッセージを表示する
4. WHEN ユーザーが有効なファイルをアップロード THEN システムはファイルをサーバーへ転送し、アップロード進行状況を表示する
5. WHEN ファイルアップロードが完了 THEN システムは解析ジョブを作成し、解析処理を開始する
6. IF アップロード中にネットワークエラーが発生 THEN システムは「アップロードに失敗しました。もう一度お試しください」というエラーメッセージを表示し、再試行オプションを提供する
### 要件2: 同時実行制御
**ユーザーストーリー:** システムとして、1ユーザーにつき1件の解析ジョブのみを許可し、システムリソースを適切に管理したい
#### 受入基準
1. WHEN ユーザーが新規ファイルをアップロード試行 AND 同一ユーザーの解析ジョブが既に実行中 THEN システムは「既に解析処理が実行中です。完了後に再度お試しください」というエラーメッセージを表示する
2. WHEN ユーザーが新規ファイルをアップロード試行 AND 同一ユーザーの解析ジョブが実行中ではない THEN システムは新規アップロードを許可する
3. WHEN 解析ジョブが完了または失敗 THEN システムは同一ユーザーの実行中ジョブカウントを0にリセットし、新規アップロードを許可する
4. IF ユーザーが実行中のジョブをキャンセル THEN システムはジョブを停止し、新規アップロードを許可する
### 要件3: 非同期AI解析処理
**ユーザーストーリー:** システムとして、アップロードされたメディアファイルをバックグラウンドで解析し、ユーザーに進行状況を通知したい
#### 受入基準
1. WHEN 解析ジョブが作成 THEN システムはバックグラウンドで解析処理を開始し、ジョブステータスを「解析中」に設定する
2. WHILE 解析処理が実行中 システムはジョブステータスを定期的(5秒ごと)に更新し、UIへ反映する
3. WHEN 解析処理が60秒以内に完了 THEN システムは解析結果を保存し、ジョブステータスを「完了」に設定する
4. IF 解析処理が60秒以内に完了しない THEN システムは処理を中断し、ジョブステータスを「タイムアウト」に設定し、エラーメッセージ「解析がタイムアウトしました。もう一度お試しください」を記録する
5. WHEN 解析処理中にシステムエラーが発生 THEN システムは処理を中断し、ジョブステータスを「失敗」に設定し、エラー詳細を記録する
6. WHEN 解析処理が完了 THEN システムは解析結果データ(解析内容、信頼度スコア、検出項目など)をデータベースに保存する
### 要件4: 解析状態の可視化
**ユーザーストーリー:** ユーザーとして、解析の進行状況をリアルタイムで確認し、完了時に通知を受け取りたい
#### 受入基準
1. WHEN ファイルアップロードが完了 THEN システムは「解析中」というステータスメッセージを表示する
2. WHILE 解析処理が実行中 システムはローディングアニメーション(スピナー)を表示し、ユーザーに処理中であることを視覚的に伝える
3. WHEN 解析ジョブのステータスが更新 THEN システムはUIを自動的に更新し、最新のステータスを表示する
4. WHEN 解析が完了 THEN システムは「解析が完了しました」という成功メッセージを表示する
5. WHEN 解析が失敗またはタイムアウト THEN システムは適切なエラーメッセージを表示する
6. IF ユーザーが解析中に他のページへ移動 THEN システムはバックグラウンドで解析を継続し、完了時にブラウザ通知またはページ内通知を表示する
### 要件5: 結果表示
**ユーザーストーリー:** ユーザーとして、解析が完了したら結果を確認したい
#### 受入基準
1. WHEN 解析が成功 THEN システムは自動的に結果画面へ遷移する
2. WHEN 結果画面が表示 THEN システムは以下の情報を表示する:
- アップロードされたメディアファイルのプレビュー(画像/動画サムネイル)
- AI解析結果の詳細(検出内容、カテゴリ分類、信頼度スコアなど)
- 解析完了日時
- 再解析オプション(新しいファイルをアップロードするボタン)
3. WHEN ユーザーが結果画面で「新しいファイルをアップロード」ボタンをクリック THEN システムはアップロード画面へ遷移する
4. IF 解析結果データに複数の検出項目が含まれる THEN システムは項目ごとに整理されたリスト形式で表示する
### 要件6: エラーハンドリングと再試行
**ユーザーストーリー:** ユーザーとして、解析が失敗した場合に簡単に再実行したい
#### 受入基準
1. WHEN 解析が失敗 THEN システムは失敗理由を明確に説明したエラーメッセージを表示する(例:「タイムアウトしました」「サーバーエラーが発生しました」「不正なファイル形式です」)
2. WHEN エラーメッセージが表示 THEN システムは「再実行」ボタンを提供する
3. WHEN ユーザーが「再実行」ボタンをクリック THEN システムは同じファイルで新しい解析ジョブを作成し、解析処理を再開始する
4. IF タイムアウトエラーが発生 THEN システムは「処理に時間がかかっています。ファイルサイズを小さくするか、別のファイルをお試しください」という追加のヒントメッセージを表示する
5. WHEN ユーザーが再実行を3回試行しても失敗 THEN システムは「問題が解決しない場合はサポートにお問い合わせください」というメッセージを表示する
6. IF ネットワークエラーが発生 THEN システムは自動的に1回再試行し、それでも失敗した場合はユーザーへエラーを通知する
## 非機能要件
### 要件7: パフォーマンスとタイムアウト
**ユーザーストーリー:** システムとして、適切なレスポンス時間とタイムアウト制御により、ユーザーエクスペリエンスを最適化したい
#### 受入基準
1. システムは解析処理を最大60秒でタイムアウトする
2. システムはファイルアップロード完了から解析ジョブ作成まで3秒以内に処理する
3. システムはジョブステータスの更新を5秒ごとに実行する
4. IF ファイルサイズが10MB未満 THEN システムは平均30秒以内に解析を完了する(ベストエフォート)
5. システムは同時に最大100ユーザーの解析ジョブを処理できる(スケーラビリティ要件)
### 要件8: ユーザーエクスペリエンス
**ユーザーストーリー:** ユーザーとして、直感的で使いやすいインターフェースを通じてスムーズに操作したい
#### 受入基準
1. システムはドラッグ&ドロップでファイルをアップロードできる機能を提供する
2. システムはアップロード進行状況をパーセンテージ(%)で表示する
3. システムは全てのエラーメッセージを明確で理解しやすい日本語で表示する
4. システムはローディング中に「解析中です。しばらくお待ちください」などの適切なメッセージを表示する
5. IF ユーザーがモバイルデバイスからアクセス THEN システムはレスポンシブデザインで最適化されたUIを表示する
6. システムは操作に対するフィードバック(ボタンクリック、ホバー効果など)を提供し、インタラクティブな体験を実現する
### 要件9: セキュリティとデータ保護
**ユーザーストーリー:** システムとして、悪意のあるファイルや不正なアクセスからシステムとユーザーデータを保護したい
#### 受入基準
1. システムはアップロードされたファイルの拡張子とMIMEタイプを両方検証する
2. システムはファイルサイズを100MBに制限し、これを超えるファイルを拒否する
3. システムは各ユーザーの解析ジョブとデータを分離し、他のユーザーがアクセスできないようにする
4. IF ユーザーが認証されていない THEN システムはアップロード機能へのアクセスを拒否する
5. システムはアップロードされたファイルに対してウイルススキャンを実行する(オプション:セキュリティレベルに応じて)
6. システムは解析結果データを暗号化して保存する
7. WHEN ユーザーがアカウント削除を要求 THEN システムはユーザーのアップロードファイルと解析結果を完全に削除する
---
**生成日時**: 2026-01-25
**ステータス**: 要件生成完了 - レビュー待ち
**次のステップ**: 要件をレビューし、承認後に `/spec-design media-ai-analysis` を実行して技術設計を生成
その内容をコピペして作成したGemに送ってあげると図1のように約1分ほどで出力してくれます
図1で出してくれたHTMLをお手元のテキストエディタにコピペして開くと図2のような形で図付きの資料として見ることができます
5.Gemのプロンプト
5.1プロンプト(コピペ可)
あなたは「SDD仕様書ビジュアライザー」です。
ユーザーの要件定義テキストを、PO(プロダクトオーナー)が読みやすい「リッチなHTML仕様書」に変換します。
### ⚠️ 最重要:Mermaid図の生成ルール(Safe Mode)
Syntax Error回避のため、以下のID命名規則を**厳守**してください。
1. **Node ID / Subgraph IDは必ず連番にする**:
- ❌ `User`, `Process_A`
- ✅ `n1`, `n2`..., `sg1`, `sg2`...
2. **ラベルは必ずダブルクォーテーションで囲む**:
- ✅ `n1["開始"]`
### 📝 EARSの翻訳・整形ルール
入力されたEARS(When/If/Then)をそのまま表示せず、**「ビジネス仕様の対応表」**に変換してください。
- **When / If** → 「🎬 シチュエーション / 条件」列にまとめる。
- **Then** → 「👉 システムの振る舞い」列にまとめる。
- 専門用語っぽい `When...` `Then...` という書き方はせず、自然な日本語にする。
### HTML出力テンプレート
```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>仕様書</title>
<style>
/* デザイン定義 */
:root { --primary: #2563eb; --bg: #f8fafc; --card: #ffffff; --text: #334155; --border: #e2e8f0; }
body { font-family: 'Helvetica Neue', Arial, sans-serif; background: var(--bg); color: var(--text); padding: 40px; margin: 0; line-height: 1.6; }
.container { max-width: 960px; margin: 0 auto; }
/* カード */
.card { background: var(--card); border-radius: 12px; padding: 24px; margin-bottom: 24px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); border: 1px solid var(--border); }
h1 { text-align: center; color: #0f172a; margin-bottom: 30px; font-weight: 800; }
h2 { font-size: 1.25rem; border-left: 5px solid var(--primary); padding-left: 12px; margin-bottom: 20px; color: #1e293b; background: #f1f5f9; padding-top: 5px; padding-bottom: 5px; }
/* ユーザーストーリー */
.story-box { background: #f8fafc; border: 1px solid #cbd5e1; border-radius: 8px; padding: 15px; margin-bottom: 20px; font-style: italic; color: #475569; }
.story-label { font-weight: bold; color: #334155; font-style: normal; display: block; margin-bottom: 5px; font-size: 0.9em; }
/* 仕様テーブル (ここがポイント) */
.spec-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 0.95rem; }
.spec-table th { background: #eff6ff; color: #1e40af; padding: 10px; text-align: left; border-bottom: 2px solid #bfdbfe; font-weight: bold; width: 40%; }
.spec-table td { padding: 12px 10px; border-bottom: 1px solid #e2e8f0; vertical-align: top; }
.spec-table tr:last-child td { border-bottom: none; }
/* タグ装飾 */
.tag { display: inline-block; padding: 2px 6px; border-radius: 4px; font-size: 0.75em; font-weight: bold; margin-right: 5px; vertical-align: middle; }
.tag-if { background: #fff7ed; color: #c2410c; border: 1px solid #ffedd5; } /* 条件 */
.tag-err { background: #fef2f2; color: #b91c1c; border: 1px solid #fee2e2; } /* エラー */
/* Mermaid */
.mermaid { display: flex; justify-content: center; margin: 20px 0; padding: 10px; background: #fff; border-radius: 8px; border: 1px solid #e2e8f0; }
</style>
</head>
<body>
<div class="container">
<h1>仕様書</h1>
<div class="card">
<h2>全体フロー図</h2>
<div class="mermaid">
flowchart TD
%% IDは n1, n2... sg1... を使用 (Syntax Error回避)
n1(("開始")) --> n2["処理"]
</div>
</div>
<div class="card">
<h2>機能名: [タイトル]</h2>
<div class="story-box">
<span class="story-label">User Story / 背景</span>
ここにユーザーストーリーを記述
</div>
<table class="spec-table">
<thead>
<tr>
<th>🎬 シチュエーション / 条件</th>
<th>👉 システムの振る舞い</th>
</tr>
</thead>
<tbody>
<tr>
<td>
ユーザーがボタンを押した時<br>
<span class="tag tag-if">条件</span> 在庫がある場合
</td>
<td>
登録完了メールを送信する
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="module">
import mermaid from '[https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs](https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs)';
mermaid.initialize({ startOnLoad: true, theme: 'neutral' });
</script>
</body>
</html>
5.2 工夫点(壊れない&読めるようにする)
ただ「Markdown→HTMLにする」だけだと、AI出力がブレたり、Mermaidが壊れたりして実運用は厳しめです。(実際プロンプトを最初作った際にはSyntaxError祭りでした)
なので今回は非エンジニアが読める形と毎回ちゃんと動くという2点を優先して、プロンプト側でいくつか制約を入れています。
5.2.1 Safe Mode:Mermaidが壊れないルールを先に敷く
Mermaidは便利ですが、AIに自由に書かせると構文エラーで死にがちです。
そこで ID命名を連番固定(n1,n2,n3…) にして、壊れにくい形に寄せています。
- ノードIDは
n1, n2, n3...のみ - 日本語ID、記号、スペース、重複IDは禁止
- 図の種類は
flowchart TDに固定(変な書き方をさせない) - 複雑な装飾(subgraph乱用など)は避けて単純にする
「図を生成できる」より “壊さず生成できる” を優先しました。
5.2.2 EARS(When/If/Then)を“読む形”に変換する
EARSは仕様の曖昧さを減らせる一方で、文章のままだと読む側の負荷が高いです。
なので When/If/Then を 「条件 → 振る舞い」 の対応表に変換するようにしています。
- When:シチュエーション
- If:条件
- Then:システムの振る舞い
- And:補足(あれば)
POが欲しいのは精読ではなく 判断できる要点 なので、表の方がレビューしやすくなります。
5.2.3 仕様の全体像を先に見せる(図→表の順)
文章を追わせるのはつらいので、HTMLの構造は固定で
- タイトル/概要
- Mermaid図(全体像)
- 条件→振る舞いテーブル
- 注意点・例外
の順にしています。
まず流れを掴んでから詳細に入れる形です。
5.2.4 1枚HTMLで完結させる
出力は HTMLファイル1枚 にしています。
- 外部ツール不要(ブラウザで開くだけ)
- チャットで共有できる
できるだけ楽に軽く共有しやすくを意識しました。
5.2.5 出力テンプレを固定して品質を安定させる
AIに自由に書かせると、毎回見た目や構造が微妙に変わります。
なので HTMLテンプレ(見出し・セクション・表)を固定して、結果がブレにくいようにしています。
6.最後に
今回はSDD開発をよりやりやすくする為のアプローチとして一番手っ取り早く行うためGemを使いました。
次はCC-SDDに組み込んで最初からこのような形で出せるようなアプローチを取れるかやってみたいと思います。
また重々承知のことではあると思いますが生成AIの出力なので本文の仕様書を見ずに全て信じるのは危険ですので必ず読むことをお勧めします。


