# 画面設計書 110-インボックス設定画面

## 概要

Captain AIアシスタントに接続されたインボックス（受信トレイ）を管理する画面設計書です。アシスタントがどのインボックスで動作するかを設定し、顧客からの初期問い合わせをAIが自動対応できるようにします。

### 本画面の処理概要

**業務上の目的・背景**：Captain AIアシスタントを実際の顧客対応に活用するためには、アシスタントをインボックス（受信トレイ）に接続する必要があります。インボックス設定画面では、アシスタントに紐づけるインボックスの追加・削除を管理します。これにより、特定のチャネル（Webサイト、WhatsApp、メールなど）からの問い合わせにAIアシスタントが自動応答できるようになります。

**画面へのアクセス方法**：Captain機能のサイドナビゲーションから「Inboxes」を選択してアクセスします。URLパスは `/app/accounts/:accountId/captain/:assistantId/inboxes` です。

**主要な操作・処理内容**：
1. 接続済みインボックス一覧の表示
2. 新規インボックスの接続
3. インボックスの接続解除（削除）

**画面遷移**：
- 遷移元：Captainアシスタント一覧画面、サイドナビゲーション
- 遷移先：なし（単独画面）

**権限による表示制御**：administrator および agent ロールがアクセス可能です。インボックスの接続・解除操作は administrator のみ可能です。CAPTAINフィーチャーフラグが有効で、CloudまたはEnterpriseインストールタイプの場合のみ利用可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 88 | インボックス関連 | 主機能 | インボックスの接続・解除管理 |

## 画面種別

一覧 / 設定

## URL/ルーティング

| パス | ルート名 |
|------|----------|
| `/app/accounts/:accountId/captain/:assistantId/inboxes` | `captain_assistants_inboxes_index` |

## 入出力項目

### 入力項目

| 項目名 | 物理名 | 型 | 必須 | バリデーション | 備考 |
|--------|--------|-----|------|---------------|------|
| インボックス | inboxId | number | Yes | 必須（required） | 接続するインボックスの選択 |

### 出力項目

| 項目名 | 物理名 | 型 | 備考 |
|--------|--------|-----|------|
| インボックス一覧 | captainInboxes | array | 接続済みインボックス |
| インボックスID | id | number | インボックスの識別子 |
| インボックス名 | name | string | インボックス名称 |
| チャネルタイプ | channel_type | string | Web, WhatsApp, Emailなど |
| 電話番号 | phone_number | string | Twilio/WhatsAppチャネル用 |
| メールアドレス | email | string | メールチャネル用 |

## 表示項目

### ヘッダー領域

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| タイトル | "Connected Inboxes" | セクションヘッダー |
| 追加ボタン | "Connect a new inbox" | administrator権限のみ表示 |

### インボックス一覧

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| インボックスカード | InboxCard | 各インボックスの情報表示 |
| インボックス名 | テキスト | チャネルタイプに応じた詳細情報付き |
| チャネルアイコン | アイコン | チャネルタイプに応じたアイコン |
| アクションメニュー | ドロップダウン | 接続解除オプション |

### 空状態

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| タイトル | "No Connected Inboxes" | 空状態時に表示 |
| 説明 | テキスト | インボックス接続の利点を説明 |
| 追加ボタン | ボタン | インボックス接続ダイアログを開く |

### 接続ダイアログ

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| タイトル | "Connect an Inbox" | ダイアログヘッダー |
| 説明 | テキスト | インボックス選択の説明 |
| インボックス選択 | ComboBox | 未接続のインボックスから選択 |
| キャンセルボタン | ボタン | ダイアログを閉じる |
| 作成ボタン | ボタン | インボックスを接続 |

### 削除確認ダイアログ

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| タイトル | "Are you sure to disconnect the inbox?" | 確認メッセージ |
| 確認ボタン | "Yes, delete" | 接続解除を実行 |
| キャンセルボタン | ボタン | キャンセル |

## イベント仕様

### 1-インボックス接続

1. 「Connect a new inbox」ボタンをクリック
2. `handleCreate()` が呼び出される
3. `dialogType` を 'create' に設定
4. `ConnectInboxDialog` が表示される
5. インボックスを選択して送信
6. `handleSubmit()` でVuelidate検証を実行
7. `captainInboxes/create` アクションをディスパッチ
8. 成功時：成功メッセージを表示、ダイアログを閉じる
9. 失敗時：エラーメッセージを表示

### 2-インボックス接続解除

1. インボックスカードのアクションメニューから「Disconnect」を選択
2. `handleAction({ action: 'delete', id })` が呼び出される
3. `selectedInbox` に対象インボックスを設定
4. `DeleteDialog` が表示される
5. 確認ボタンをクリック
6. `captainInboxes/delete` アクションをディスパッチ
7. 成功時：成功メッセージを表示、一覧から削除

### 3-アシスタント切り替え時のデータ取得

1. URLパラメータの `assistantId` が変更される
2. watchで変更を検知（52-60行目）
3. `captainInboxes/get` アクションをディスパッチ
4. 新しいアシスタントのインボックス一覧を取得

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| インボックス接続 | captain_assistant_inboxes | INSERT | インボックスとアシスタントの紐付け作成 |
| インボックス解除 | captain_assistant_inboxes | DELETE | インボックスとアシスタントの紐付け削除 |

### API仕様

#### インボックス一覧取得

| メソッド | エンドポイント | 備考 |
|---------|---------------|------|
| GET | `/api/v1/accounts/:accountId/captain/assistants/:assistantId/inboxes` | 接続済みインボックス一覧 |

#### インボックス接続

| メソッド | エンドポイント | 備考 |
|---------|---------------|------|
| POST | `/api/v1/accounts/:accountId/captain/assistants/:assistantId/inboxes` | インボックス接続 |

##### リクエストボディ

```json
{
  "inbox": {
    "inbox_id": 123
  }
}
```

#### インボックス接続解除

| メソッド | エンドポイント | 備考 |
|---------|---------------|------|
| DELETE | `/api/v1/accounts/:accountId/captain/assistants/:assistantId/inboxes/:inboxId` | インボックス解除 |

## メッセージ仕様

| 種別 | メッセージキー | メッセージ内容 |
|------|---------------|---------------|
| ヘッダー | CAPTAIN.INBOXES.HEADER | "Connected Inboxes" |
| ボタン | CAPTAIN.INBOXES.ADD_NEW | "Connect a new inbox" |
| 空状態タイトル | CAPTAIN.INBOXES.EMPTY_STATE.TITLE | "No Connected Inboxes" |
| 空状態説明 | CAPTAIN.INBOXES.EMPTY_STATE.SUBTITLE | インボックス接続の利点説明 |
| ダイアログタイトル | CAPTAIN.INBOXES.CREATE.TITLE | "Connect an Inbox" |
| ダイアログ説明 | CAPTAIN.INBOXES.FORM_DESCRIPTION | "Choose an inbox to connect with the assistant." |
| 成功メッセージ | CAPTAIN.INBOXES.CREATE.SUCCESS_MESSAGE | "The inbox was successfully connected." |
| エラーメッセージ | CAPTAIN.INBOXES.CREATE.ERROR_MESSAGE | "An error occurred while connecting the inbox. Please try again." |
| 解除オプション | CAPTAIN.INBOXES.OPTIONS.DISCONNECT | "Disconnect" |
| 削除確認タイトル | CAPTAIN.INBOXES.DELETE.TITLE | "Are you sure to disconnect the inbox?" |
| 削除成功 | CAPTAIN.INBOXES.DELETE.SUCCESS_MESSAGE | "The inbox was successfully disconnected." |
| 削除エラー | CAPTAIN.INBOXES.DELETE.ERROR_MESSAGE | "There was an error disconnecting the inbox, please try again." |
| フォームラベル | CAPTAIN.INBOXES.FORM.INBOX.LABEL | "Inbox" |
| フォームプレースホルダー | CAPTAIN.INBOXES.FORM.INBOX.PLACEHOLDER | "Choose the inbox to deploy the assistant." |
| フォームエラー | CAPTAIN.INBOXES.FORM.INBOX.ERROR | "An inbox selection is required." |

## 例外処理

| 例外条件 | 処理内容 | 表示 |
|----------|----------|------|
| インボックス接続エラー | エラーメッセージをアラート表示 | CREATE.ERROR_MESSAGE |
| インボックス解除エラー | エラーメッセージをアラート表示 | DELETE.ERROR_MESSAGE |
| 必須項目未入力 | バリデーションエラー表示 | FORM.INBOX.ERROR |
| データ取得中 | ローディング表示 | ローディングインジケータ |

## 備考

- インボックスリストは既存のインボックスストア（`inboxes/getInboxes`）から取得
- 既に接続済みのインボックスはComboBoxの選択肢から除外される
- インボックス名の表示はチャネルタイプに応じて詳細情報を付加
  - Twilio/WhatsApp: 電話番号を括弧で表示
  - Email: メールアドレスを括弧で表示
- チャネルアイコンは `getInboxIconByType` ヘルパー関数で動的に決定
- 接続・解除操作は administrator 権限が必要

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、インボックスデータの構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | inboxes.js (store) | `app/javascript/dashboard/store/captain/inboxes.js` | createStoreファクトリを使用したストア構造を確認 |
| 1-2 | inboxes.js (api) | `app/javascript/dashboard/api/captain/inboxes.js` | APIクライアントのエンドポイント構造を確認 |

**読解のコツ**: ストアは`createStore`ファクトリパターンを使用しており、カスタムのdeleteアクションのみを定義しています。

#### Step 2: エントリーポイントを理解する

処理の起点となるVueコンポーネントを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Index.vue (inboxes) | `app/javascript/dashboard/routes/dashboard/captain/assistants/inboxes/Index.vue` | ページの全体構造を確認 |

**主要処理フロー（Index.vue）**:
1. **13-26行目**: ストア、ルート、ref変数の初期化
2. **28-30行目**: `handleDelete()` で削除ダイアログを開く
3. **34-37行目**: `handleCreate()` で接続ダイアログを開く
4. **38-45行目**: `handleAction()` でアクションを振り分け
5. **52-60行目**: watchでassistantId変更時にデータ再取得

#### Step 3: コンポーネント構造を理解する

各子コンポーネントの役割を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | InboxCard.vue | `app/javascript/dashboard/components-next/captain/assistant/InboxCard.vue` | インボックス表示コンポーネント |
| 3-2 | ConnectInboxDialog.vue | `app/javascript/dashboard/components-next/captain/pageComponents/inbox/ConnectInboxDialog.vue` | 接続ダイアログ |
| 3-3 | ConnectInboxForm.vue | `app/javascript/dashboard/components-next/captain/pageComponents/inbox/ConnectInboxForm.vue` | 接続フォーム |

**InboxCard.vue主要処理**:
- **29-49行目**: `inboxName` computedでチャネルタイプに応じた名前表示
- **51-58行目**: `menuItems` でアクションメニュー定義
- **60-63行目**: `icon` computedでチャネルアイコン取得

**ConnectInboxForm.vue主要処理**:
- **38-47行目**: `inboxList` computedで未接続インボックスをフィルタリング
- **70-77行目**: `handleSubmit()` でVuelidate検証と送信

#### Step 4: API通信を理解する

APIクライアントの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | inboxes.js (api) | `app/javascript/dashboard/api/captain/inboxes.js` | CRUD操作のエンドポイント |

**主要処理フロー**:
- **9-11行目**: `get()` でアシスタントのインボックス一覧取得
- **13-18行目**: `create()` でインボックス接続
- **20-23行目**: `delete()` でインボックス解除

### プログラム呼び出し階層図

```
Index.vue (inboxes)
    |
    +-- PageLayout.vue
    |       |
    |       +-- header-title: "Connected Inboxes"
    |       +-- button-label: "Connect a new inbox"
    |       +-- button-policy: ['administrator']
    |       +-- is-fetching: ローディング状態
    |       +-- is-empty: インボックス空判定
    |
    +-- InboxPageEmptyState.vue (空状態時)
    |       |
    |       +-- @click -> handleCreate()
    |
    +-- InboxCard.vue (v-for)
    |       |
    |       +-- inbox: インボックスデータ
    |       +-- @action -> handleAction()
    |               |
    |               +-- 'delete' -> handleDelete()
    |                       |
    |                       +-- disconnectInboxDialog.open()
    |
    +-- ConnectInboxDialog.vue
    |       |
    |       +-- Dialog.vue
    |       |       |
    |       |       +-- title: "Connect an Inbox"
    |       |
    |       +-- ConnectInboxForm.vue
    |               |
    |               +-- ComboBox (インボックス選択)
    |               |       |
    |               |       +-- inboxList (未接続のみフィルタ)
    |               |
    |               +-- @submit -> handleSubmit()
    |                       |
    |                       +-- captainInboxes/create
    |
    +-- DeleteDialog.vue
            |
            +-- type: "Inboxes"
            +-- delete-payload: { assistantId, inboxId }
                    |
                    +-- captainInboxes/delete
```

### データフロー図

```
[入力]                    [処理]                           [出力]

画面初期表示 ─────────▶ watch(assistantId)
                              │
                              ▼
                        captainInboxes/get
                              │
                              ▼
                        GET /api/v1/.../captain/assistants/:id/inboxes
                              │
                              ▼
                        captainInboxes に格納
                              │
                              ▼
                        InboxCard で描画 ──────────▶ インボックス一覧表示

インボックス接続 ────▶ handleCreate()
                              │
                              ▼
                        ConnectInboxDialog表示
                              │
                              ▼
                        インボックス選択
                              │
                              ▼
                        Vuelidate検証
                              │
                              ▼
                        captainInboxes/create
                              │
                              ▼
                        POST /api/v1/.../captain/assistants/:id/inboxes
                              │
                              ├── 成功 → 成功メッセージ表示
                              │           一覧更新
                              │
                              └── 失敗 → エラーメッセージ表示

インボックス解除 ────▶ handleAction({ action: 'delete' })
                              │
                              ▼
                        selectedInbox設定
                              │
                              ▼
                        DeleteDialog表示
                              │
                              ▼
                        確認
                              │
                              ▼
                        captainInboxes/delete
                              │
                              ▼
                        DELETE /api/v1/.../captain/assistants/:id/inboxes/:inboxId
                              │
                              ├── 成功 → 一覧から削除
                              │
                              └── 失敗 → エラーメッセージ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Index.vue | `app/javascript/dashboard/routes/dashboard/captain/assistants/inboxes/Index.vue` | ソース | ページコンポーネント |
| captain.routes.js | `app/javascript/dashboard/routes/dashboard/captain/captain.routes.js` | 設定 | ルーティング定義 |
| inboxes.js (store) | `app/javascript/dashboard/store/captain/inboxes.js` | ソース | Vuexストア |
| inboxes.js (api) | `app/javascript/dashboard/api/captain/inboxes.js` | ソース | APIクライアント |
| InboxCard.vue | `app/javascript/dashboard/components-next/captain/assistant/InboxCard.vue` | ソース | インボックスカード |
| ConnectInboxDialog.vue | `app/javascript/dashboard/components-next/captain/pageComponents/inbox/ConnectInboxDialog.vue` | ソース | 接続ダイアログ |
| ConnectInboxForm.vue | `app/javascript/dashboard/components-next/captain/pageComponents/inbox/ConnectInboxForm.vue` | ソース | 接続フォーム |
| DeleteDialog.vue | `app/javascript/dashboard/components-next/captain/pageComponents/DeleteDialog.vue` | ソース | 削除確認ダイアログ |
| InboxPageEmptyState.vue | `app/javascript/dashboard/components-next/captain/pageComponents/emptyStates/InboxPageEmptyState.vue` | ソース | 空状態表示 |
| PageLayout.vue | `app/javascript/dashboard/components-next/captain/PageLayout.vue` | ソース | ページレイアウト |
| integrations.json | `app/javascript/dashboard/i18n/locale/en/integrations.json` | 設定 | i18nメッセージ定義 |
