# Gemini APIキー設定 UI/UXフロー詳細設計

**バージョン**: 1.0.0  
**作成日**: 2025年12月16日  
**対象**: NewsSkins Chrome拡張機能 MVP  

---

## 📋 目次

1. [概要](#概要)
2. [フロー全体図](#フロー全体図)
3. [初回セットアップフロー（オンボーディング）](#初回セットアップフロー)
4. [APIキー入力・検証・保存](#apiキー入力検証保存)
5. [エラーハンドリングとトラブルシューティング](#エラーハンドリングとトラブルシューティング)
6. [APIキー管理画面](#apiキー管理画面)
7. [実装ガイド（HTML/CSS/JavaScript）](#実装ガイド)
8. [テスト項目](#テスト項目)

---

## 概要

ユーザーがGemini APIキーを設定する際のUI/UXフローを詳細に設計しました。以下の原則に基づいています：

| 原則 | 説明 |
|-----|------|
| **シンプル** | 3ステップ以内で完了 |
| **安全** | APIキーの入力・保存・表示を安全に |
| **親切** | Google AI Studio へのリンク、ステップバイステップガイド |
| **エラー耐性** | 各種エラーに対して明確なメッセージと対処法を提示 |
| **再利用可能** | キー更新・削除・確認の機能も含む |

---

## フロー全体図

```
┌─────────────────────────────────────────────────────────────────┐
│                    拡張機能インストール                         │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                  初回起動：APIキー未設定を検出                   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│          オンボーディング画面を表示（セットアップウィザード）    │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ ステップ 1/3: APIキーとは？（教育）                     │   │
│  │ ┌─────────────────────────────────────────────────────┐ │   │
│  │ │ 🔑 Gemini APIキーが必要です                         │ │   │
│  │ │                                                     │ │   │
│  │ │ このアプリは、あなたのGemini APIキーを使って      │ │   │
│  │ │ テキスト変換を行います。                           │ │   │
│  │ │                                                     │ │   │
│  │ │ ✅ 無料で取得できます                              │ │   │
│  │ │ ✅ あなたのブラウザ内に保存されます                │ │   │
│  │ │ ✅ サーバーには送信されません                      │ │   │
│  │ │ ✅ いつでも削除・更新できます                      │ │   │
│  │ │                                                     │ │   │
│  │ │ [次へ →]                                           │ │   │
│  │ └─────────────────────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│          ステップ 2/3: APIキーを取得（ガイド付き）              │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 📖 APIキーの取得方法（3ステップ）                      │   │
│  │                                                         │   │
│  │ 1️⃣  Google AI Studio にアクセス                       │   │
│  │     [Google AI Studio を開く ↗]                        │   │
│  │                                                         │   │
│  │ 2️⃣  「Get API Key」をクリック                          │   │
│  │     （新しいタブで開きます）                           │   │
│  │                                                         │   │
│  │ 3️⃣  APIキーをコピー                                    │   │
│  │     （AIza... で始まる39文字）                         │   │
│  │                                                         │   │
│  │ ⏱️  所要時間：約2分                                    │   │
│  │                                                         │   │
│  │ [← 戻る]  [次へ →]                                    │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│        ステップ 3/3: APIキーを入力・検証・保存                   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 🔐 APIキーを入力                                        │   │
│  │                                                         │   │
│  │ [AIza                                              ]   │   │
│  │  ↑ ここにコピーしたAPIキーを貼り付けてください         │   │
│  │                                                         │   │
│  │ 💡 ヒント：                                            │   │
│  │ • 空白や改行を含めないでください                      │   │
│  │ • 「AIza」で始まります                                │   │
│  │ • 39文字です                                          │   │
│  │                                                         │   │
│  │ [← 戻る]  [保存して始める]                            │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    APIキー検証中...                              │
│                                                                 │
│                      ⏳ 検証中...                               │
│                                                                 │
│                  Gemini APIに接続しています                    │
└─────────────────────────────────────────────────────────────────┘
                              │
                    ┌─────────┴─────────┐
                    │                   │
                    ▼                   ▼
            ✅ 成功              ❌ エラー
                    │                   │
                    ▼                   ▼
        ┌─────────────────┐  ┌──────────────────┐
        │ セットアップ完了 │  │ エラーハンドリング│
        │ メイン画面へ    │  │ 原因を特定・表示  │
        └─────────────────┘  └──────────────────┘
                                      │
                                      ▼
                        ┌──────────────────────────┐
                        │ 再入力を促す              │
                        │ 設定画面に戻る            │
                        └──────────────────────────┘
```

---

## 初回セットアップフロー

### フェーズ1: ウェルカム画面（教育）

**目的**: ユーザーにAPIキーの必要性と安全性を理解させる

**画面構成**:

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                          🔑                                     │
│                                                                 │
│                  Gemini APIキーが必要です                       │
│                                                                 │
│  このアプリは、あなたのGemini APIキーを使ってテキスト変換を     │
│  行います。                                                     │
│                                                                 │
│  ✅ 無料で取得できます                                         │
│     Google AI Studioで無料のAPIキーを発行できます             │
│                                                                 │
│  ✅ あなたのブラウザ内に保存されます                           │
│     ローカルストレージ（chrome.storage.local）に保存          │
│                                                                 │
│  ✅ サーバーには送信されません                                 │
│     PWAサーバーに送信されることはありません                   │
│                                                                 │
│  ✅ いつでも削除・更新できます                                 │
│     設定画面から簡単に変更・削除可能                           │
│                                                                 │
│                    [次へ →]                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**テキスト内容**:

> **Gemini APIキーとは？**
>
> Google Gemini APIは、テキスト生成・分析を行うAI APIです。このアプリでは、あなたが選択したテキストをGemini APIに送信して、指定されたスタイルで変換しています。
>
> **なぜAPIキーが必要？**
>
> APIキーは、あなたがGemini APIを使用する権限を証明するものです。このアプリはあなたのAPIキーを使って、Googleのサーバーに直接アクセスします。
>
> **安全性について**
>
> - あなたのAPIキーはあなたのブラウザ内にのみ保存されます
> - このアプリのサーバーには一切送信されません
> - あなたが削除するまで、あなたのコンピュータ内に留まります

### フェーズ2: APIキー取得ガイド

**目的**: ユーザーがGoogle AI StudioからAPIキーを取得するのを支援

**画面構成**:

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│              📖 APIキーの取得方法（3ステップ）                  │
│                                                                 │
│  1️⃣  Google AI Studio にアクセス                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  [Google AI Studio を開く ↗]                            │   │
│  │                                                         │   │
│  │  新しいタブで Google AI Studio が開きます              │   │
│  │  （既にログインしていれば、そのまま進みます）          │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  2️⃣  「Get API Key」をクリック                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  Google AI Studio の画面で「Get API Key」ボタンを      │   │
│  │  クリックしてください。                                │   │
│  │                                                         │   │
│  │  初回の場合は、プロジェクトの作成を求められます。      │   │
│  │  「Create」をクリックして進んでください。              │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  3️⃣  APIキーをコピー                                           │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  表示されたAPIキー（AIza... で始まる39文字）を         │   │
│  │  コピーしてください。                                  │   │
│  │                                                         │   │
│  │  💡 コピーボタンが表示されているはずです。            │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ⏱️  所要時間：約2分                                           │
│                                                                 │
│  [← 戻る]  [次へ →]                                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**ボタンの実装**:

```javascript
// Google AI Studio を開く
document.getElementById('open-ai-studio').addEventListener('click', () => {
  chrome.tabs.create({
    url: 'https://aistudio.google.com/app/apikey',
    active: true
  });
});
```

### フェーズ3: APIキー入力・検証・保存

**目的**: ユーザーからAPIキーを入力させ、検証・保存する

**画面構成**:

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                  🔐 APIキーを入力                               │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ AIza                                                [👁]│   │
│  │                                                         │   │
│  │ ↑ ここにコピーしたAPIキーを貼り付けてください         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  💡 ヒント：                                                    │
│  • 空白や改行を含めないでください                             │
│  • 「AIza」で始まります                                       │
│  • 39文字です                                                 │
│  • 👁 アイコンをクリックすると、入力内容を表示できます       │
│                                                                 │
│  [← 戻る]  [保存して始める]                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**入力フィールドの仕様**:

| 項目 | 仕様 |
|-----|------|
| **タイプ** | `password`（デフォルト）、👁 で `text` に切り替え可能 |
| **プレースホルダ** | `AIza...` |
| **バリデーション** | リアルタイム（入力中） |
| **フォーマット** | 空白・改行を自動削除 |
| **最大長** | 39文字 |

**リアルタイムバリデーション**:

```javascript
const input = document.getElementById('api-key-input');

input.addEventListener('input', (e) => {
  let value = e.target.value.trim();
  
  // 空白・改行を削除
  value = value.replace(/\s/g, '');
  
  // 最大39文字に制限
  value = value.substring(0, 39);
  
  // 入力フィールドを更新
  e.target.value = value;
  
  // リアルタイムバリデーション
  const isValid = validateApiKeyFormat(value);
  const saveBtn = document.getElementById('save-btn');
  saveBtn.disabled = !isValid || value.length === 0;
  
  // フォーマットチェック表示
  updateValidationUI(value);
});

function updateValidationUI(value) {
  const indicator = document.getElementById('validation-indicator');
  
  if (value.length === 0) {
    indicator.textContent = '';
    indicator.className = '';
  } else if (!value.startsWith('AIza')) {
    indicator.textContent = '❌ 「AIza」で始まる必要があります';
    indicator.className = 'error';
  } else if (value.length < 39) {
    indicator.textContent = `⚠️  ${39 - value.length}文字入力してください`;
    indicator.className = 'warning';
  } else if (value.length === 39 && /^AIza[a-zA-Z0-9_-]{35}$/.test(value)) {
    indicator.textContent = '✅ フォーマットが正しいです';
    indicator.className = 'success';
  } else {
    indicator.textContent = '❌ 無効な形式です';
    indicator.className = 'error';
  }
}
```

---

## APIキー入力・検証・保存

### 検証ステップ

**ステップ1: フォーマット検証（クライアント側）**

```javascript
function validateApiKeyFormat(apiKey) {
  // Gemini APIキーの形式: AIza + 35文字（英数字、アンダースコア、ハイフン）
  const pattern = /^AIza[a-zA-Z0-9_-]{35}$/;
  return pattern.test(apiKey);
}
```

**ステップ2: 実際の有効性検証（サーバー側）**

```javascript
async function validateApiKey(apiKey) {
  try {
    const response = await fetch(
      `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,
      {
        method: 'GET',
        timeout: 10000 // 10秒でタイムアウト
      }
    );

    if (response.ok) {
      return {
        valid: true,
        message: 'APIキーが有効です'
      };
    } else if (response.status === 401 || response.status === 403) {
      return {
        valid: false,
        code: 'INVALID_KEY',
        message: 'APIキーが無効です。再確認してください。'
      };
    } else if (response.status === 429) {
      return {
        valid: false,
        code: 'QUOTA_EXCEEDED',
        message: 'APIのクォータを超過しています。Google AI Studioで確認してください。'
      };
    } else {
      return {
        valid: false,
        code: 'UNKNOWN_ERROR',
        message: 'APIキーの検証に失敗しました。後でもう一度試してください。'
      };
    }
  } catch (error) {
    if (error.name === 'AbortError') {
      return {
        valid: false,
        code: 'TIMEOUT',
        message: 'APIキーの検証がタイムアウトしました。インターネット接続を確認してください。'
      };
    } else {
      return {
        valid: false,
        code: 'NETWORK_ERROR',
        message: 'ネットワークエラーが発生しました。インターネット接続を確認してください。'
      };
    }
  }
}
```

### 検証中の画面

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                                                                 │
│                          ⏳                                     │
│                                                                 │
│                      APIキーを検証中...                         │
│                                                                 │
│                  Gemini APIに接続しています                    │
│                                                                 │
│                                                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 成功時の画面

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                          ✅                                     │
│                                                                 │
│                    セットアップが完了しました！                 │
│                                                                 │
│  APIキーが正常に保存されました。                                │
│  これでテキスト変換を使用できます。                            │
│                                                                 │
│                   [メイン画面へ進む →]                         │
│                                                                 │
│                                                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**実装**:

```javascript
async function saveApiKey() {
  const apiKey = document.getElementById('api-key-input').value.trim();
  
  // フォーマット検証
  if (!validateApiKeyFormat(apiKey)) {
    showError('無効なAPIキー形式です。');
    return;
  }

  // UI更新：検証中
  showLoadingScreen();

  // 実際の有効性検証
  const result = await validateApiKey(apiKey);

  if (result.valid) {
    // ストレージに保存
    await chrome.storage.local.set({
      gemini_api_key: apiKey,
      api_key_saved_at: new Date().toISOString()
    });

    // 成功画面を表示
    showSuccessScreen();

    // 2秒後にメイン画面へ遷移
    setTimeout(() => {
      showMainScreen();
    }, 2000);
  } else {
    // エラー画面を表示
    showErrorScreen(result);
  }
}
```

---

## エラーハンドリングとトラブルシューティング

### エラーパターンと対応

| エラーコード | 原因 | ユーザー向けメッセージ | 対処法 |
|-------------|------|----------------------|--------|
| **INVALID_KEY** | APIキーが無効 | APIキーが無効です。再確認してください。 | Google AI Studioでキーを再確認 |
| **QUOTA_EXCEEDED** | クォータ超過 | APIのクォータを超過しています。 | Google AI Studioで使用状況を確認 |
| **TIMEOUT** | タイムアウト | APIキーの検証がタイムアウトしました。 | インターネット接続を確認、再試行 |
| **NETWORK_ERROR** | ネットワークエラー | ネットワークエラーが発生しました。 | インターネット接続を確認、再試行 |
| **EMPTY_KEY** | 空の入力 | APIキーを入力してください。 | APIキーを入力 |
| **FORMAT_ERROR** | フォーマット不正 | 「AIza」で始まる39文字である必要があります。 | Google AI Studioでキーを再確認 |

### エラー画面の設計

**エラータイプ1: 無効なAPIキー**

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                          ❌                                     │
│                                                                 │
│                  APIキーが無効です                              │
│                                                                 │
│  入力されたAPIキーが無効です。以下を確認してください：          │
│                                                                 │
│  ✓ 「AIza」で始まっていますか？                               │
│  ✓ 39文字ですか？                                             │
│  ✓ 空白や改行が含まれていませんか？                           │
│  ✓ Google AI Studioで有効なキーですか？                       │
│                                                                 │
│  [Google AI Studio で確認する ↗]                              │
│                                                                 │
│  [← 戻る]  [もう一度試す]                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**エラータイプ2: クォータ超過**

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                          ⚠️                                     │
│                                                                 │
│              APIのクォータを超過しています                      │
│                                                                 │
│  このAPIキーの月間使用量が上限に達しています。                 │
│                                                                 │
│  解決方法：                                                     │
│  1. Google AI Studio にアクセス                               │
│  2. 「Billing」で使用状況を確認                               │
│  3. 必要に応じて有料プランにアップグレード                     │
│                                                                 │
│  [Google AI Studio で確認する ↗]                              │
│                                                                 │
│  [← 戻る]  [別のAPIキーを使う]                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**エラータイプ3: ネットワークエラー**

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                          🌐                                     │
│                                                                 │
│              ネットワークエラーが発生しました                   │
│                                                                 │
│  APIキーの検証中にネットワークエラーが発生しました。           │
│                                                                 │
│  確認事項：                                                     │
│  ✓ インターネット接続を確認してください                       │
│  ✓ ファイアウォールやプロキシの設定を確認してください         │
│  ✓ 少し待ってから再試行してください                           │
│                                                                 │
│  [← 戻る]  [再試行]                                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### トラブルシューティングガイド

**Q: APIキーが見つかりません**

```
A: 以下の手順で取得してください：

1. https://aistudio.google.com/app/apikey にアクセス
2. Googleアカウントでログイン（まだの場合）
3. 「Get API Key」をクリック
4. 「Create API key in new project」をクリック
5. 表示されたAPIキーをコピー
```

**Q: 「無効なAPIキー」というエラーが出ます**

```
A: 以下を確認してください：

1. APIキーが「AIza」で始まっていますか？
2. 39文字ですか？
3. 空白や改行が含まれていませんか？
4. Google AI Studioで「Disabled」になっていませんか？
5. クォータを超過していませんか？

それでも解決しない場合は、新しいAPIキーを作成してください。
```

**Q: 「クォータを超過しています」というエラーが出ます**

```
A: 月間の使用量が上限に達しています。

解決方法：
1. Google AI Studio にアクセス
2. 「Billing」で使用状況を確認
3. 有料プランにアップグレード（オプション）
4. または翌月まで待つ

無料プランの上限は月間60リクエストです。
```

---

## APIキー管理画面

### 設定ページの構成

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│                  ⚙️ 設定                                        │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  🔑 APIキー管理                                                │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  現在のAPIキー: AIza...xxxxxx                           │   │
│  │                                                         │   │
│  │  ✅ 有効（最終確認: 2025-12-16）                        │   │
│  │                                                         │   │
│  │  [APIキーを更新]  [APIキーを削除]                      │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  🎨 デフォルトスキン                                            │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  [関西弁 ▼]                                            │   │
│  │                                                         │   │
│  │  新しい変換を開始する際のデフォルトスキンを選択        │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  📝 履歴設定                                                    │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  ☐ 変換履歴を保存する                                  │   │
│  │                                                         │   │
│  │  有効にすると、過去50件の変換履歴がローカルに保存      │   │
│  │  されます。30日後に自動削除されます。                  │   │
│  │                                                         │   │
│  │  [詳細を見る]                                          │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ℹ️ 情報                                                        │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                                                         │   │
│  │  バージョン: 1.0.0                                     │   │
│  │  [プライバシーポリシー]  [ヘルプ]  [フィードバック]   │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### APIキー更新フロー

```
[1] 「APIキーを更新」をクリック
         │
         ▼
[2] 確認ダイアログを表示
    ┌─────────────────────────────────────┐
    │ APIキーを更新しますか？             │
    │                                     │
    │ 現在のAPIキー: AIza...xxxxxx        │
    │                                     │
    │ [キャンセル]  [更新する]            │
    └─────────────────────────────────────┘
         │
         ▼
[3] APIキー入力画面を表示（初回セットアップと同じ）
         │
         ▼
[4] 新しいAPIキーを検証・保存
         │
         ▼
[5] 成功メッセージを表示
    ┌─────────────────────────────────────┐
    │ ✅ APIキーを更新しました           │
    │                                     │
    │ 新しいAPIキー: AIza...yyyyyy        │
    │ 更新日時: 2025-12-16 14:30         │
    └─────────────────────────────────────┘
```

### APIキー削除フロー

```
[1] 「APIキーを削除」をクリック
         │
         ▼
[2] 警告ダイアログを表示
    ┌─────────────────────────────────────┐
    │ ⚠️ APIキーを削除しますか？         │
    │                                     │
    │ この操作は取り消せません。          │
    │ 削除後は、新しいAPIキーを設定      │
    │ する必要があります。                │
    │                                     │
    │ [キャンセル]  [削除する]            │
    └─────────────────────────────────────┘
         │
         ▼
[3] APIキーを削除
         │
         ▼
[4] 初回セットアップ画面に戻る
```

---

## 実装ガイド

### HTML実装例

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>APIキー設定 - AIスラングメーカー</title>
  <link rel="stylesheet" href="setup.css">
</head>
<body>
  <div id="app" class="setup-container">
    
    <!-- ステップ 1: ウェルカム画面 -->
    <div id="step-1" class="setup-step active">
      <div class="step-header">
        <div class="step-icon">🔑</div>
        <h1>Gemini APIキーが必要です</h1>
      </div>
      
      <div class="step-content">
        <p class="description">
          このアプリは、あなたのGemini APIキーを使ってテキスト変換を行います。
        </p>
        
        <div class="benefits">
          <div class="benefit">
            <span class="benefit-icon">✅</span>
            <span class="benefit-text">無料で取得できます</span>
          </div>
          <div class="benefit">
            <span class="benefit-icon">✅</span>
            <span class="benefit-text">あなたのブラウザ内に保存されます</span>
          </div>
          <div class="benefit">
            <span class="benefit-icon">✅</span>
            <span class="benefit-text">サーバーには送信されません</span>
          </div>
          <div class="benefit">
            <span class="benefit-icon">✅</span>
            <span class="benefit-text">いつでも削除・更新できます</span>
          </div>
        </div>
      </div>
      
      <div class="step-actions">
        <button id="step-1-next" class="btn-primary">次へ →</button>
      </div>
    </div>

    <!-- ステップ 2: APIキー取得ガイド -->
    <div id="step-2" class="setup-step">
      <div class="step-header">
        <div class="step-number">2 / 3</div>
        <h1>📖 APIキーの取得方法</h1>
      </div>
      
      <div class="step-content">
        <div class="guide-step">
          <div class="guide-number">1️⃣</div>
          <div class="guide-content">
            <h3>Google AI Studio にアクセス</h3>
            <button id="open-ai-studio" class="btn-link">
              Google AI Studio を開く ↗
            </button>
            <p class="guide-note">新しいタブで開きます</p>
          </div>
        </div>

        <div class="guide-step">
          <div class="guide-number">2️⃣</div>
          <div class="guide-content">
            <h3>「Get API Key」をクリック</h3>
            <p>Google AI Studio の画面で「Get API Key」ボタンをクリックしてください。</p>
            <p class="guide-note">初回の場合は、プロジェクトの作成を求められます。「Create」をクリックして進んでください。</p>
          </div>
        </div>

        <div class="guide-step">
          <div class="guide-number">3️⃣</div>
          <div class="guide-content">
            <h3>APIキーをコピー</h3>
            <p>表示されたAPIキー（AIza... で始まる39文字）をコピーしてください。</p>
            <p class="guide-note">コピーボタンが表示されているはずです。</p>
          </div>
        </div>

        <div class="guide-time">
          <span class="time-icon">⏱️</span>
          <span class="time-text">所要時間：約2分</span>
        </div>
      </div>
      
      <div class="step-actions">
        <button id="step-2-back" class="btn-secondary">← 戻る</button>
        <button id="step-2-next" class="btn-primary">次へ →</button>
      </div>
    </div>

    <!-- ステップ 3: APIキー入力 -->
    <div id="step-3" class="setup-step">
      <div class="step-header">
        <div class="step-number">3 / 3</div>
        <h1>🔐 APIキーを入力</h1>
      </div>
      
      <div class="step-content">
        <div class="input-group">
          <label for="api-key-input">APIキー</label>
          <div class="input-wrapper">
            <input
              id="api-key-input"
              type="password"
              placeholder="AIza..."
              maxlength="39"
              autocomplete="off"
            />
            <button id="toggle-visibility" class="btn-icon" title="表示/非表示">
              👁
            </button>
          </div>
          <div id="validation-indicator" class="validation-indicator"></div>
        </div>

        <div class="input-hints">
          <h3>💡 ヒント：</h3>
          <ul>
            <li>空白や改行を含めないでください</li>
            <li>「AIza」で始まります</li>
            <li>39文字です</li>
            <li>👁 アイコンをクリックすると、入力内容を表示できます</li>
          </ul>
        </div>
      </div>
      
      <div class="step-actions">
        <button id="step-3-back" class="btn-secondary">← 戻る</button>
        <button id="save-api-key" class="btn-primary" disabled>保存して始める</button>
      </div>
    </div>

    <!-- ローディング画面 -->
    <div id="loading-screen" class="setup-step">
      <div class="loading-content">
        <div class="spinner"></div>
        <p class="loading-text">APIキーを検証中...</p>
        <p class="loading-subtext">Gemini APIに接続しています</p>
      </div>
    </div>

    <!-- 成功画面 -->
    <div id="success-screen" class="setup-step">
      <div class="success-content">
        <div class="success-icon">✅</div>
        <h1>セットアップが完了しました！</h1>
        <p class="success-message">APIキーが正常に保存されました。</p>
        <p class="success-submessage">これでテキスト変換を使用できます。</p>
        <button id="go-to-main" class="btn-primary">メイン画面へ進む →</button>
      </div>
    </div>

    <!-- エラー画面 -->
    <div id="error-screen" class="setup-step">
      <div class="error-content">
        <div class="error-icon">❌</div>
        <h1 id="error-title">エラーが発生しました</h1>
        <p id="error-message" class="error-message"></p>
        <div id="error-details" class="error-details"></div>
        <div class="error-actions">
          <button id="error-retry" class="btn-primary">もう一度試す</button>
          <button id="error-back" class="btn-secondary">← 戻る</button>
        </div>
      </div>
    </div>

  </div>

  <script src="../utils/storage.js"></script>
  <script src="../utils/validation.js"></script>
  <script src="setup.js"></script>
</body>
</html>
```

### CSS実装例

```css
/* setup.css */

:root {
  --primary-color: #9333EA;
  --secondary-color: #EC4899;
  --accent-color: #F97316;
  --success-color: #10B981;
  --error-color: #EF4444;
  --warning-color: #F59E0B;
  --bg-light: #FFFFFF;
  --bg-dark: #F3F4F6;
  --text-primary: #1F2937;
  --text-secondary: #6B7280;
  --border-color: #E5E7EB;
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.15);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  background: linear-gradient(135deg, #F3F4F6 0%, #E5E7EB 100%);
  color: var(--text-primary);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.setup-container {
  width: 100%;
  max-width: 500px;
  background: var(--bg-light);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.setup-step {
  padding: 40px 32px;
  display: none;
  animation: fadeIn 0.3s ease-out;
}

.setup-step.active {
  display: flex;
  flex-direction: column;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ステップヘッダー */
.step-header {
  text-align: center;
  margin-bottom: 32px;
}

.step-number {
  display: inline-block;
  background: var(--primary-color);
  color: white;
  padding: 4px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 12px;
}

.step-icon {
  font-size: 48px;
  margin-bottom: 16px;
}

.step-header h1 {
  font-size: 24px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 8px;
}

/* ステップコンテンツ */
.step-content {
  flex: 1;
  margin-bottom: 32px;
}

.description {
  font-size: 16px;
  line-height: 1.6;
  color: var(--text-secondary);
  margin-bottom: 24px;
}

/* ベネフィット */
.benefits {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.benefit {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  background: var(--bg-dark);
  border-radius: 8px;
  font-size: 14px;
}

.benefit-icon {
  font-size: 18px;
  flex-shrink: 0;
}

.benefit-text {
  color: var(--text-primary);
}

/* ガイドステップ */
.guide-step {
  display: flex;
  gap: 16px;
  margin-bottom: 24px;
}

.guide-number {
  font-size: 24px;
  flex-shrink: 0;
}

.guide-content h3 {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 8px;
  color: var(--text-primary);
}

.guide-content p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.guide-note {
  font-size: 12px;
  color: var(--text-secondary);
  font-style: italic;
}

.guide-time {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px;
  background: var(--bg-dark);
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-primary);
}

.time-icon {
  font-size: 18px;
}

/* 入力フィールド */
.input-group {
  margin-bottom: 24px;
}

.input-group label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 8px;
  color: var(--text-primary);
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

.input-wrapper input {
  width: 100%;
  padding: 12px 40px 12px 16px;
  border: 2px solid var(--border-color);
  border-radius: 8px;
  font-size: 14px;
  font-family: 'Courier New', monospace;
  transition: border-color 0.2s ease;
}

.input-wrapper input:focus {
  outline: none;
  border-color: var(--primary-color);
  box-shadow: 0 0 0 3px rgba(147, 51, 234, 0.1);
}

.btn-icon {
  position: absolute;
  right: 12px;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 18px;
  padding: 4px;
  transition: opacity 0.2s ease;
}

.btn-icon:hover {
  opacity: 0.7;
}

/* バリデーション表示 */
.validation-indicator {
  margin-top: 8px;
  font-size: 12px;
  min-height: 20px;
}

.validation-indicator.error {
  color: var(--error-color);
}

.validation-indicator.warning {
  color: var(--warning-color);
}

.validation-indicator.success {
  color: var(--success-color);
}

/* ヒント */
.input-hints {
  background: var(--bg-dark);
  padding: 16px;
  border-radius: 8px;
  margin-top: 16px;
}

.input-hints h3 {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 8px;
  color: var(--text-primary);
}

.input-hints ul {
  list-style: none;
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.8;
}

.input-hints li:before {
  content: "• ";
  color: var(--primary-color);
  font-weight: bold;
  margin-right: 4px;
}

/* ボタン */
.step-actions {
  display: flex;
  gap: 12px;
  justify-content: space-between;
}

.btn-primary,
.btn-secondary,
.btn-link {
  padding: 12px 24px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-primary {
  background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
  color: white;
  flex: 1;
}

.btn-primary:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(147, 51, 234, 0.4);
}

.btn-primary:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--bg-dark);
  color: var(--text-primary);
  flex: 1;
}

.btn-secondary:hover {
  background: var(--border-color);
}

.btn-link {
  background: none;
  color: var(--primary-color);
  padding: 8px 0;
  text-decoration: underline;
  cursor: pointer;
}

.btn-link:hover {
  color: var(--secondary-color);
}

/* ローディング画面 */
.loading-content,
.success-content,
.error-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border-color);
  border-top-color: var(--primary-color);
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16px;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loading-text {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 8px;
}

.loading-subtext {
  font-size: 14px;
  color: var(--text-secondary);
}

/* 成功画面 */
.success-icon {
  font-size: 64px;
  margin-bottom: 16px;
}

.success-content h1 {
  font-size: 24px;
  font-weight: 700;
  margin-bottom: 8px;
}

.success-message {
  font-size: 16px;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.success-submessage {
  font-size: 14px;
  color: var(--text-secondary);
  margin-bottom: 24px;
}

/* エラー画面 */
.error-icon {
  font-size: 64px;
  margin-bottom: 16px;
}

.error-content h1 {
  font-size: 24px;
  font-weight: 700;
  margin-bottom: 8px;
  color: var(--error-color);
}

.error-message {
  font-size: 16px;
  color: var(--text-secondary);
  margin-bottom: 16px;
}

.error-details {
  background: var(--bg-dark);
  padding: 16px;
  border-radius: 8px;
  margin-bottom: 24px;
  font-size: 12px;
  color: var(--text-secondary);
  text-align: left;
  max-height: 150px;
  overflow-y: auto;
}

.error-actions {
  display: flex;
  gap: 12px;
  width: 100%;
}

.error-actions button {
  flex: 1;
}
```

### JavaScript実装例

```javascript
// setup.js

class SetupWizard {
  constructor() {
    this.currentStep = 1;
    this.apiKey = '';
    this.init();
  }

  init() {
    this.attachEventListeners();
    this.checkApiKey();
  }

  checkApiKey() {
    chrome.storage.local.get('gemini_api_key', (result) => {
      if (result.gemini_api_key) {
        // APIキーが既に設定されている場合
        this.showMainScreen();
      } else {
        // APIキーが未設定の場合
        this.showStep(1);
      }
    });
  }

  attachEventListeners() {
    // ステップ 1
    document.getElementById('step-1-next').addEventListener('click', () => {
      this.showStep(2);
    });

    // ステップ 2
    document.getElementById('step-2-back').addEventListener('click', () => {
      this.showStep(1);
    });

    document.getElementById('step-2-next').addEventListener('click', () => {
      this.showStep(3);
    });

    document.getElementById('open-ai-studio').addEventListener('click', () => {
      chrome.tabs.create({
        url: 'https://aistudio.google.com/app/apikey',
        active: true
      });
    });

    // ステップ 3
    document.getElementById('step-3-back').addEventListener('click', () => {
      this.showStep(2);
    });

    const apiKeyInput = document.getElementById('api-key-input');
    apiKeyInput.addEventListener('input', (e) => this.validateInput(e));

    const toggleVisibility = document.getElementById('toggle-visibility');
    toggleVisibility.addEventListener('click', () => this.togglePasswordVisibility());

    const saveBtn = document.getElementById('save-api-key');
    saveBtn.addEventListener('click', () => this.saveApiKey());

    // エラー画面
    document.getElementById('error-retry').addEventListener('click', () => {
      this.showStep(3);
    });

    document.getElementById('error-back').addEventListener('click', () => {
      this.showStep(2);
    });

    // 成功画面
    document.getElementById('go-to-main').addEventListener('click', () => {
      this.showMainScreen();
    });
  }

  showStep(stepNumber) {
    // すべてのステップを非表示
    document.querySelectorAll('.setup-step').forEach(step => {
      step.classList.remove('active');
    });

    // 指定されたステップを表示
    const stepId = `step-${stepNumber}`;
    const stepElement = document.getElementById(stepId);
    if (stepElement) {
      stepElement.classList.add('active');
    }

    this.currentStep = stepNumber;
  }

  validateInput(e) {
    let value = e.target.value.trim();
    value = value.replace(/\s/g, '');
    value = value.substring(0, 39);
    e.target.value = value;

    const isValid = /^AIza[a-zA-Z0-9_-]{35}$/.test(value);
    const saveBtn = document.getElementById('save-api-key');
    saveBtn.disabled = !isValid || value.length === 0;

    this.updateValidationUI(value);
  }

  updateValidationUI(value) {
    const indicator = document.getElementById('validation-indicator');

    if (value.length === 0) {
      indicator.textContent = '';
      indicator.className = 'validation-indicator';
    } else if (!value.startsWith('AIza')) {
      indicator.textContent = '❌ 「AIza」で始まる必要があります';
      indicator.className = 'validation-indicator error';
    } else if (value.length < 39) {
      indicator.textContent = `⚠️ ${39 - value.length}文字入力してください`;
      indicator.className = 'validation-indicator warning';
    } else if (value.length === 39 && /^AIza[a-zA-Z0-9_-]{35}$/.test(value)) {
      indicator.textContent = '✅ フォーマットが正しいです';
      indicator.className = 'validation-indicator success';
    } else {
      indicator.textContent = '❌ 無効な形式です';
      indicator.className = 'validation-indicator error';
    }
  }

  togglePasswordVisibility() {
    const input = document.getElementById('api-key-input');
    const btn = document.getElementById('toggle-visibility');

    if (input.type === 'password') {
      input.type = 'text';
      btn.textContent = '🙈';
    } else {
      input.type = 'password';
      btn.textContent = '👁';
    }
  }

  async saveApiKey() {
    const apiKey = document.getElementById('api-key-input').value.trim();

    if (!validateApiKeyFormat(apiKey)) {
      this.showError('無効なAPIキー形式です。');
      return;
    }

    this.showLoadingScreen();

    try {
      const result = await validateApiKey(apiKey);

      if (result.valid) {
        await chrome.storage.local.set({
          gemini_api_key: apiKey,
          api_key_saved_at: new Date().toISOString()
        });

        this.showSuccessScreen();

        setTimeout(() => {
          this.showMainScreen();
        }, 2000);
      } else {
        this.showErrorScreen(result);
      }
    } catch (error) {
      this.showErrorScreen({
        code: 'UNKNOWN_ERROR',
        message: 'エラーが発生しました。後でもう一度試してください。'
      });
    }
  }

  showLoadingScreen() {
    document.querySelectorAll('.setup-step').forEach(step => {
      step.classList.remove('active');
    });
    document.getElementById('loading-screen').classList.add('active');
  }

  showSuccessScreen() {
    document.querySelectorAll('.setup-step').forEach(step => {
      step.classList.remove('active');
    });
    document.getElementById('success-screen').classList.add('active');
  }

  showErrorScreen(error) {
    document.querySelectorAll('.setup-step').forEach(step => {
      step.classList.remove('active');
    });

    const errorScreen = document.getElementById('error-screen');
    errorScreen.classList.add('active');

    document.getElementById('error-title').textContent = this.getErrorTitle(error.code);
    document.getElementById('error-message').textContent = error.message;

    const errorDetails = document.getElementById('error-details');
    errorDetails.innerHTML = this.getErrorDetails(error.code);
  }

  getErrorTitle(code) {
    const titles = {
      'INVALID_KEY': 'APIキーが無効です',
      'QUOTA_EXCEEDED': 'APIのクォータを超過しています',
      'TIMEOUT': 'APIキーの検証がタイムアウトしました',
      'NETWORK_ERROR': 'ネットワークエラーが発生しました',
      'UNKNOWN_ERROR': 'エラーが発生しました'
    };
    return titles[code] || 'エラーが発生しました';
  }

  getErrorDetails(code) {
    const details = {
      'INVALID_KEY': `
        <p>入力されたAPIキーが無効です。以下を確認してください：</p>
        <ul>
          <li>「AIza」で始まっていますか？</li>
          <li>39文字ですか？</li>
          <li>空白や改行が含まれていませんか？</li>
          <li>Google AI Studioで有効なキーですか？</li>
        </ul>
      `,
      'QUOTA_EXCEEDED': `
        <p>このAPIキーの月間使用量が上限に達しています。</p>
        <p>Google AI Studioで使用状況を確認し、必要に応じて有料プランにアップグレードしてください。</p>
      `,
      'TIMEOUT': `
        <p>APIキーの検証がタイムアウトしました。</p>
        <p>インターネット接続を確認して、もう一度試してください。</p>
      `,
      'NETWORK_ERROR': `
        <p>ネットワークエラーが発生しました。</p>
        <p>インターネット接続を確認して、もう一度試してください。</p>
      `,
      'UNKNOWN_ERROR': `
        <p>予期しないエラーが発生しました。</p>
        <p>後でもう一度試してください。</p>
      `
    };
    return details[code] || '';
  }

  showMainScreen() {
    // メイン画面へ遷移
    window.location.href = chrome.runtime.getURL('popup/popup.html');
  }
}

// 初期化
document.addEventListener('DOMContentLoaded', () => {
  new SetupWizard();
});
```

---

## テスト項目

### 初回セットアップフロー

| テストケース | 期待結果 |
|-------------|---------|
| 拡張機能インストール後、初回起動 | ウェルカム画面（ステップ1）が表示される |
| ステップ1で「次へ」をクリック | ステップ2（APIキー取得ガイド）が表示される |
| ステップ2で「Google AI Studio を開く」をクリック | 新しいタブでGoogle AI Studioが開く |
| ステップ2で「戻る」をクリック | ステップ1に戻る |
| ステップ2で「次へ」をクリック | ステップ3（APIキー入力）が表示される |

### APIキー入力フロー

| テストケース | 期待結果 |
|-------------|---------|
| 空のAPIキーで「保存して始める」をクリック | ボタンが無効（disabled）状態 |
| 「AIza」で始まらないテキストを入力 | エラーメッセージ「「AIza」で始まる必要があります」が表示 |
| 39文字未満のAPIキーを入力 | 警告メッセージ「○文字入力してください」が表示 |
| 有効なAPIキー形式を入力 | 成功メッセージ「✅ フォーマットが正しいです」が表示 |
| 有効なAPIキーで「保存して始める」をクリック | ローディング画面が表示され、検証が開始される |

### APIキー検証フロー

| テストケース | 期待結果 |
|-------------|---------|
| 有効なAPIキーを入力・保存 | 成功画面が表示され、2秒後にメイン画面へ遷移 |
| 無効なAPIキーを入力・保存 | エラー画面が表示され、エラーメッセージが表示される |
| クォータ超過のAPIキーを入力・保存 | 「APIのクォータを超過しています」というエラーが表示 |
| ネットワークが接続されていない状態で保存 | ネットワークエラーが表示される |

### APIキー管理フロー

| テストケース | 期待結果 |
|-------------|---------|
| 設定ページでAPIキーを確認 | マスク表示（AIza...xxxxxx）で表示される |
| 「APIキーを更新」をクリック | 確認ダイアログが表示される |
| 確認ダイアログで「更新する」をクリック | APIキー入力画面が表示される |
| 新しいAPIキーを入力・保存 | 成功メッセージが表示され、APIキーが更新される |
| 「APIキーを削除」をクリック | 警告ダイアログが表示される |
| 警告ダイアログで「削除する」をクリック | APIキーが削除され、初回セットアップ画面に戻る |

---

**ドキュメント終了**
