# 機能設計書 88-インボックス関連

## 概要

本ドキュメントは、Chatwoot Captain AIアシスタントとインボックスの関連付け機能の設計を記載する。AIアシスタントを特定のインボックスに配置して自動応答を行わせるためのEnterprise機能である。

### 本機能の処理概要

インボックス関連機能は、AIアシスタントを1つ以上のインボックスに配置し、そのインボックスで受信した会話に対してAIが自動応答できるようにする機能である。

**業務上の目的・背景**：AIアシスタントは特定のインボックス（チャネル）に配置することで機能する。例えば、WebサイトのチャットウィジェットにAIアシスタントを配置して24時間対応を実現したり、特定のサポートチャネルにのみAIを配置するといった柔軟な運用が可能になる。

**機能の利用シーン**：
- 管理者がアシスタントを特定のインボックスに配置する際
- アシスタントに紐付くインボックス一覧を確認する際
- インボックスからアシスタントを削除する際

**主要な処理内容**：
1. アシスタントに紐付くインボックス一覧の取得
2. アシスタントとインボックスの関連付け作成
3. アシスタントとインボックスの関連付け削除

**関連システム・外部連携**：Inbox、Captain Assistantとの連携。

**権限による制御**：Captain::Assistantポリシーによる権限制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 110 | インボックス設定画面 | 主画面 | アシスタントのインボックス設定 |

## 機能種別

関連付け管理（Create/Delete）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| assistant_id | Integer | Yes | アシスタントID | 存在するアシスタント |
| inbox_id | Integer | Yes | インボックスID | 存在するインボックス |

### 入力データソース

- 管理画面からのAPI呼び出し

## 出力仕様

### 出力データ（インボックス一覧）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| inboxes | Array | 紐付いたインボックス一覧 |
| inboxes[].id | BigInt | インボックスID |
| inboxes[].name | String | インボックス名 |
| inboxes[].channel_type | String | チャネルタイプ |

### 出力データ（関連付け作成）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | CaptainInboxレコードID |
| captain_assistant_id | BigInt | アシスタントID |
| inbox_id | BigInt | インボックスID |

### 出力先

- JSON APIレスポンス

## 処理フロー

### 処理シーケンス

```
1. インボックス一覧取得（index）
   └─ アシスタントに紐付くインボックスを取得
2. 関連付け作成（create）
   └─ インボックスIDの検証
   └─ captain_inboxesテーブルにINSERT
3. 関連付け削除（destroy）
   └─ CaptainInboxレコードを検索
   └─ レコード削除
```

### フローチャート

```mermaid
flowchart TD
    A[インボックス設定画面] --> B[GET /captain/assistants/:assistant_id/inboxes]
    B --> C[InboxesController#index]
    C --> D[@assistant.inboxes取得]
    D --> E[JSON応答]

    F[インボックス追加] --> G[POST /captain/assistants/:assistant_id/inboxes]
    G --> H[InboxesController#create]
    H --> I{権限チェック}
    I -->|OK| J[インボックス存在確認]
    I -->|NG| K[403 Forbidden]
    J --> L[CaptainInbox.build]
    L --> M{一意性チェック}
    M -->|重複| N[422 Error]
    M -->|OK| O[captain_inbox.save!]
    O --> P[JSON応答]

    Q[インボックス削除] --> R[DELETE /captain/assistants/:assistant_id/inboxes/:inbox_id]
    R --> S[InboxesController#destroy]
    S --> T[find_by!(inbox_id:)]
    T --> U[captain_inbox.destroy!]
    U --> V[204 No Content]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-88-01 | インボックス一意性 | 1つのインボックスには1つのアシスタントのみ | 関連付け作成時 |
| BR-88-02 | アカウント境界 | アシスタントとインボックスは同一アカウント | 関連付け作成時 |
| BR-88-03 | アシスタント存在確認 | 指定アシスタントが存在すること | 全操作 |
| BR-88-04 | インボックス存在確認 | 指定インボックスがアカウント内に存在すること | 関連付け作成時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | captain_inboxes, inboxes | SELECT | 関連インボックス取得 |
| 作成 | captain_inboxes | INSERT | 関連付けレコード作成 |
| 削除 | captain_inboxes | DELETE | 関連付けレコード削除 |

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

#### captain_inboxes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | captain_assistant_id | アシスタントID | 関連取得 |
| INSERT | captain_assistant_id | パスパラメータ | 必須 |
| INSERT | inbox_id | リクエストボディ | 必須、一意 |
| DELETE | captain_assistant_id, inbox_id | 削除条件 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 権限がない | 管理者に連絡 |
| 404 | NotFound | アシスタント/インボックスが存在しない | IDを確認 |
| 422 | ValidationError | インボックス重複 | 別のインボックスを選択 |

### リトライ仕様

該当なし

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

単一レコード操作のため、暗黙的トランザクション

## パフォーマンス要件

- インボックス一覧取得はthrough関連で効率的に取得

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

- Captain::Assistantポリシーによる権限制御
- アカウント境界による分離

## 備考

- Enterprise版機能
- 1インボックス=1アシスタントの制約（inbox_id一意性）
- アシスタント削除時は関連レコードも非同期削除

---

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

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

### 推奨読解順序

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

まず、CaptainInbox（中間テーブル）のデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | captain_inbox.rb | `enterprise/app/models/captain_inbox.rb` | 中間テーブル定義 |

**読解のコツ**:
- **17-19行目**: belongs_to関連（captain_assistant, inbox）
- **21行目**: inbox_idの一意性バリデーション（1インボックス=1アシスタント）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inboxes_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/inboxes_controller.rb` | CRUD操作 |

**主要処理フロー**:
- **6-8行目**: indexで@assistant.inboxes取得（through関連）
- **10-14行目**: createでCaptainInbox作成
- **16-20行目**: destroyでfind_by!(inbox_id:)検索と削除

#### Step 3: アシスタント側の関連を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | assistant.rb | `enterprise/app/models/captain/assistant.rb` | has_many関連 |

**主要処理フロー**:
- **29-32行目**: has_many :captain_inboxes（dependent: :destroy_async）
- **33-34行目**: has_many :inboxes, through: :captain_inboxes

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

```
InboxesController
    │
    ├─ index
    │      └─ @assistant.inboxes
    │              └─ through: captain_inboxes
    │
    ├─ create
    │      ├─ Current.account.inboxes.find(inbox_id)
    │      │
    │      └─ @assistant.captain_inboxes.build(inbox:)
    │              └─ save!
    │                     └─ validates inbox_id uniqueness
    │
    └─ destroy
           └─ @assistant.captain_inboxes.find_by!(inbox_id:)
                  └─ destroy!

Captain::Assistant (削除時)
    │
    └─ destroy
           └─ dependent: :destroy_async
                  └─ captain_inboxes削除
```

### データフロー図

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

assistant_id ───▶ InboxesController ───▶ @assistant.inboxes
inbox_id                │
                        ├─ インボックス検証
                        │
                        └─ CaptainInbox操作

Captain::Assistant
        │
        └─ has_many :inboxes ───▶ [Inbox, Inbox, ...]
               through: captain_inboxes
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inboxes_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/inboxes_controller.rb` | コントローラー | CRUD API |
| captain_inbox.rb | `enterprise/app/models/captain_inbox.rb` | モデル | 中間テーブル |
| assistant.rb | `enterprise/app/models/captain/assistant.rb` | モデル | has_many関連定義 |
| inbox.rb | `app/models/inbox.rb` | モデル | インボックスモデル |
