# 機能設計書 115-会話分析

## 概要

本ドキュメントは、Chatwootの会話分析機能の設計を記述する。この機能は、会話に関する詳細なメトリクスを分析し、アカウント全体またはエージェント別のライブ会話統計を提供するレポーティング機能である。

### 本機能の処理概要

会話分析機能は、指定されたタイプ（アカウント全体またはエージェント別）に基づいて、現在のオープン会話数、未対応会話数、未割り当て会話数、保留中会話数などのライブメトリクスを取得する機能である。これにより、リアルタイムのサポート状況を把握し、リソース配分の判断材料として活用できる。

**業務上の目的・背景**：カスタマーサポート業務では、現在の会話状況をリアルタイムで把握することが重要である。会話分析機能により、オープン中の会話数、対応待ちの会話数、各エージェントの負荷状況などを即座に確認できる。これにより、マネージャーはリソースの再配分やエスカレーションの判断を迅速に行える。

**機能の利用シーン**：
- リアルタイムのサポートキュー状況確認
- エージェント別の負荷分散確認
- 未対応会話の早期検知と対応優先度の判断
- シフト交代時の状況引き継ぎ

**主要な処理内容**：
1. タイプパラメータ（account/agent）に基づいてスコープを決定
2. アカウント全体の場合：オープン、未対応、未割り当て、保留中の会話数を取得
3. エージェント別の場合：各エージェントのオープン、未対応会話数をページネーション付きで取得
4. JSON形式でメトリクスを返却

**関連システム・外部連携**：特になし（内部データの集計機能）

**権限による制御**：管理者（Administrator）ロールを持つユーザーのみがレポートを閲覧可能（ReportPolicy#view?で制御）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | 会話レポート画面 | 主機能 | 会話に関するレポート表示 |

## 機能種別

データ集計・リアルタイムレポート

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | String | Yes | 分析タイプ（account/agent） | account または agent |
| user_id | Integer | No | エージェントID（type=agentの場合） | 存在するユーザーID |
| page | Integer | No | ページ番号（エージェント一覧のページネーション） | 1以上の整数（デフォルト: 1） |

### 入力データソース

- HTTPリクエストパラメータ（API呼び出し時）
- Current.account（認証済みユーザーのアカウント情報）

## 出力仕様

### 出力データ（type=account）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| open | Integer | オープン状態の会話数 |
| unattended | Integer | 未対応の会話数 |
| unassigned | Integer | 未割り当ての会話数 |
| pending | Integer | 保留中の会話数 |

### 出力データ（type=agent）

配列形式で各エージェントの情報を返却。

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | ユーザーID |
| name | String | ユーザー名 |
| email | String | メールアドレス |
| thumbnail | String | アバターURL |
| availability | String | 可用性ステータス |
| metric.open | Integer | オープン状態の会話数 |
| metric.unattended | Integer | 未対応の会話数 |

### 出力先

- JSON形式：API V2エンドポイント（`/api/v2/accounts/:account_id/reports/conversations`）

## 処理フロー

### 処理シーケンス

```
1. API呼び出し（GET /api/v2/accounts/:account_id/reports/conversations）
   └─ ReportsController#conversations アクションが起動

2. 認可チェック
   └─ ReportPolicy#view? で管理者権限を確認

3. タイプパラメータのバリデーション
   └─ type が空の場合は 422 Unprocessable Entity

4. メトリクス取得
   └─ V2::ReportBuilder#conversation_metrics を呼び出し

5. タイプ別処理
   └─ type=account の場合：live_conversations でアカウント全体のメトリクスを取得
   └─ type=agent の場合：agent_metrics で各エージェントのメトリクスを取得

6. レスポンス返却
   └─ JSON形式でメトリクスを返却
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{認可チェック}
    B -->|権限あり| C{type パラメータ}
    B -->|権限なし| Z[403 Forbidden]
    C -->|空| Y[422 Unprocessable Entity]
    C -->|account| D[live_conversations]
    C -->|agent| E[agent_metrics]
    D --> F[open, unattended, unassigned, pending を取得]
    E --> G[account_users をページネーション]
    G --> H[各エージェントの live_conversations]
    F --> I[JSON レスポンス]
    H --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-115-01 | タイプ必須 | typeパラメータは必須 | 常時 |
| BR-115-02 | アカウントメトリクス | type=accountの場合、unassigned, pendingも含む | type=account |
| BR-115-03 | エージェントメトリクス | type=agentの場合、各エージェントのメトリクスを配列で返却 | type=agent |
| BR-115-04 | ページネーション | エージェント一覧は25件/ページ | type=agent |
| BR-115-05 | ソート順 | エージェントはオープン会話数の降順でソート | type=agent |

### 計算ロジック

**オープン会話の取得**：
```ruby
scope.conversations.where(account_id: account.id).open
```

**未対応会話の取得**：
```ruby
open_conversations.unattended
```

**未割り当て会話の取得**：
```ruby
open_conversations.unassigned
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 会話カウント | conversations | SELECT | 各種ステータスの会話数をカウント |
| エージェント取得 | account_users, users | SELECT | ページネーション付きでエージェント一覧を取得 |

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

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | COUNT(*) | status = 'open'、各種条件 | ステータス別会話数 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 管理者権限がない場合 | 権限のあるユーザーでログイン |
| 422 | Unprocessable Entity | typeパラメータが空の場合 | typeパラメータを指定 |

### リトライ仕様

該当なし（同期処理のため）

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

読み取り専用処理のため、トランザクション制御は不要。

## パフォーマンス要件

- リアルタイム性が求められるため、高速なレスポンスが必要
- conversations.statusへの適切なインデックスが必要

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

- 管理者ロールのみがアクセス可能（ReportPolicyで制御）
- アカウント間のデータ分離はCurrent.accountスコープで担保
- エージェントのメールアドレスなど個人情報を含むため、適切な認可制御が重要

## 備考

- この機能はライブ（リアルタイム）データを返却するため、期間指定パラメータ（since/until）は不要
- unattendedスコープは会話に対する応答がないものを指す
- エージェント別レポートでは可用性ステータス（availability）も返却される

---

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

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

### 推奨読解順序

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

まず、会話のステータスとスコープを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversation.rb | `app/models/conversation.rb` | statusのenum、open, unattended, unassignedスコープ |

**読解のコツ**: Conversationモデルには`open`、`unattended`、`unassigned`などのスコープが定義されている。これらのスコープがどのような条件でフィルタリングするかを理解することが重要。

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

APIコントローラーからの処理フローを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | conversationsアクション（54-58行目） |

**主要処理フロー**:
1. **54-58行目**: `conversations`アクションでtypeの存在チェック、conversation_metricsを呼び出し
2. **111-116行目**: `conversation_params`でパラメータを整形
3. **139-141行目**: `conversation_metrics`でV2::ReportBuilder#conversation_metricsを呼び出し

#### Step 3: ビルダー層を理解する

実際のデータ集計ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | report_builder.rb | `app/builders/v2/report_builder.rb` | conversation_metricsメソッド（64-70行目） |

**主要処理フロー**:
- **64-70行目**: conversation_metricsでタイプに応じてlive_conversationsまたはagent_metricsを呼び出し
- **113-126行目**: agent_metricsでページネーション付きでエージェント一覧を取得し、各エージェントのメトリクスを構築
- **128-137行目**: live_conversationsでオープン会話のカウントと各種メトリクスを取得

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

```
ReportsController#conversations
    │
    ├─ check_authorization
    │      └─ ReportPolicy#view?
    │
    ├─ params[:type].blank? チェック
    │
    └─ conversation_metrics
           │
           └─ V2::ReportBuilder#conversation_metrics
                  │
                  ├─ (type == :account)
                  │      └─ live_conversations
                  │             │
                  │             ├─ scope.conversations.open.count
                  │             ├─ open_conversations.unattended.count
                  │             ├─ open_conversations.unassigned.count
                  │             └─ open_conversations.pending.count
                  │
                  └─ (type == :agent)
                         └─ agent_metrics
                                │
                                ├─ account.account_users.page(...).per(25)
                                │
                                └─ each account_user
                                       │
                                       └─ live_conversations (per user)
                                              │
                                              └─ { id, name, email, thumbnail,
                                                   availability, metric }
```

### データフロー図

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

type パラメータ ──────────────▶ タイプ判定 ──────────────────────┐
                                                                  │
user_id パラメータ ───────────▶ (type=agent時のみ使用)           │
                                                                  │
page パラメータ ──────────────▶ ページネーション設定              │
                                                                  │
                              ┌──────────────────────────────────┘
                              │
                              ▼
                         ┌─────────┐
                         │ type?   │
                         └────┬────┘
                              │
              ┌───────────────┴───────────────┐
              │                               │
              ▼                               ▼
    [type = account]                 [type = agent]
              │                               │
              ▼                               ▼
    scope.conversations           account.account_users
    .open                         .page(page).per(25)
              │                               │
              ├─▶ count (open)               │
              ├─▶ unattended.count           │
              ├─▶ unassigned.count           │
              └─▶ pending.count     each do |account_user|
                                             │
                                             └─▶ user.conversations
                                                  .open.count
                                                  .unattended.count
                                                        │
                                                        ▼
                                             { id, name, email, ...
                                               metric: { open, unattended } }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | コントローラー | APIエンドポイント |
| report_builder.rb | `app/builders/v2/report_builder.rb` | ビルダー | メトリクス集計ロジック |
| conversation.rb | `app/models/conversation.rb` | モデル | 会話モデル（スコープ定義） |
| account_user.rb | `app/models/account_user.rb` | モデル | アカウント-ユーザー関連 |
| report_policy.rb | `app/policies/report_policy.rb` | ポリシー | 認可制御 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（443行目） |
