17
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レビューしやすい設計書を作ってくれるエージェント決定戦! cc-sddで設計書作って比べてみた

Posted at

読みやすい設計書作ってくれるAI、いったいどれなんだい!!

どうも。最近仕様駆動開発を触っている者です。

仕様駆動開発、個人的にすごく好きなのですが、設計書レビューはやはり負荷がかかります。
というわけで、仕様駆動開発ライブラリのcc-sddを使って、各コーディングエージェント(Claude Code, Codex CLI, Gemini CLI)に同じ機能の設計書を作ってもらい、その特徴を比較してみました。

忙しい人向け結果と考察まとめ

単純なモデルの性質とcc-sddで設定されているプロンプトだけではなく、今回の検証特有の何かが効いてる可能性を考慮して見てください。

Claude Code

生成される文字数: 中
設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 14,371文字
    • 一文あたりの目安: 80~100文字程度
  • 文章の構造:
    • cc-sddテンプレートに忠実。見出しは適切だが番号なし
    • 英単語と日本語が混ざった文章を生成する
    • 決められている型に忠実な文章を生成するので、慣れれば解釈しやすい文章
  • 理解しやすくする要素:
    • シーケンス図あり、箇条書き適切、既存アーキテクチャ分析が豊富
    • mermaid等の図も適切に使用
    • 既存の実装との兼ね合いや実装戦略も考慮した設計をしてくれる

その他: 設計書作成が非常にスムーズで途中で失敗等はなかった


Gemini CLI

生成される文字数: 少〜中
設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 13,340文字
    • 一文あたりの目安: 40~60文字程度
  • 文章の構造:
    • 英文と日本語が混ざった文章を生成するので、好みが分かれる(オフショアなら良い?)
    • 形式化されていない文章を生成することもある
  • 理解しやすくする要素:
    • mermaid等の図は適切に使用してくれる
    • design.mdは少しシンプルすぎるものができた

その他: なし


Codex CLI

生成される文字数: 中〜多
設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 15,723文字
    • 一文あたりの目安: 50~70文字程度
  • 文章の構造:
    • 自然な日本語で、読みやすいドキュメントを作ろうとする
    • 文章は自然で読みやすいが、文の型は決まっていない
  • 理解しやすくする要素:
    • mermaid等の図は適切に作ってくれるが、シーケンス図は初手で作ってくれなかった

その他:

  • 設計は具体的な実装について深く記載してあり、実装時の手戻りは少なそう
  • 設計書作成時や触っているときに意図せぬ動作が少しあった

上記ではわかりづらいかもなので、ぜひ実際の設計書をちょこっと眺めて見てください。

やったこと

cc-sddとコーディングエージェントを使い、あるアプリの新機能の設計を実施します。
成果物を比較することで個人的に読みやすい設計書を作ってくれるエージェントを見つけようと思います。

比較観点としては、

  • 生成される文字数
  • 設計書としての読みやすさ
    • 文章の長さ
    • 文章の構造
    • 設計を理解しやすくする要素(図や箇条書き等)

を比較します。

また、生成された設計書の全文も載せておくので興味があれば見てみてください。

一方で、設計書の正しさや精度は真面目に比較しません。最後の感想に参考情報として書きます。

cc-sdd is 何?

cc-sddは、AIコーディングエージェントで仕様駆動開発を行うOSSのライブラリです。

下記の流れで、段階的に設計書を生成します。

主なコマンド:

コマンド 説明
spec-init 機能名で新しい仕様を初期化
spec-requirements EARS記法で要件ドキュメントを生成
validate-gap 要件と既存コードベース間の実装ギャップを分析
spec-design 技術設計ドキュメントを生成
validate-design 技術設計品質をレビュー・検証
spec-tasks 実装タスクを生成

上記の流れでコマンドを実行していくと、主に下記のファイルが生成されます。

ファイル 説明
requirements.md EARS記法の要件定義書。機能要件と受け入れ基準を記載
design.md 技術設計書。アーキテクチャ、API仕様、データモデル等を記載
tasks.md 実装タスク一覧。要件とのトレーサビリティを含む

実験でやったこと

使用したツール

  • cc-sdd
  • コーディングエージェントと使用モデル
    • Claude Code: Opus 4.5
    • Codex CLI: Codex max (effort: medium)
    • Gemini CLI: Gemini 2.5 Pro

対象機能

個人開発の「思い出アルバムアプリ」に「最新の思い出」機能を追加する設計を行いました。

思い出アルバムアプリ

Googleドライブに保存した、世界一カワイイ我が息子との思い出写真や動画を良い感じに見れるアプリです。

omoide-album.png

機能の中でも、「この写真、きっとこんなことしゃべってる」機能がお気に入りで、写真を勝手に喋らせてくれます。
写真の中の思わぬ登場人物(🐘)も喋ったりするのでそれもまた楽しいです。

新機能「最新の思い出」

今回設計してもらう思い出アルバムの新機能は、最新の写真や動画をピックアップし、表示してくれる機能になります。
なお、以降の設計書等に子供の名前が思いっきり載ってたので、「ひまお」(仮名)に変更しておきました。

ざっくり、

  • トップページに「最新の思い出」タブを追加
  • 「今日のひまお」フォルダから最新メディアを表示
  • ランダムに1件を「最新のおすすめ写真」として表示
  • 新着時は「New」バッジで通知

というものです。

下記のようなissueを作成し、それを各エージェントに渡します。

GitHub Issue(クリックで展開)
## 機能リクエスト
最新の写真・動画に素早くアクセスできるページを追加する。

### 解決したい課題

- ユーザーは最新の写真や画像に速やかにアクセスしたい
- 最新の画像がある場合に更新があったことを知りたい

### 提案する解決策

トップページに新しいタブ「最新の思い出」を追加し、以下の機能を実装する。

**表示対象:**
- 「ひまおアルバム>今日のひまお」配下にある画像と動画を表示
- 「今日のひまお」フォルダが空の場合は、最新日付の画像・動画を表示

**UI/UX:**
- 既存の「今日のおすすめ」とほぼ同じUIを使用
- 対象画像からランダムでピックアップし「最新のおすすめ写真」としてページトップに表示
- その写真と同日にアップロードされた写真・動画をその下に並べる
- 最新画像がある場合、タブに「New」バッジを表示して更新を通知

**アクセス方法:**
- ログイン後、該当タブをクリックしてアクセス

### 受け入れ基準

- [ ] トップページに「最新の思い出」タブが追加されること
- [ ] 「今日のひまお」フォルダ配下の画像・動画を取得するバックエンドAPIが作成されること
- [ ] フォルダが空の場合は、最新日付の画像・動画にフォールバックすること
- [ ] 「最新のおすすめ写真」がページトップにランダム表示されること
- [ ] 同日アップロードの写真・動画がその下に一覧表示されること
- [ ] 最新画像がある場合、タブに「New」バッジが表示されること
- [ ] ログイン必須であること

### 優先度

中(近いうちに欲しい)

### 影響範囲

- [x] フロントエンド
- [x] バックエンド
- [ ] インフラストラクチャ
- [ ] ドキュメント
- [x] テスト
- [ ] その他

### 技術的な考慮事項(任意)

- 「今日のひまお」フォルダIDをバックエンド設定で管理
- 既存の「今日のおすすめ」コンポーネントを再利用・拡張
- 「New」バッジの判定ロジック(例:24時間以内のアップロード、または前回アクセス以降の更新)

**実装フェーズ:**
1. Phase 1: バックエンドAPI(今日のひまおフォルダからのメディア取得)
2. Phase 2: フロントエンドタブ追加とページ作成
3. Phase 3: 「New」バッジ機能の実装
4. Phase 4: E2Eテスト

### 追加情報(任意)

既存の「今日のおすすめの一枚」機能との差別化:
- 「今日のおすすめ」: 過去の同日の思い出をランダム表示
- 「最新の思い出」: 直近アップロードされた最新コンテンツを表示

実験手順

  1. 共通のGitHub Issueに対して、それぞれのコーディングエージェントでcc-sddを実行する
  2. 各コーディングエージェントの設定はデフォルト
  3. 下記コマンドをレビュー修正なしで連続実行
    • spec-init
    • spec-requirements
    • validate-gap
    • spec-design -y
    • validate-design
    • spec-tasks -y

比較するファイル

下記のファイルをそれぞれ比較してみます。

ファイル 説明
requirements.md EARS記法の要件定義書。機能要件と受け入れ基準を記載
design.md 技術設計書。アーキテクチャ、API仕様、データモデル等を記載

実際の設計書の比較

生成される文字数比較

ファイル Claude Code Gemini CLI Codex CLI
requirements.md 4,892文字 6,606文字 5,645文字
design.md 9,479文字 6,734文字 10,078文字
合計 14,371文字 13,340文字 15,723文字

文字数だけ見るとCodex CLIが最も多いです。
また、Gemini CLIのdesign.mdが少ないのも特徴的ですね。

では、中身にどんな感じに書かれているか見てみましょう。

各ドキュメントの詳細比較

requirements.md(要件定義書)

冒頭の比較

Claude Code:

## Introduction
本ドキュメントは「最新の思い出ページ」機能の要件を定義する。この機能により、ユーザーは
最新の写真・動画に素早くアクセスでき、更新があった場合に通知を受け取ることができる。

## Project Description (Input)
(以下、Issueの全文が続く)

Gemini CLI:

## Project Description (Input)
最新の思い出ページ機能を実装する。【概要】最新の写真・動画に素早くアクセスできるページを
追加する。【解決したい課題】ユーザーは最新の写真や画像に速やかにアクセスしたい。最新の画像が
ある場合に更新があったことを知りたい。【提案する解決策】トップページに新しいタブ「最新の
思い出」を追加し、以下の機能を実装する。表示対象:「ひまおアルバム>今日のひまお」配下にある...
(以下、Issueの全文が続く)

Codex CLI:

## はじめに
本ドキュメントは、トップページに「最新の思い出」タブを追加し、最新にアップロードされた
写真・動画へ素早くアクセスできるページを提供するための要件を定義する。主に「ひまおアルバム
>今日のひまお」フォルダ配下のメディアを対象とし、フォルダが空の場合でも最新日付のメディア
にフォールバックして閲覧性を確保する。

Gemini CLIには、導入文がないですね。
Codex CLIは機能の概要に加え、対象フォルダやフォールバックの仕様まで簡潔に記載しています。Claude Codeは簡潔な機能概要のみですが、Issue全文も記載しているのが特徴的ですね。

要件の書き方の比較(最初の要件)

Claude Code:

### Requirement 1: バックエンドAPI - 最新メディア取得
**Objective:** As a フロントエンド開発者, I want 「今日のひまお」フォルダのメディアを
取得するAPI, so that 最新の写真・動画をユーザーに表示できる

#### Acceptance Criteria
1. When 認証済みユーザーが最新メディアAPIを呼び出す, the Backend API shall
   「今日のひまお」フォルダ配下の画像と動画を返却する
2. If 「今日のひまお」フォルダが空である, then the Backend API shall
   最新日付の画像・動画にフォールバックして返却する

Gemini CLI:

### Requirement 1: 最新の思い出タブとアクセス
#### Acceptance Criteria
1. The system shall display a "Latest Memories" (最新の思い出) tab on the top page.
   (トップページに「最新の思い出」タブを表示すること。)
2. When the user clicks the "Latest Memories" tab, the system shall retrieve
   media files from the configured "Today's Touma" (今日のひまお) folder.
   (ユーザーが「最新の思い出」タブをクリックした際、設定された「今日のひまお」フォルダから
   メディアファイルを取得すること。)

Codex CLI:

### 要件 1: 最新の思い出タブとアクセス制御
**目的:** ログインユーザーとして、トップページから最新メディア専用ページへ安全に遷移できるようにしたい

#### 受け入れ基準
1. WHEN ログイン済みユーザーがトップページを開く
   THEN 思い出アルバムは既存タブ群と同じUIで「最新の思い出」タブを表示する
2. WHEN ユーザーが「最新の思い出」タブを選択した場合
   THEN 思い出アルバムは最新の思い出ページに遷移し直近メディアを読み込む
3. IF ユーザーが未ログインで最新の思い出ページへアクセスした場合
   THEN 思い出アルバムはログインを要求し、認証後に同ページへ遷移する
4. WHERE ナビゲーションがモバイル/デスクトップ表示に切り替わる場合
   THEN 思い出アルバムはタブ表示をレイアウトに合わせて崩れずに維持する

Claude Code, Codex CLIはともにEARS記法で記載されています。
一方Gemini CLIは他の2つと異なる記法で書かれています。また、英語と日本語が併記されていますね。

全体の特徴

観点 Claude Code Gemini CLI Codex CLI
言語 日本語 英語/日本語 日本語
形式 EARS記法 ? EARS記法
冒頭 簡潔な機能概要 Issue文章が丸ごと含まれる 簡潔な機能概要
文字数 4,892文字 6,606文字 5,645文字

design.mdはボリュームが大きくシンプルにピックアップできるところがなかったので、ぜひ全文を御覧ください。

個人的な感想ですが、

  • Claude Codeは、既存のアーキテクチャを分析してくれてたり、セキュリティの考慮やテスト戦略等、堅実かつ戦略的な仕様書を記載
  • Gemini CLIは全体的にシンプル
  • Codex CLIは具体的な実装に関する記載が多い

ような感想です。

cc-sddは人間のレビューと修正が前提なので、不足している情報があれば追記していくものですが、
AIの思考のクセが垣間見えて非常に興味深かったです。

参考: requirements.md 全文

requirements.md 全文(クリックで展開)

Claude Code:

# Requirements Document

## Introduction
本ドキュメントは「最新の思い出ページ」機能の要件を定義する。この機能により、ユーザーは最新の写真・動画に素早くアクセスでき、更新があった場合に通知を受け取ることができる。

## Requirements

### Requirement 1: バックエンドAPI - 最新メディア取得
**Objective:** As a フロントエンド開発者, I want 「今日のひまお」フォルダのメディアを取得するAPI, so that 最新の写真・動画をユーザーに表示できる

#### Acceptance Criteria
1. When 認証済みユーザーが最新メディアAPIを呼び出す, the Backend API shall 「今日のひまお」フォルダ配下の画像と動画を返却する
2. If 「今日のひまお」フォルダが空である, then the Backend API shall 最新日付の画像・動画にフォールバックして返却する
3. The Backend API shall 「今日のひまお」フォルダIDを環境設定から取得する
4. When APIが呼び出される, the Backend API shall メディアのアップロード日時情報を含めて返却する
5. If 認証されていないユーザーがAPIを呼び出す, then the Backend API shall 401 Unauthorizedエラーを返却する

### Requirement 2: フロントエンド - タブナビゲーション
**Objective:** As a ユーザー, I want トップページに「最新の思い出」タブがある, so that 最新の写真・動画に素早くアクセスできる

#### Acceptance Criteria
1. When ユーザーがトップページにアクセスする, the Frontend shall 「最新の思い出」タブを表示する
2. When ユーザーが「最新の思い出」タブをクリックする, the Frontend shall 最新の思い出ページに遷移する
3. While ユーザーが認証されていない, the Frontend shall 「最新の思い出」タブを非表示にする

### Requirement 3: フロントエンド - 最新のおすすめ写真表示
**Objective:** As a ユーザー, I want ページトップにランダムで選ばれた写真が表示される, so that 最新の思い出を印象的に閲覧できる

#### Acceptance Criteria
1. When ユーザーが最新の思い出ページにアクセスする, the Frontend shall 対象画像からランダムに選択した写真を「最新のおすすめ写真」としてページトップに表示する
2. The Frontend shall 既存の「今日のおすすめ」コンポーネントと同様のUIレイアウトを使用する
3. When おすすめ写真が表示される, the Frontend shall その写真のメタデータ(撮影日など)を併せて表示する

### Requirement 4: フロントエンド - 同日アップロードメディア一覧
**Objective:** As a ユーザー, I want おすすめ写真と同日にアップロードされた写真・動画を見たい, so that その日の思い出をまとめて閲覧できる

#### Acceptance Criteria
1. When おすすめ写真が表示される, the Frontend shall その写真と同日にアップロードされた写真・動画をおすすめ写真の下に一覧表示する
2. The Frontend shall 画像と動画の両方を一覧に含める
3. When ユーザーが一覧のメディアをクリックする, the Frontend shall そのメディアの詳細表示に遷移する

### Requirement 5: 「New」バッジ通知機能
**Objective:** As a ユーザー, I want 新しい画像がある場合に通知を受けたい, so that 更新があったことを素早く知ることができる

#### Acceptance Criteria
1. When 24時間以内にアップロードされた画像が存在する, the Frontend shall 「最新の思い出」タブに「New」バッジを表示する
2. When ユーザーが最新の思い出ページにアクセスする, the Frontend shall 「New」バッジを非表示にする
3. If 新しい画像が存在しない, then the Frontend shall 「New」バッジを表示しない
4. The Backend API shall 最新画像の有無を判定するための情報を提供する

### Requirement 6: 認証・アクセス制御
**Objective:** As a システム管理者, I want 認証済みユーザーのみがアクセスできる, so that プライベートな写真・動画を保護できる

#### Acceptance Criteria
1. While ユーザーが認証されていない, the Frontend shall 最新の思い出ページへのアクセスをブロックしログインページにリダイレクトする
2. When 認証トークンが期限切れの場合, the Backend API shall 401エラーを返却し再認証を要求する
3. The System shall ログイン後のみ最新の思い出ページへのアクセスを許可する

Gemini CLI:

# Requirements Document (要件定義書)

## Project Description (Input)
最新の思い出ページ機能を実装する。【概要】最新の写真・動画に素早くアクセスできるページを追加する。【解決したい課題】ユーザーは最新の写真や画像に速やかにアクセスしたい。最新の画像がある場合に更新があったことを知りたい。【提案する解決策】トップページに新しいタブ「最新の思い出」を追加し、以下の機能を実装する。表示対象:「ひまおアルバム>今日のひまお」配下にある画像と動画を表示。「今日のひまお」フォルダが空の場合は、最新日付の画像・動画を表示。UI/UX:既存の「今日のおすすめ」とほぼ同じUIを使用。対象画像からランダムでピックアップし「最新のおすすめ写真」としてページトップに表示。その写真と同日にアップロードされた写真・動画をその下に並べる。最新画像がある場合、タブに「New」バッジを表示して更新を通知。アクセス方法:ログイン後、該当タブをクリックしてアクセス。【受け入れ基準】トップページに「最新の思い出」タブが追加されること。「今日のひまお」フォルダ配下の画像・動画を取得するバックエンドAPIが作成されること。フォルダが空の場合は、最新日付の画像・動画にフォールバックすること。「最新のおすすめ写真」がページトップにランダム表示されること。同日アップロードの写真・動画がその下に一覧表示されること。最新画像がある場合、タブに「New」バッジが表示されること。ログイン必須であること。【技術的な考慮事項】「今日のひまお」フォルダIDをバックエンド設定で管理。既存の「今日のおすすめ」コンポーネントを再利用・拡張。「New」バッジの判定ロジック(例:24時間以内のアップロード、または前回アクセス以降の更新)。【実装フェーズ】Phase 1: バックエンドAPI。Phase 2: フロントエンドタブ追加とページ作成。Phase 3: 「New」バッジ機能の実装。Phase 4: E2Eテスト。【影響範囲】フロントエンド、バックエンド、テスト。GitHub Issue: #45

## Requirements

### Requirement 1: 最新の思い出タブとアクセス
**目的:** ログインユーザーとして、最新の写真や動画に素早くアクセスし、最近の更新を確認したい。

#### Acceptance Criteria
1. The system shall display a "Latest Memories" (最新の思い出) tab on the top page.
   (トップページに「最新の思い出」タブを表示すること。)
2. When the user clicks the "Latest Memories" tab, the system shall retrieve media files from the configured "Today's Touma" (今日のひまお) folder.
   (ユーザーが「最新の思い出」タブをクリックした際、設定された「今日のひまお」フォルダからメディアファイルを取得すること。)
3. If the "Today's Touma" folder is empty, then the system shall retrieve media files from the most recent date available.
   (「今日のひまお」フォルダが空の場合、利用可能な最新の日付からメディアファイルを取得すること。)
4. While the user is not logged in, the system shall restrict access to the "Latest Memories" content.
   (ユーザーがログインしていない間は、「最新の思い出」コンテンツへのアクセスを制限すること。)

### Requirement 2: 最新のおすすめ写真
**目的:** ユーザーとして、最新のコレクションからハイライトされた写真を見て、その日のランダムな一枚を楽しみたい。

#### Acceptance Criteria
1. When the "Latest Memories" page is loaded, the system shall randomly select one photo from the retrieved media as the "Latest Recommended Photo".
   (「最新の思い出」ページが読み込まれた際、取得したメディアの中からランダムに1枚を選び、「最新のおすすめ写真」とすること。)
2. The system shall display the "Latest Recommended Photo" at the top of the page.
   (「最新のおすすめ写真」をページ上部に表示すること。)

### Requirement 3: メディアリスト表示
**目的:** ユーザーとして、おすすめ写真と同じ日の全ての写真・動画を見て、最新の更新の全体像を確認したい。

#### Acceptance Criteria
1. When displaying the page, the system shall list all photos and videos uploaded on the same day as the "Latest Recommended Photo" below it.
   (ページを表示する際、「最新のおすすめ写真」と同じ日にアップロードされた全ての写真・動画をその下に一覧表示すること。)
2. The system shall reuse the existing "Today's Recommendation" (今日のおすすめ) UI component for the display.
   (表示には既存の「今日のおすすめ」UIコンポーネントを再利用すること。)

### Requirement 4: 新着更新通知
**目的:** ユーザーとして、タブを開かなくても新しい写真があるかどうかを知り、更新を見逃さないようにしたい。

#### Acceptance Criteria
1. Where new images are available (e.g., uploaded within 24 hours or unread), the system shall display a "New" badge on the "Latest Memories" tab.
   (新しい画像が利用可能な場合(例:24時間以内にアップロードされた、または未読)、 「最新の思い出」タブに「New」バッジを表示すること。)
2. If no new images are available, then the system shall hide the "New" badge.
   (新しい画像がない場合は、「New」バッジを非表示にすること。)

### Requirement 5: バックエンド設定とセキュリティ
**目的:** 開発者として、システムを保守可能にするために、対象フォルダを安全に管理したい。

#### Acceptance Criteria
1. The system shall manage the "Today's Touma" folder ID in the backend configuration (environment variables or settings).
   (「今日のひまお」フォルダIDをバックエンド設定(環境変数または設定ファイル)で管理すること。)
2. The system shall require authentication for the API endpoint retrieving these media files.
   (これらのメディアファイルを取得するAPIエンドポイントには認証を必須とすること。)

Codex CLI:

# 要件定義書

## はじめに
本ドキュメントは、トップページに「最新の思い出」タブを追加し、最新にアップロードされた写真・動画へ素早くアクセスできるページを提供するための要件を定義する。主に「ひまおアルバム>今日のひまお」フォルダ配下のメディアを対象とし、フォルダが空の場合でも最新日付のメディアにフォールバックして閲覧性を確保する。

## 要件

### 要件 1: 最新の思い出タブとアクセス制御
**目的:** ログインユーザーとして、トップページから最新メディア専用ページへ安全に遷移できるようにしたい

#### 受け入れ基準
1. WHEN ログイン済みユーザーがトップページを開く THEN 思い出アルバムは既存タブ群と同じUIで「最新の思い出」タブを表示する
2. WHEN ユーザーが「最新の思い出」タブを選択した場合 THEN 思い出アルバムは最新の思い出ページに遷移し直近メディアを読み込む
3. IF ユーザーが未ログインで最新の思い出ページへアクセスした場合 THEN 思い出アルバムはログインを要求し、認証後に同ページへ遷移する
4. WHERE ナビゲーションがモバイル/デスクトップ表示に切り替わる場合 THEN 思い出アルバムはタブ表示をレイアウトに合わせて崩れずに維持する

### 要件 2: 今日のひまおメディア取得API
**目的:** APIサーバーとして、指定フォルダ配下の最新メディアを取得してフロントへ提供できるようにしたい

#### 受け入れ基準
1. WHEN クライアントが最新の思い出データ取得APIをリクエストした場合 THEN 思い出アルバムAPIはバックエンド設定で管理された「今日のひまお」フォルダ配下の画像・動画一覧を返す
2. IF 「今日のひまお」フォルダ配下にメディアが存在しない場合 THEN 思い出アルバムAPIはGoogle Drive上で最も新しい日付のフォルダまたはメディアを特定し、その日の画像・動画一覧を返す
3. WHEN レスポンスを返す際 THEN 思い出アルバムAPIは各メディアについてメディアID、ファイル名、MIMEタイプ、サムネイルURL(=s300)、表示用URL/動画再生リンク、撮影日時または作成日時、所属日付、メディア種別(写真/動画)を含める
4. WHEN メディア一覧を返す際 THEN 思い出アルバムAPIは日付降順かつ撮影日時の降順でソートし最新のものが先頭になるようにする
5. IF 認証が失敗した場合 THEN 思い出アルバムAPIは401を返しメディア情報を返さない

### 要件 3: 最新のおすすめ写真
**目的:** ユーザーとして、最新日のメディアからランダムに選ばれたおすすめ写真をページ上部で確認できるようにしたい

#### 受け入れ基準
1. WHEN 最新日のメディア一覧に1件以上の写真または動画が含まれる場合 THEN 思い出アルバムはその中からランダムに1件を「最新のおすすめ写真」として選出する
2. WHEN 最新のおすすめ写真を表示する場合 THEN 思い出アルバムは対象メディアの撮影日・種別を示すラベルと共に大きく表示する
3. WHEN 最新のおすすめ写真が選出された場合 THEN 思い出アルバムは同一日付のメディアのみを下部一覧に紐付けて表示する
4. IF 最新日のメディアが0件の場合 THEN 思い出アルバムはおすすめ写真セクションを非表示にし「最新の思い出がまだありません」などの案内を表示する

### 要件 4: 同日メディア一覧表示
**目的:** ユーザーとして、最新日のすべての写真・動画を一覧で確認し個別に閲覧できるようにしたい

#### 受け入れ基準
1. WHEN 最新のおすすめ写真の日付が決定した場合 THEN 思い出アルバムは同日アップロードまたは撮影されたメディアをサムネイルグリッドで表示する
2. WHEN サムネイルを描画する場合 THEN 思い出アルバムは撮影日時の昇順で並べ、動画には再生アイコンをオーバーレイ表示する
3. WHEN ユーザーが写真サムネイルをクリックした場合 THEN 思い出アルバムは既存の拡大表示またはビューアを用いて高解像度で表示する
4. WHEN ユーザーが動画サムネイルをクリックした場合 THEN 思い出アルバムは動画のWebViewLinkを新しいタブで開く
5. IF メディア一覧の取得に失敗した場合 THEN 思い出アルバムは一覧セクションを非表示にしコンソールログでエラーを残す

### 要件 5: Newバッジによる更新通知
**目的:** ユーザーとして、新しいメディアの追加をトップページのタブから素早く認知できるようにしたい

#### 受け入れ基準
1. WHEN 「今日のひまお」フォルダに直近24時間以内の新規アップロードが存在する場合 THEN 思い出アルバムは「最新の思い出」タブに「New」バッジを表示する
2. IF ユーザーの最終閲覧時刻以降に新規メディアが追加された場合 THEN 思い出アルバムはバッジを表示し、最新の思い出ページを開いたタイミングで最終閲覧時刻を更新する
3. WHEN 新規メディアが存在しない場合 THEN 思い出アルバムは「New」バッジを表示しない

design.md(技術設計書)

Overview/概要の比較

Claude Code:

## Overview
Purpose: 最新アップロードの写真・動画を「最新の思い出」タブで即時に見られるようにし、
新着があることを分かりやすく知らせる。
Users: 認証済みの家族・親族ユーザーが日々のアップロード状況を確認し、
最新日付のコンテンツをまとめて閲覧・再生する。
Impact: 既存ダッシュボードに新タブを追加し、バックエンドに「今日のひまお」優先の
取得APIを拡張する。

Gemini CLI:

## Overview
**目的**: この機能は、ユーザーが最近アップロードされた写真や動画
(特に「今日のひまお」フォルダからのもの)に素早くアクセスできるようにする。
**ユーザー**: 家族(ログインユーザー)は、月別アーカイブを閲覧することなく、
日々の更新を確認するためにこれを使用する。
**影響**: ダッシュボードに新しい「最新の思い出」タブを追加し、
「New」バッジ通知とともに最新コンテンツ専用のビューを提供する。

Codex CLI:

## 1. 目的とスコープ
- トップページに「最新の思い出」タブを追加し、「ひまおアルバム>今日のひまお」
  フォルダの最新メディアを即時に閲覧できる導線を提供する。
- 今日のフォルダが空でも最新日付のメディアへフォールバックし、
  ハイライト(ランダム1件)と同日メディア一覧を一画面で表示する。
- 新規アップロードをタブ上の「New」バッジで通知し、閲覧後は既読化する。

### スコープ
- バックエンド: 最新メディア取得APIの新設、フォルダ探索/フォールバックロジック、レスポンス整形
- フロントエンド: 新タブ追加、ハイライト+グリッド表示、バッジ判定と最終閲覧の保存、ローディング/エラー表示
- テスト: 新APIのユニット/統合テスト、フロントのレンダリング/バッジ判定/フェッチエラーハンドリングのテスト

Codex CLIは番号付きでセクションが分かれており、スコープ/非スコープも明確に記載されています。
Claude CodeとGemini CLIは似た構成ですが、Claude Codeは英語キーワード(Purpose/Users/Impact)を使っているのが特徴的です。

全体の特徴

観点 Claude Code Gemini CLI Codex CLI
言語 日本語 日本語 日本語
セクション番号 なし なし あり(1., 2., 3.1...)
セキュリティセクション あり なし 「例外・ログ・性能」に含む
文字数 9,479文字 6,734文字 10,078文字

※比較観点は色々つくれますが、このくらいにしておきます。詳細はdesign.md 全文を御覧ください。

参考: design.md 全文

design.md 全文(クリックで展開)

Claude Code:

# 技術設計書

## Overview
Purpose: 最新アップロードの写真・動画を「最新の思い出」タブで即時に見られるようにし、新着があることを分かりやすく知らせる。
Users: 認証済みの家族・親族ユーザーが日々のアップロード状況を確認し、最新日付のコンテンツをまとめて閲覧・再生する。
Impact: 既存ダッシュボードに新タブを追加し、バックエンドに「今日のひまお」優先の取得APIを拡張する。

### Goals
- 最新の思い出タブを追加し、新着有無を「New」バッジで通知する。
- 「今日のひまお」フォルダを優先して最新日付のメディアを取得し、最上部にランダム1件+同日一覧を表示する。
- 既存認証・UIパターンを流用し、最小限の追加で統合する。

### Non-Goals
- 画像編集・加工機能の提供。
- 複数日を跨いだ履歴ページや高度な通知(プッシュ配信)の実装。
- Drive以外のストレージ対応や履歴アクセスログの保持。

## Architecture

### Existing Architecture Analysis
- フロント: `dashboard/page.tsx`でタブ状態・データ取得を管理し、`RecommendedMedia`/`Monthly*`コンポーネントに委譲。`TabNavigation`はタブID固定。
- バックエンド: `backend/media.py`でDrive探索(年月ベース)、`/media/recommended`でランダム抽出+Gemini説明生成。全エンドポイントは`Depends(get_current_user)`を利用。
- APIクライアント: `frontend/src/lib/api.ts`がRESTをラップし、`types/media.ts`で型定義。

### High-Level Architecture
```mermaid
sequenceDiagram
    actor User
    participant FE as Next.js (Dashboard)
    participant API as FastAPI /media/latest
    participant Drive as Google Drive
    participant Gemini as Gemini API

    User->>FE: 最新の思い出タブを開く
    FE->>API: GET /media/latest (X-User-Email)
    API->>Drive: 今日のひまおフォルダを探索
    API->>Drive: 空なら最新日付フォルダを探索
    API-->>FE: highlighted + items + hasNew
    FE->>User: 最新のおすすめ写真 + 同日一覧を表示
    FE->>Gemini: 既存説明生成を再利用(必要時)
```

### Technology Alignment & Key Design Decisions
- 既存スタック(Next.js/React, FastAPI, Drive API, Gemini, NextAuth + X-User-Emailヘッダー)に完全準拠。新規依存は追加しない。
- **Decision 1**: エンドポイントを`GET /media/latest`として新設し、「今日のひまお」IDを環境変数化。
  - Alternatives: `/media/recommended?scope=latest`で兼用 / 既存`/media`を拡張。
  - Rationale: フォールバックやバッジ判定など専用ロジックを分離し、既存おすすめAPIを壊さない。
  - Trade-offs: エンドポイントが増えるが責務が明確。
- **Decision 2**: Newバッジ判定を「最新取得日時が現在から24時間以内」で行う。
  - Alternatives: 「前回アクセス以降の更新」には状態管理が必要で重い。
  - Rationale: 状態レスで判定可能、仕様の例に合致。
  - Trade-offs: 24時間を跨ぐとバッジが消えるが簡潔で再現性が高い。
- **Decision 3**: highlighted(ランダム1件)とitems(同日全件)をまとめて返すAPIレスポンスを定義。
  - Alternatives: フロントでランダム選択 / 個別API分割。
  - Rationale: サーバー側で決定論を担保し、フロント実装を単純化。
  - Trade-offs: APIレスポンスサイズ増だが当面問題なし。

## System Flows
- **最新取得フロー**: フロントで`getLatestMedia`を呼び、レスポンスの`hasNew`でバッジ表示、`highlighted`をヒーロー表示、`items`を同日グリッド表示。ローディング中はスケルトン、空の場合はエンプティ表示。
- **フォールバックフロー**: 今日のひまおが空→Driveの最新日付フォルダを探索→同日メディアを返却。

## Requirements Traceability
- 1.1–1.4: `TabNavigation`拡張・Dashboard状態管理、`hasNew`でバッジ表示、ヒーロー表示。
- 2.1–2.4: `/media/latest`のフォルダ探索・レスポンス生成で充足。
- 3.1–3.4: `highlighted`表示+`items`一覧、動画再生ハンドリング。
- 4.1–4.3: 既存認証フローを新API・新タブに適用。
- 5.1–5.2: フロントのローディング・エンプティ状態表示。

## Components and Interfaces

### Backend: LatestMedia API (`/media/latest`)
- **Responsibility**: 「今日のひまお」フォルダを優先して最新日付のメディアセットを返却し、ランダム1件をhighlightedとして選択。
- **Dependencies**: Drive API(フォルダ探索、ファイル一覧取得)、既存MIME正規化・認証依存、Gemini説明生成(必要なら既存関数を流用)。
- **Contract (REST)**:
  | Method | Endpoint | Request | Response | Errors |
  |--------|----------|---------|----------|--------|
  | GET | /media/latest | Headers: `X-User-Email` (必須) | `LatestMediaResponse` | 401/403(未認証/未許可), 404(有効メディアなし), 500(Drive/Gemini失敗) |
- **LatestMediaResponse**:
  ```json
  {
    "hasNew": true,
    "date": "2025-12-08",
    "highlighted": MediaItem,
    "items": [MediaItem]
  }
  ```
- **Pre/Post条件**: 「今日のひまお」フォルダIDが設定済み。アイテムはMIME正規化済みでサムネイル/表示用リンクを含む。

### Frontend: Latest Memories Tab
- **Responsibility**: 新タブの状態管理、最新API呼び出し、ヒーロー+同日一覧表示、Newバッジ表示。
- **Dependencies**: `api.getLatestMedia`, `TabNavigation`, `RecommendedMedia`レイアウト、`MediaItem`型拡張。
- **Contract (State/Props)**:
  - `latestData: { highlighted: MediaItem | null; items: MediaItem[]; date: string | null; hasNew: boolean }`
  - `loading.latest: boolean`, `errors.latest?: string`
  - `TabNavigation``latest`タブ追加(aria-current・ホバー挙動は既存踏襲)。

### Shared Types / Utilities
- `MediaItem``uploadedDate`(ISO文字列)を追加し、`LatestMediaResponse`型を新設。
- APIクライアントに`getLatestMedia(): Promise<LatestMediaResponse>`.
- エンプティ/ローディング用のスケルトン/メッセージコンポーネント追加または再利用。

## Data Models
- **MediaItem (拡張)**: `id`, `name`, `mimeType`, `thumbnailLink`, `webViewLink`, `createdTime`, `uploadedDate`, `description?`, `highlight?`.
- **LatestMediaResponse**: `hasNew: boolean`, `date: string`, `highlighted: MediaItem`, `items: MediaItem[]`.
- **日付決定ロジック**: `imageMediaMetadata.time``createdTime`の順で取得し、UTCで比較。最新日付のYYYY-MM-DDを`date`にセット。

## Error Handling
- バックエンド: Drive 4xxは即時エラー、5xxは既存リトライロジックを流用。対象メディアなしは404を返し、フロントはエンプティ表示にフォールバック。
- フロント: `errors.latest`がある場合はエラーバナー内に追加表示。ローディング中はスケルトン、404時は「最新の思い出がまだありません」を表示。
- 認証失敗時は既存のリダイレクト(/login)に従う。

## Testing Strategy
- **Unit (Backend)**: フォルダ探索優先順位(今日のひまお→最新日付)、MIME正規化、24時間以内判定、ランダム選択の決定性(同日内同じseedなら固定)。
- **Integration (Backend)**: `/media/latest`が認証必須であること、空フォルダでフォールバックが動作すること、レスポンス構造/型が正しいこと。
- **Unit (Frontend)**: TabNavigationに新タブが表示されること、`hasNew`でバッジ表示/非表示、ローディング・エンプティ・エラーの描画切替。
- **Integration/UI (Frontend)**: `dashboard/page.tsx`で最新タブ切替時にAPIが呼ばれ、ヒーロー+一覧が表示されること。動画サムネイルがプレーヤーになること。
- **E2E**: ログイン後に最新タブを開き、Newバッジ→最新表示→拡大/再生までの主要フローを検証。

## Security Considerations
- すべての最新API呼び出しで`X-User-Email`を必須とし、`Depends(get_current_user)`で許可ユーザーのみ通過。ログにはフォルダIDやファイルIDを漏らさない。
- Drive APIキー/フォルダIDは環境変数管理。Geminiキーの扱いは既存パターンに従う。

## Performance & Scalability
- Drive呼び出しは最新日だけを探索するため最小限。レスポンスは小規模のため現状キャッシュ不要だが、必要なら既存`CollageCache`を拡張しユーザー別/TTL 5分でキャッシュ可能。
- ランダム選択は1回のみで計算量低。サムネイルは既存プロキシ/サイズ指定を利用。

## Migration Strategy
- 新環境変数(例: `LATEST_MEMORIES_FOLDER_ID`)を追加し、未設定時は明示的に500を返して気づけるようにする。
- デプロイ手順: 環境変数追加 → バックエンドデプロイ → フロントデプロイ(タブ追加)。ロールバックは環境変数を無効化し、新タブを非表示にするフラグを追加可能。

Gemini CLI:

# Design Document: Latest Memories Page (設計書: 最新の思い出ページ)

## Overview
**目的**: この機能は、ユーザーが最近アップロードされた写真や動画(特に「今日のひまお」フォルダからのもの)に素早くアクセスできるようにする。
**ユーザー**: 家族(ログインユーザー)は、月別アーカイブを閲覧することなく、日々の更新を確認するためにこれを使用する。
**影響**: ダッシュボードに新しい「最新の思い出」タブを追加し、「New」バッジ通知とともに最新コンテンツ専用のビューを提供する。

### Goals
- 「今日のひまお」フォルダのコンテンツを表示する。
- ターゲットフォルダが空の場合、利用可能な最新のメディアにフォールバックする。

### Non-Goals
- リアルタイムプッシュ通知(バッジで十分)。
- ユーザーごとの複雑な「未読」追跡(まずは単純な時間ベースのロジック)。

## Architecture

### Architecture Pattern & Boundary Map
**アーキテクチャ統合**:
- **選択パターン**: レイヤードアーキテクチャ (Frontend -> API -> Service -> Google Drive)。
- **ドメイン境界**: この機能は `Media` および `ContentGeneration` ドメイン内に位置する。

### Technology Stack

| Layer | Choice / Version | Role in Feature | Notes |
|-------|------------------|-----------------|-------|
| Frontend | React / Next.js | UI Components | 既存コンポーネントの再利用 |
| Backend | FastAPI | API Endpoint | 新規 `/media/latest` エンドポイント |
| Data | Google Drive | Storage | 特定のフォルダIDをターゲット |

## System Flows

### 最新メディア取得フロー
```mermaid
sequenceDiagram
    participant User
    participant FE as Frontend (LatestMemories)
    participant BE as Backend (/media/latest)
    participant DS as Drive Service

    User->>FE: 「最新の思い出」タブをクリック
    FE->>BE: GET /media/latest
    BE->>DS: get_latest_media(folder_id)
    DS->>DS: 「今日のひまお」内のファイルをリスト
    alt フォルダが空
        DS->>DS: 最新の月別フォルダを探す
        DS->>DS: 最新月からファイルをリスト
    end
    DS-->>BE: List[MediaItem]
    BE->>BE: ランダムにおすすめを選択
    BE->>BE: 説明文を生成 (Gemini)
    BE-->>FE: { recommendation, media_list, is_new }
    FE-->>User: コンテンツを表示
```

## Requirements Traceability

| Requirement | Summary | Components | Interfaces | Flows |
|-------------|---------|------------|------------|-------|
| 1.1, 1.2 | 最新タブとアクセス | TabNavigation, DashboardPage | - | - |
| 1.3 | フォールバックロジック | MediaService | `get_latest_media` | 取得フロー |
| 2.1, 2.2 | おすすめ写真 | LatestMemories, ContentGen | `/media/latest` | 取得フロー |
| 3.1, 3.2 | メディアリスト表示 | LatestMemories, MediaGrid | - | - |
| 4.1, 4.2 | Newバッジ | TabNavigation, DashboardPage | `/media/latest` | - |
| 5.1, 5.2 | 設定とセキュリティ | Backend Config, Router | Env Vars | - |

## Components and Interfaces

### Frontend

#### LatestMemories Component
- Intent: おすすめと最新メディアのリストビューを表示するコンテナ
- Requirements: 2.1, 2.2, 3.1, 3.2

#### TabNavigation Component
- Intent: 「最新」タブとNewバッジを含めるよう更新
- Requirements: 1.1, 4.1, 4.2

### Backend

#### Media Service (Extension)
- Intent: 特定フォルダからフォールバック付きでメディアを取得
- Requirements: 1.3, 5.1

#### Latest Media Router
- Intent: 最新メディア用APIエンドポイント
- Requirements: 1.2, 5.2

## Data Models

### Domain Model
- **MediaItem**: 既存モデル。
- **LatestMediaResponse**: 新しい集約。

### Data Contracts

**LatestMediaResponse (Pydantic)**
```python
class LatestMediaResponse(BaseModel):
    recommendation: RecommendationResponse
    media_list: List[MediaItem]
    is_new: bool
```

## Error Handling

### Error Strategy
- **Drive API Error**: エラー詳細と共に500を返す。
- **No Media Found**: 空リストとnullおすすめを返す(フロントエンドで適切に処理)。

## Testing Strategy
- **Unit Tests**:
  - `test_get_media_from_specific_folder`: Drive APIをモックして取得を検証。
  - `test_latest_media_fallback`: フォルダが空の場合のフォールバックロジックを検証。
  - `test_new_badge_logic`: タイムスタンプ比較を検証。
- **Integration Tests**:
  - `test_get_latest_media_endpoint`: APIレスポンス構造を検証。
- **E2E Tests**:
  - タブ切り替えを検証。
  - バッジ表示を検証。

Codex CLI:

# 設計ドキュメント - latest-omoide-page

## 1. 目的とスコープ
- トップページに「最新の思い出」タブを追加し、「ひまおアルバム>今日のひまお」フォルダの最新メディアを即時に閲覧できる導線を提供する。
- 今日のフォルダが空でも最新日付のメディアへフォールバックし、ハイライト(ランダム1件)と同日メディア一覧を一画面で表示する。
- 新規アップロードをタブ上の「New」バッジで通知し、閲覧後は既読化する。

### スコープ
- バックエンド: 最新メディア取得APIの新設、フォルダ探索/フォールバックロジック、レスポンス整形。
- フロントエンド: 新タブ追加、ハイライト+グリッド表示、バッジ判定と最終閲覧の保存、ローディング/エラー表示。
- テスト: 新APIのユニット/統合テスト、フロントのレンダリング/バッジ判定/フェッチエラーハンドリングのテスト。

### 非スコープ
- AI説明文生成や会話生成の拡張(既存の「今日のおすすめ」を流用しない)。
- 管理画面/UIテーマ変更。

## 2. システム構成概要
- **フロントエンド (Next.js/React)**
  - `TabNavigation``latest` タブを追加し、`DashboardPage` がアクティブタブに応じてデータを取得。
  - `api.getLatestMedia``/media/latest` を叩き、結果からハイライトをランダム選出。
  - `MediaGrid`/`ImageModal` を再利用して同日メディア一覧を表示。動画は `api.getMediaContent` を使用してWebViewLink/ダウンロードURLを取得。
  - `localStorage``latestOmoideLastViewedAt` を保存し、`latestUploadedAt` と比較してNewバッジを判定。
- **バックエンド (FastAPI)**
  - 新エンドポイント `/media/latest` を追加。認証依存は既存と同じ `Depends(get_current_user)`  - 環境変数 `LATEST_TODAY_FOLDER_ID`(「今日のひまお」フォルダID)を優先参照。空なら既存年/月階層から最新日付を算出。
  - 画像/動画のフィルタリング、EXIF撮影日時優先のソート、プレイアブル動画チェックを適用し、日付キーや種別を付与したレスポンスを返却。

## 3. バックエンド設計
### 3.1 エンドポイント仕様 `/media/latest`
- **認証**: `Depends(get_current_user)`(X-User-Emailヘッダー必須)。
- **クエリ**: なし。将来拡張のため `?limit=` を許容する余地を残す。
- **レスポンス例**
  - `date`: "2025-12-08"
  - `source`: "today-folder" または "latest-fallback"
  - `latestUploadedAt`: "2025-12-08T12:34:56Z"
  - `items`: メディアID、ファイル名、MIMEタイプ、mediaType、thumbnailLink、webViewLink、displayUrl、capturedAt、uploadedAt、dayKeyを含む配列
  - `highlightId`: itemsからランダムに1件選択

### 3.2 データ取得フロー
1. 環境変数 `LATEST_TODAY_FOLDER_ID` を取得。未設定なら 400/500 ではなくフォールバックへ進む。
2. **優先フォルダ探索**: `LATEST_TODAY_FOLDER_ID` 配下で `mimeType contains 'image/' or 'video/'` を取得。
   - `imageMediaMetadata/time``capturedAt`。無い場合は `createdTime` を使用。
   - プレイアブル動画のみ許可(`is_browser_playable_video`)。
3. **フォールバック探索**: 1件も無い場合は `find_monthly_folders` から最新年/月フォルダを取得し、同様にメディアを取得。
   - メディアの `capturedAt`/`createdTime` からもっとも新しい日付を `latest_day` として抽出し、その日付のメディアのみ返す。
4. **レスポンス整形**:
   - `mediaType`: `photo`/`video` を付与。
   - `displayUrl`: サムネイルURLで `=s2048` に差し替え。
   - `latestUploadedAt`: `uploadedAt` の最大値(Newバッジ判定用)。
   - `highlightId`: itemsから `random.choice` で1件。
5. **エラーハンドリング**: 認証エラー=401、フォルダ未検出またはメディア0件=404、Drive APIエラー=500(既存リトライを必要に応じて流用)。

### 3.3 設定
- `LATEST_TODAY_FOLDER_ID`: 「ひまおアルバム>今日のひまお」フォルダID。
- 既存 `DRIVE_ROOT_FOLDER_ID`: フォールバック探索に利用。
- 追加が必要な `.env.example` 更新とREADME追記(タスクで対応)。

## 4. フロントエンド設計
### 4.1 データモデル
- `LatestMediaItem extends MediaItem`
  - `mediaType: 'photo' | 'video'`
  - `capturedAt: string` (ISO)
  - `uploadedAt: string` (ISO)
  - `dayKey: string` (YYYY-MM-DD)
  - `displayUrl?: string` (高解像度サムネイル)
- `LatestMediaResponse`
  - `date: string`
  - `source: 'today-folder' | 'latest-fallback'`
  - `latestUploadedAt: string`
  - `items: LatestMediaItem[]`
  - `highlightId: string | null`

### 4.2 UI構成
- **TabNavigation**: `activeTab` のunionに `latest` を追加。`newBadgeTabs`(tab id → boolean)を渡せるよう拡張し、「New」ピルを表示。
- **DashboardPage**:
  - `latest` タブ選択時に `api.getLatestMedia` を呼び、結果を `latestMedia` ステートへ格納。
  - `highlight``useMemo``items` からランダム1件を安定選出(データ更新時のみ変化)。
  - `ImageModal`/`MediaGrid` を組み合わせ、グリッドクリックで画像モーダル/動画新規タブを開く。
  - ローディング: Skeleton流用。エラー: バナーに「最新の思い出の取得に失敗しました」を表示。
  - 最終閲覧: フェッチ成功後、タブ表示完了タイミングで `localStorage.latestOmoideLastViewedAt = new Date().toISOString()` を記録。
- **Newバッジ判定**:
  - `latestUploadedAt``now-24h` 以内 **または** `latestUploadedAt > lastViewedAt` の場合にバッジ表示。
  - `lastViewedAt` が無い場合はバッジ表示。タブ閲覧後に更新して非表示化。
- **ハイライトカード**: `RecommendedMedia` のレイアウトを簡略化し、AI会話/推しポイントを除去した `LatestMediaHighlight` を新規作成。撮影日・種別ラベルと高解像度画像のみ表示。
- **空・エラー時UI**:
  - items空: 「最新の思い出がまだありません」を表示しグリッド非表示。
  - APIエラー: 既存エラーバナーに追加。

### 4.3 APIクライアント
- `api.getLatestMedia(): Promise<LatestMediaResponse>` を追加。エラーレスポンスは既存 `ApiError` を利用。

## 5. 例外・ログ・性能
- **例外**: 認証401 → フロントは `/login` リダイレクトを維持。404 → 空状態表示。500 → エラーバナー。
- **ログ**: バックエンドは Driveクエリ失敗時やフォールバック切替時に INFO/ERROR を出力。フロントはフェッチ失敗を `console.error` + UI表示(既存パターンに合わせる)。
- **性能**: 1日分のみ返却し、ページサイズを1000に固定。必要ならキャッシュ(メモリ/5分)を `latest` 専用に追加検討。画像はサムネイルURLを使用し、`Image`はunoptimizedのまま既存に合わせる。

## 6. テスト計画
- **バックエンド (pytest)**
  - `/media/latest` 認証なしで401。
  - 今日のフォルダにメディアがある場合にdate/items/highlightIdを返す。
  - 今日のフォルダ空→フォールバックで最新日付のみ返す。
  - プレイアブルでない動画が除外されること。
  - latestUploadedAtが最大値になること。
- **フロント (Jest/RTL)**
  - タブに「最新の思い出」表示とバッジ表示条件。
  - APIモックでハイライト/グリッドが描画されること、空データ時は空表示。
  - lastViewedAtが更新されるとバッジが消えること。
  - 動画クリックで `window.open` (または `api.getMediaContent`) が呼ばれること。
- **E2E (Playwright, オプション)**
  - ログイン後、最新タブでハイライトと同日グリッドが見えること。
  - 新規アップロード直後にNewバッジが出るシナリオ(テストデータ前提)。

## 7. リスクと未決事項
- `LATEST_TODAY_FOLDER_ID` が未設定/誤設定の場合の扱いはフォールバックで吸収するが、警告ログを出すか環境チェックを追加するか要検討。
- Newバッジの既読タイミングを「タブ表示時」にするか「API成功+画面描画完了時」にするか。現設計ではAPI成功時点で既読化する想定。
- Google Driveのクエリ性能が日付フィルタ無しの全件取得に依存するため、件数増加時の最適化(キャッシュ/クエリ絞り込み)が将来必要。

## 8. 実装タスクリード
- バックエンド `/media/latest` 実装(フォルダ探索、フォールバック、レスポンス整形、設定追加)。
- フロント TabNavigation拡張 + `api.getLatestMedia` 追加。
- 最新タブ用コンポーネント(ハイライト/グリッド組み合わせ)とNewバッジ処理。
- テスト追加(pytest/Jest)と `.env.example`/README 更新。

まとめ

単純なモデルの性質とcc-sddで設定されているプロンプトだけではなく、今回の検証特有の何かが効いてる可能性を考慮して見てください。

cc-sddを使い、各コーディングエージェントで作成した設計書を比較してみました。
あくまで個人の感想ですが、「読みやすい設計書」という観点で広く勧めるのはCodex CLIかなと思いました。
自然な日本語で設計書が出てくるので、非常に日本人にやさしいです。

一方で、好みなのはClaude Codeで、文章の型が決まっているので、どこに注意を向けて読めばよいのか解釈しやすかったです。

今回の実験のまとめは下記です。


Claude Code

生成される文字数: 中

設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 14,371文字
    • 一文あたりの目安: 80~100文字程度
  • 文章の構造:
    • cc-sddテンプレートに忠実。見出しは適切だが番号なし
    • 英単語と日本語が混ざった文章を生成する
    • 決められている型に忠実な文章を生成するので、慣れれば解釈しやすい文章
  • 理解しやすくする要素:
    • シーケンス図あり、箇条書き適切、既存アーキテクチャ分析が豊富
    • mermaid等の図も適切に使用
    • 既存の実装との兼ね合いや実装戦略も考慮した設計をしてくれる

その他: 設計書作成が非常にスムーズで途中で失敗等はなかった


Gemini CLI

生成される文字数: 少〜中

設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 13,340文字
    • 一文あたりの目安: 40~60文字程度
  • 文章の構造:
    • 英文と日本語が混ざった文章を生成するので、好みが分かれる(オフショアなら良い?)
    • 形式化されていない文章を生成することもある
  • 理解しやすくする要素:
    • mermaid等の図は適切に使用してくれる
    • design.mdは少しシンプルすぎるものができた

その他: なし


Codex CLI

生成される文字数: 中〜多

設計書としての読みやすさ:

  • 文章の長さ:
    • 全体: 15,723文字
    • 一文あたりの目安: 50~70文字程度
  • 文章の構造:
    • 自然な日本語で、読みやすいドキュメントを作ろうとする
    • 文章は自然で読みやすいが、文の型は決まっていない
  • 理解しやすくする要素:
    • mermaid等の図は適切に作ってくれるが、シーケンス図は初手で作ってくれなかった

その他:

  • 設計は具体的な実装について深く記載してあり、実装時の手戻りは少なそう
  • 設計書作成時や触っているときに意図せぬ動作が少しあった

感想

同じcc-sddのプロンプトを使っても、コーディングエージェントによって生成される設計書に大きな差が出ることがわかりました。
これは使用しているモデルや、コーディングエージェントによる差分が見えて面白かったです。

設計書の精度としては、個人的にはCodex CLI, Claude Codeが良かったです。Gemini CLIは少しイメージと違うものを上げてきました。
これもコメントして修正していけば問題ないので、実際に使う上ではそこまで問題ではないと思います。

また気が向いたらモデルごとの比較や、プロンプトごとの比較をやってみようかなと思いました。

次は実装編か、同一モデルでAGENTS.mdを変えて動かす差分をみるか。
気が向いたらやります。気が向いたら。


17
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?