# 機能設計書 180-インボックスアシスタント

## 概要

本ドキュメントは、Chatwootにおけるインボックスアシスタント機能の設計仕様を定義する。この機能は、会話に関連付けられたインボックスのCaptain AIアシスタント情報を取得するためのAPIを提供する。これはEnterprise機能である。

### 本機能の処理概要

**業務上の目的・背景**：
Chatwoot EnterpriseではCaptain AIアシスタント機能が提供されており、インボックス毎に専用のAIアシスタントを配置できる。フロントエンドでは会話画面においてCopilotパネルを表示し、AIアシスタントによる自動応答や提案機能を利用するために、現在の会話に関連付けられたアシスタント情報を取得する必要がある。

**機能の利用シーン**：
- エージェントが会話を開いた際に、その会話のインボックスに設定されたAIアシスタント情報を取得する場合
- Copilotパネルでアシスタントの名前やIDを表示する場合
- AIアシスタントが設定されているかどうかを確認する場合

**主要な処理内容**：
1. 会話の取得と認可確認
2. 会話のインボックスからCaptainアシスタントを取得
3. アシスタント情報（存在する場合）またはnullを返却

**関連システム・外部連携**：
- Captain AI: Chatwoot Enterprise AIアシスタント機能
- CaptainInbox: インボックスとアシスタントの関連

**権限による制御**：
認証済みユーザーで、会話のshowアクション権限を持つユーザーのみがアクセス可能。Enterprise機能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 会話詳細画面 | 主画面 | AIアシスタント情報の表示 |

## 機能種別

データ取得 / AI連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | 会話のdisplay_id | 存在する会話であること |

### 入力データソース

- URLパラメータからの会話ID
- 認証トークンからのユーザー識別

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| assistant | Object/null | アシスタント情報（設定されている場合） |
| assistant.id | Integer | アシスタントID |
| assistant.name | String | アシスタント名 |

### 出力先

- JSON形式でHTTPレスポンスとして返却

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GET /api/v1/accounts/:account_id/conversations/:id/inbox_assistant
2. 認証・認可検証
   └─ 会話のshow権限確認
3. 会話取得
   └─ display_idで会話を検索
4. インボックスのアシスタント取得
   └─ conversation.inbox.captain_assistant
5. レスポンス生成
   └─ アシスタント情報またはnullを返却
```

### フローチャート

```mermaid
flowchart TD
    A[GET /api/v1/accounts/:account_id/conversations/:id/inbox_assistant] --> B{認証済み?}
    B -->|No| C[401 Unauthorized]
    B -->|Yes| D[会話取得]
    D --> E{会話存在?}
    E -->|No| F[404 Not Found]
    E -->|Yes| G{show権限あり?}
    G -->|No| H[403 Forbidden]
    G -->|Yes| I[captain_assistant取得]
    I --> J{アシスタント存在?}
    J -->|Yes| K[アシスタント情報返却]
    J -->|No| L[null返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-180-01 | Enterprise機能 | この機能はEnterprise版でのみ利用可能 | 常時 |
| BR-180-02 | インボックス経由取得 | アシスタントは会話のインボックスを経由して取得 | 常時 |
| BR-180-03 | null許容 | アシスタントが設定されていない場合はnullを返却 | アシスタント未設定時 |

### 計算ロジック

特になし

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 会話取得 | conversations | SELECT | display_idで会話を検索 |
| インボックス取得 | inboxes | SELECT | 会話に関連するインボックス |
| CaptainInbox取得 | captain_inboxes | SELECT | インボックスに関連するCaptainInbox |
| アシスタント取得 | captain_assistants | SELECT | CaptainInboxに関連するアシスタント |

### テーブル別操作詳細

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | display_id = params[:id] AND account_id = current_account.id | 会話取得 |

#### captain_inboxes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | inbox_id = conversation.inbox_id | CaptainInbox取得 |

#### captain_assistants

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name | id = captain_inbox.captain_assistant_id | アシスタント情報取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証トークンが無効 | 再ログイン |
| 403 | Forbidden | 会話のshow権限がない | 適切な権限を持つユーザーでアクセス |
| 404 | Not Found | 指定された会話が存在しない | 正しい会話IDを指定 |

### リトライ仕様

特になし

## トランザクション仕様

読み取り専用のため、トランザクションは使用しない。

## パフォーマンス要件

- レスポンス時間: 200ms以内

## セキュリティ考慮事項

- 会話のshow権限による認可確認
- Enterprise機能としてのライセンス確認

## 備考

- この機能はEnterprise版でのみ利用可能
- CaptainInboxが存在しない場合はassistant: nullを返却
- アシスタント情報はidとnameのみを返却（詳細情報は別APIで取得）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | captain_inbox.rb | `enterprise/app/models/captain_inbox.rb` | CaptainInboxモデル、インボックスとアシスタントの関連 |
| 1-2 | enterprise/concerns/inbox.rb | `enterprise/app/models/enterprise/concerns/inbox.rb` | captain_assistant関連の定義 |
| 1-3 | assistant.rb | `enterprise/app/models/captain/assistant.rb` | Captain::Assistantモデル |

**読解のコツ**: Inboxモデルはenterprise/concerns/inboxで拡張され、`has_one :captain_assistant, through: :captain_inbox`が定義されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | conversations_controller.rb | `enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb` | inbox_assistantアクションの実装 |

**主要処理フロー**:
1. **4-12行目**: `inbox_assistant`アクション
2. **5行目**: `@conversation.inbox.captain_assistant` - インボックス経由でアシスタントを取得
3. **7-8行目**: アシスタントが存在する場合、idとnameを返却
4. **10行目**: アシスタントが存在しない場合、nullを返却

#### Step 3: ルーティングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | routes.rb | `config/routes.rb` | inbox_assistantルートの定義 |

**主要処理フロー**:
- **155行目**: `get :inbox_assistant` - conversationsリソースのmemberルート

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

```
Api::V1::Accounts::ConversationsController
    │ (prepend_mod_with Enterprise::...)
    │
    └─ Enterprise::Api::V1::Accounts::ConversationsController#inbox_assistant
           │
           ├─ @conversation (from before_action)
           │      └─ Current.account.conversations.find_by!(display_id: params[:id])
           │
           └─ @conversation.inbox.captain_assistant
                  │
                  ├─ Inbox (belongs_to)
                  │
                  └─ has_one :captain_assistant, through: :captain_inbox
                         │
                         ├─ CaptainInbox (has_one)
                         │      └─ captain_inboxes WHERE inbox_id = inbox.id
                         │
                         └─ Captain::Assistant (belongs_to)
                                └─ captain_assistants WHERE id = captain_inbox.captain_assistant_id
```

### データフロー図

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

GET リクエスト ───────▶ ConversationsController#inbox_assistant ───────▶ JSON Response
(conversation_id)         │                                              {assistant: {id, name}}
                          │                                              または
                          │                                              {assistant: null}
                          ▼
                    @conversation
                          │
                          ├─▶ inbox (belongs_to)
                          │
                          └─▶ inbox.captain_assistant
                                 │
                                 ├─▶ captain_inboxes (through)
                                 │
                                 └─▶ captain_assistants
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| conversations_controller.rb | `enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb` | コントローラー | inbox_assistantアクションの定義（4-12行目） |
| conversations_controller.rb | `app/controllers/api/v1/accounts/conversations_controller.rb` | コントローラー | 基底コントローラー、prepend_mod_withで拡張 |
| inbox.rb | `app/models/inbox.rb` | モデル | Inboxモデル基底 |
| enterprise/concerns/inbox.rb | `enterprise/app/models/enterprise/concerns/inbox.rb` | concern | captain_assistant関連定義（5-8行目） |
| enterprise/inbox.rb | `enterprise/app/models/enterprise/inbox.rb` | モジュール | captain_active?メソッド |
| captain_inbox.rb | `enterprise/app/models/captain_inbox.rb` | モデル | CaptainInboxモデル |
| assistant.rb | `enterprise/app/models/captain/assistant.rb` | モデル | Captain::Assistantモデル |
| conversation.js | `app/javascript/dashboard/api/inbox/conversation.js` | API | フロントエンドAPIクライアント（136-138行目） |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（155行目） |
