# 機能設計書 17-インボックス基本管理

## 概要

本ドキュメントは、Chatwootのインボックス基本管理機能について、その処理内容、データベース操作、およびコード構成を詳細に記述した設計書である。

### 本機能の処理概要

インボックス基本管理機能は、Chatwootの中核となるインボックス（受信トレイ）の作成・編集・削除・表示を行う機能である。インボックスは会話を受信・処理するためのチャネルの論理的なコンテナであり、各種コミュニケーションチャネル（Web Widget, Email, SMS, WhatsApp等）と紐付けられる。

**業務上の目的・背景**：カスタマーサポート業務では、複数のコミュニケーションチャネル（Webサイト、メール、SNS等）からの問い合わせを一元管理する必要がある。インボックスを作成することで、各チャネルからの会話を統合的に管理し、エージェントの割り当て、ボットの配置、営業時間設定などをチャネルごとに設定できる。

**機能の利用シーン**：
- 新しいコミュニケーションチャネルの追加（Web Widget, Email等）
- 既存インボックスの設定変更（名前、営業時間、自動割り当て等）
- 不要になったインボックスの削除
- インボックス一覧の確認

**主要な処理内容**：
1. インボックスのCRUD操作（作成・読取・更新・削除）
2. 各種チャネルタイプに応じたチャネルオブジェクトの作成
3. インボックス設定（営業時間、自動割り当て、グリーティング等）の管理
4. エージェントボットの割り当て設定
5. インボックスアバターの管理
6. テンプレート同期（WhatsApp等）

**関連システム・外部連携**：
- 各種チャネルAPI（Facebook, WhatsApp, Telegram等）
- ActiveStorage（アバター画像管理）
- Redis（ラウンドロビンキュー）

**権限による制御**：
- インボックスの作成・編集・削除はAdministratorロールのみ
- インボックスの閲覧は割り当てられたエージェントのみ

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 47 | インボックス一覧画面 | 主画面 | インボックスの一覧表示 |
| 48 | インボックス新規作成画面 | 主画面 | 新しいインボックスのチャネル選択 |
| 50 | インボックス設定画面 | 主画面 | 既存インボックスの詳細設定 |
| 52 | インボックス設定完了 | 参照画面 | インボックス設定の完了確認 |
| 10 | インボックス別会話一覧 | 参照画面 | 特定インボックスの会話一覧 |

## 機能種別

CRUD操作 / 設定管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | インボックス名 | presence |
| channel | Object | Yes（作成時） | チャネル設定オブジェクト | チャネルタイプ別バリデーション |
| greeting_enabled | Boolean | No | グリーティング有効フラグ | - |
| greeting_message | String | No | グリーティングメッセージ | max: GREETING_MESSAGE_MAX_LENGTH |
| enable_auto_assignment | Boolean | No | 自動割り当て有効フラグ（デフォルト: true） | - |
| working_hours_enabled | Boolean | No | 営業時間有効フラグ | - |
| out_of_office_message | String | No | 営業時間外メッセージ | max: OUT_OF_OFFICE_MESSAGE_MAX_LENGTH |
| timezone | String | No | タイムゾーン（デフォルト: UTC） | TZInfo有効値 |
| csat_survey_enabled | Boolean | No | CSAT有効フラグ | - |
| allow_messages_after_resolved | Boolean | No | 解決後メッセージ許可（デフォルト: true） | - |
| lock_to_single_conversation | Boolean | No | 単一会話ロック | - |
| portal_id | Integer | No | 紐付けるポータルID | 存在確認 |
| sender_name_type | Integer | No | 送信者名タイプ（friendly: 0, professional: 1） | enum値 |
| business_name | String | No | ビジネス名 | - |
| avatar | File | No | アバター画像 | 画像形式 |

### 入力データソース

- 画面入力（インボックス管理画面からの操作）
- API経由（REST API）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | インボックスID |
| name | String | インボックス名 |
| channel_type | String | チャネルタイプ |
| channel_id | Integer | チャネルID |
| greeting_enabled | Boolean | グリーティング有効フラグ |
| greeting_message | String | グリーティングメッセージ |
| enable_auto_assignment | Boolean | 自動割り当て有効フラグ |
| working_hours_enabled | Boolean | 営業時間有効フラグ |
| out_of_office_message | String | 営業時間外メッセージ |
| timezone | String | タイムゾーン |
| avatar_url | String | アバター画像URL |
| working_hours | Array | 営業時間設定 |

### 出力先

- APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ InboxesController経由でインボックス操作リクエスト受信

2. 認可チェック
   └─ InboxPolicyで操作者の権限を確認

3. インボックス操作実行
   ├─ Index: 許可されたインボックス一覧取得
   ├─ Show: 指定インボックスの詳細取得
   ├─ Create: チャネル作成 → インボックス作成（トランザクション）
   ├─ Update: インボックス設定更新 → 営業時間更新 → チャネル更新
   └─ Destroy: 非同期削除ジョブ投入

4. コールバック処理
   ├─ 作成時: デフォルト営業時間作成、イベントディスパッチ
   └─ 削除時: ラウンドロビンキュークリア

5. レスポンス返却
   └─ 操作結果をJSON形式で返却
```

### フローチャート

```mermaid
flowchart TD
    A[インボックス操作リクエスト] --> B{認可チェック}
    B -->|Administrator| C{操作種別}
    B -->|Agent| D{show操作?}
    D -->|Yes| E{割り当て済み?}
    E -->|Yes| F[インボックス情報取得]
    E -->|No| G[403エラー]
    D -->|No| G
    C -->|Index| H[policy_scope適用]
    C -->|Create| I[チャネル作成]
    C -->|Update| J[設定更新]
    C -->|Destroy| K[削除ジョブ投入]
    I --> L[インボックス作成]
    L --> M[デフォルト営業時間作成]
    J --> N[営業時間更新]
    N --> O[チャネル更新]
    H --> P[レスポンス返却]
    F --> P
    M --> P
    O --> P
    K --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | デフォルト自動割り当て | enable_auto_assignmentのデフォルト値はtrue | インボックス作成時 |
| BR-002 | デフォルトタイムゾーン | timezoneのデフォルト値はUTC | インボックス作成時 |
| BR-003 | 許可チャネルタイプ | 作成可能なチャネルタイプは web_widget, api, email, line, telegram, whatsapp, sms | インボックス作成時 |
| BR-004 | 営業時間自動作成 | インボックス作成時にデフォルト営業時間（月-金 9:00-17:00）が自動作成 | インボックス作成時 |
| BR-005 | 非同期削除 | インボックス削除は非同期ジョブで実行 | インボックス削除時 |
| BR-006 | ラウンドロビンクリア | インボックス削除時にラウンドロビンキューをクリア | インボックス削除時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| インボックス一覧取得 | inboxes | SELECT | アカウント内インボックス一覧取得 |
| インボックス作成 | inboxes | INSERT | 新規インボックスレコード作成 |
| インボックス作成 | channel_* | INSERT | チャネル別テーブルにレコード作成 |
| インボックス作成 | working_hours | INSERT | デフォルト営業時間作成（7レコード） |
| インボックス更新 | inboxes | UPDATE | インボックス設定更新 |
| インボックス更新 | working_hours | UPDATE | 営業時間更新 |
| インボックス削除 | inboxes | DELETE | インボックスレコード削除 |

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

#### inboxes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | リクエストパラメータ | 必須 |
| INSERT | channel_type | チャネルクラス名 | 自動設定 |
| INSERT | channel_id | 作成されたチャネルID | 自動設定 |
| INSERT | account_id | Current.account.id | 自動設定 |
| SELECT | * | account_id条件 | policy_scope適用 |
| UPDATE | * | リクエストパラメータ | 各属性 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 操作権限がない | 権限確認メッセージ表示 |
| 404 | NotFound | 指定インボックスが存在しない | 対象確認メッセージ表示 |
| 422 | UnprocessableEntity | バリデーションエラー | エラー内容を表示 |
| 500 | InternalServerError | チャネル作成失敗 | エラーログ確認 |

### リトライ仕様

DeleteObjectJobは Sidekiq のデフォルトリトライポリシーに従う。

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

- インボックス作成時、チャネル作成とインボックス作成はActiveRecord::Base.transactionでラップ
- 営業時間更新はupdate_working_hours内でトランザクション管理

## パフォーマンス要件

- インボックス一覧取得: 100ms以内のレスポンス
- インデックス（account_id）、（channel_id, channel_type）による高速検索

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

- InboxPolicyによる認可制御
- policy_scopeによる閲覧可能インボックスの制限
- チャネル認証情報の暗号化保存

## 備考

- Inbox.prepend_mod_with('Inbox') によりEnterprise拡張が適用される
- 各チャネルタイプ固有の設定はチャネルモデル（Channel::*）で管理

---

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

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

### 推奨読解順序

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

Inboxモデルのスキーマとアソシエーションを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | inbox.rb | `app/models/inbox.rb` | スキーマ、アソシエーション、バリデーション、Concern |

**読解のコツ**:
- `belongs_to :channel, polymorphic: true` でポリモーフィック関連を確認
- `include OutOfOffisable` で営業時間機能を確認
- `include Avatarable` でアバター管理を確認
- 各種ヘルパーメソッド（`web_widget?`, `email?`等）でチャネルタイプ判定を確認

**主要処理フロー**:
1. **1-41行目**: スキーマ情報
2. **42-48行目**: Concern インクルード
3. **50-55行目**: バリデーション
4. **57-76行目**: アソシエーション
5. **90-101行目**: add_members / remove_members メソッド
6. **113-159行目**: チャネルタイプ判定メソッド

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

コントローラでのインボックス操作の入り口を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inboxes_controller.rb | `app/controllers/api/v1/accounts/inboxes_controller.rb` | インボックスCRUD API |

**主要処理フロー**:
1. **10-12行目**: index - policy_scope適用でインボックス一覧取得
2. **30-43行目**: create - トランザクション内でチャネル作成→インボックス作成
3. **45-51行目**: update - 設定更新→営業時間更新→チャネル更新
4. **68-71行目**: destroy - DeleteObjectJob投入
5. **107-111行目**: create_channel - チャネルオブジェクト作成
6. **117-119行目**: update_inbox_working_hours - 営業時間更新

#### Step 3: 認可ポリシーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | inbox_policy.rb | `app/policies/inbox_policy.rb` | インボックス操作の認可ルール |

**主要処理フロー**:
1. **3-16行目**: Scopeクラス - 割り当てられたインボックスのみ返す
2. **22-27行目**: show? - 割り当て済みインボックスのみ閲覧可能
3. **41-43行目**: create? - Administratorのみ

#### Step 4: 営業時間機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | out_of_offisable.rb | `app/models/concerns/out_of_offisable.rb` | 営業時間Concern |

**主要処理フロー**:
1. **9行目**: `has_many :working_hours`
2. **10行目**: `after_create :create_default_working_hours`
3. **34-40行目**: update_working_hours - 営業時間一括更新
4. **44-52行目**: create_default_working_hours - デフォルト営業時間作成

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

```
Api::V1::Accounts::InboxesController
    │
    ├─ InboxPolicy (認可チェック)
    │      ├─ Scope.resolve → user.assigned_inboxes
    │      └─ show?, create?, update?, destroy?
    │
    └─ Inbox (モデル操作)
           ├─ belongs_to :channel (polymorphic)
           │      └─ Channel::WebWidget / Email / Whatsapp / etc.
           │
           ├─ include OutOfOffisable
           │      ├─ has_many :working_hours
           │      ├─ create_default_working_hours (after_create)
           │      └─ update_working_hours
           │
           ├─ include Avatarable
           │
           └─ after_destroy :delete_round_robin_agents
                  └─ InboxRoundRobinService.clear_queue
```

### データフロー図

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

APIリクエスト ────────▶ InboxesController ────────────▶ JSONレスポンス
(name, channel, etc.)          │
                               ▼
                         InboxPolicy
                        (認可チェック)
                               │
                               ▼
                      ActiveRecord::Base.transaction
                               │
                               ├───▶ create_channel
                               │        └───▶ channel_* テーブル
                               │
                               └───▶ Inbox.create
                                        │
                                        ├───▶ inboxes テーブル
                                        │
                                        └───▶ OutOfOffisable
                                                 └───▶ working_hours テーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inbox.rb | `app/models/inbox.rb` | モデル | インボックスデータモデル |
| inboxes_controller.rb | `app/controllers/api/v1/accounts/inboxes_controller.rb` | コントローラ | インボックスCRUD API |
| inbox_policy.rb | `app/policies/inbox_policy.rb` | ポリシー | インボックス操作の認可 |
| out_of_offisable.rb | `app/models/concerns/out_of_offisable.rb` | Concern | 営業時間機能 |
| avatarable.rb | `app/models/concerns/avatarable.rb` | Concern | アバター管理 |
| working_hour.rb | `app/models/working_hour.rb` | モデル | 営業時間データモデル |
| inbox_round_robin_service.rb | `app/services/auto_assignment/inbox_round_robin_service.rb` | サービス | ラウンドロビンキュー操作 |
