# 機能設計書 117-ボット分析

## 概要

本ドキュメントは、Chatwootのボット分析機能の設計を記述する。この機能は、AIボット（Agent Bot）のパフォーマンスを分析し、ボットによる自動解決率やハンドオフ率などの指標を提供するレポーティング機能である。

### 本機能の処理概要

ボット分析機能は、ボットが有効化されているインボックスにおける会話の統計情報を集計し、ボットの自動解決数、人間エージェントへのハンドオフ数、解決率、ハンドオフ率などを算出する機能である。これにより、ボットの効果測定と改善施策の立案を支援する。

**業務上の目的・背景**：カスタマーサポートにおいて、AIボットの導入は業務効率化の重要な施策である。ボット分析機能により、ボットがどの程度の問い合わせを自動解決できているか、どの程度の問い合わせが人間エージェントにエスカレーションされているかを定量的に把握できる。この情報は、ボットの学習データ改善やシナリオ拡充の判断材料として活用できる。

**機能の利用シーン**：
- ボット導入効果の測定
- ボット解決率の推移モニタリング
- ハンドオフ率の分析によるボットシナリオ改善
- ボット会話数・メッセージ数の確認

**主要な処理内容**：
1. ボットが有効化されているインボックスを特定
2. 該当インボックスの会話数・メッセージ数を集計
3. ReportingEventからボット解決イベント・ハンドオフイベントを集計
4. 解決率・ハンドオフ率を算出
5. JSON形式でメトリクスを返却（サマリーとメトリクスの2種類のエンドポイント）

**関連システム・外部連携**：Agent Bot機能（AIボット）との連携

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 44 | ボットレポート画面 | 主機能 | ボットパフォーマンス分析 |

## 機能種別

データ集計・レポート出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| since | String | Yes | 集計開始日時（UNIXタイムスタンプ文字列） | 数値変換可能な文字列 |
| until | String | Yes | 集計終了日時（UNIXタイムスタンプ文字列） | 数値変換可能な文字列 |

### 入力データソース

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

## 出力仕様

### 出力データ（bot_summary）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| bot_resolutions_count | Integer | ボットによる解決数 |
| bot_handoffs_count | Integer | 人間エージェントへのハンドオフ数 |

### 出力データ（bot_metrics）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| conversation_count | Integer | ボット有効インボックスの会話数 |
| message_count | Integer | ボットが送信したメッセージ数 |
| resolution_rate | Integer | ボット解決率（%） |
| handoff_rate | Integer | ハンドオフ率（%） |

### 出力先

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

## 処理フロー

### 処理シーケンス

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

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

3. ボット有効インボックスの特定
   └─ account.inboxes.filter(&:active_bot?) でボット有効インボックスを取得

4. メトリクス集計
   └─ bot_summary: MetricBuilder#bot_summary（解決数、ハンドオフ数）
   └─ bot_metrics: BotMetricsBuilder#metrics（会話数、メッセージ数、解決率、ハンドオフ率）

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

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{認可チェック}
    B -->|権限あり| C{エンドポイント}
    B -->|権限なし| Z[403 Forbidden]
    C -->|bot_summary| D[build_summary :bot_summary]
    C -->|bot_metrics| E[BotMetricsBuilder#metrics]
    D --> F[MetricBuilder#bot_summary]
    F --> G[bot_resolutions_count, bot_handoffs_count]
    E --> H[ボット有効インボックスを特定]
    H --> I[会話数・メッセージ数を集計]
    I --> J[解決率・ハンドオフ率を算出]
    G --> K[JSON レスポンス]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-117-01 | 期間指定必須 | since/untilパラメータは必須 | 常時 |
| BR-117-02 | ボット有効インボックス | active_bot?がtrueのインボックスのみ対象 | 常時 |
| BR-117-03 | 解決率計算 | (ボット解決数 / ボット会話数) * 100 | ボット会話数 > 0 |
| BR-117-04 | ハンドオフ率計算 | (ハンドオフ数 / ボット会話数) * 100 | ボット会話数 > 0 |
| BR-117-05 | ゼロ除算対策 | ボット会話数が0の場合は率を0とする | ボット会話数 = 0 |

### 計算ロジック

**ボット解決数の取得**：
```ruby
reporting_events.where(name: :conversation_bot_resolved, created_at: range).distinct.count
```

**ハンドオフ数の取得**：
```ruby
reporting_events.where(name: :conversation_bot_handoff, created_at: range).distinct.count
```

**解決率の計算**：
```ruby
(bot_resolutions_count.to_f / bot_conversations.count * 100).to_i
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| インボックス取得 | inboxes | SELECT | ボット有効インボックスを取得 |
| 会話数集計 | conversations | SELECT | ボット有効インボックスの会話数をカウント |
| メッセージ数集計 | messages | SELECT | ボットが送信したメッセージ数をカウント |
| イベント集計 | reporting_events | SELECT | ボット解決・ハンドオフイベントをカウント |

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

#### reporting_events

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | COUNT(DISTINCT conversation_id) | name = 'conversation_bot_resolved', created_at BETWEEN since AND until | ボット解決数 |
| SELECT | COUNT(DISTINCT conversation_id) | name = 'conversation_bot_handoff', created_at BETWEEN since AND until | ハンドオフ数 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 管理者権限がない場合 | 権限のあるユーザーでログイン |
| 422 | Unprocessable Entity | パラメータ不正 | パラメータを確認して再リクエスト |

### リトライ仕様

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

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

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

## パフォーマンス要件

- ボット有効インボックスの数が多い場合でも迅速にレスポンスを返すこと
- reporting_events.nameへのインデックスが適切に設定されていること

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

- 管理者ロールのみがアクセス可能（ReportPolicyで制御）
- アカウント間のデータ分離はCurrent.accountスコープで担保

## 備考

- bot_summaryはサマリーレポートと同様に前期間比較データを含む
- bot_metricsはBotMetricsBuilderで専用の集計を行う
- ボットが1つも有効化されていない場合、全てのメトリクスは0となる

---

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

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

### 推奨読解順序

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

まず、ボット関連のイベント種別を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reporting_event.rb | `app/models/reporting_event.rb` | イベント種別（conversation_bot_resolved, conversation_bot_handoff） |
| 1-2 | inbox.rb | `app/models/inbox.rb` | active_bot?メソッドの定義 |

**読解のコツ**: ReportingEventのname属性には`conversation_bot_resolved`（ボット自動解決）と`conversation_bot_handoff`（人間へのハンドオフ）という特別なイベント種別がある。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | bot_summary（17-19行目）、bot_metrics（60-63行目） |

**主要処理フロー**:
1. **17-19行目**: `bot_summary`アクションでbuild_summary(:bot_summary)を呼び出し
2. **60-63行目**: `bot_metrics`アクションでBotMetricsBuilder#metricsを呼び出し

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | metric_builder.rb | `app/builders/v2/reports/conversations/metric_builder.rb` | bot_summary（14-18行目） |
| 3-2 | bot_metrics_builder.rb | `app/builders/v2/reports/bot_metrics_builder.rb` | 専用の集計ロジック |

**主要処理フロー**:
- **metric_builder.rb 14-18行目**: bot_summaryでbot_resolutions_countとbot_handoffs_countを取得
- **bot_metrics_builder.rb 10-17行目**: metricsでconversation_count, message_count, resolution_rate, handoff_rateを返却
- **bot_metrics_builder.rb 21-23行目**: bot_activated_inbox_idsでボット有効インボックスを特定
- **bot_metrics_builder.rb 25-27行目**: bot_conversationsでボット有効インボックスの会話を取得
- **bot_metrics_builder.rb 43-53行目**: 解決率・ハンドオフ率の計算

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

```
ReportsController#bot_summary
    │
    ├─ check_authorization
    │      └─ ReportPolicy#view?
    │
    └─ build_summary(:bot_summary)
           │
           └─ MetricBuilder#bot_summary
                  │
                  ├─ count('bot_resolutions_count')
                  │      └─ CountReportBuilder#aggregate_value
                  │             └─ scope_for_bot_resolutions_count
                  │
                  └─ count('bot_handoffs_count')
                         └─ CountReportBuilder#aggregate_value
                                └─ scope_for_bot_handoffs_count

ReportsController#bot_metrics
    │
    ├─ check_authorization
    │      └─ ReportPolicy#view?
    │
    └─ BotMetricsBuilder#metrics
           │
           ├─ bot_activated_inbox_ids
           │      └─ inboxes.filter(&:active_bot?)
           │
           ├─ bot_conversations.count
           │
           ├─ bot_messages.count
           │
           ├─ bot_resolution_rate
           │      └─ bot_resolutions_count / bot_conversations.count * 100
           │
           └─ bot_handoff_rate
                  └─ bot_handoffs_count / bot_conversations.count * 100
```

### データフロー図

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

since/until パラメータ ───▶ DateRangeHelper#range ───────────┐
                                                              │
                              ┌──────────────────────────────┘
                              ▼
Current.account ────────────▶ BotMetricsBuilder
                              │
                              ├─▶ inboxes.filter(&:active_bot?) ──┐
                              │      → bot_activated_inbox_ids    │
                              │                                    │
                              └─────────────────────────────────────┤
                                                                    │
                              ┌─────────────────────────────────────┘
                              ▼
                         conversations.where(inbox_id: bot_ids)
                              │
                              ├─▶ count → conversation_count
                              │
                              ▼
                         messages.outgoing
                              │
                              └─▶ count → message_count

                         reporting_events
                              │
                              ├─▶ conversation_bot_resolved → resolution_rate
                              │
                              └─▶ conversation_bot_handoff → handoff_rate
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | コントローラー | APIエンドポイント |
| bot_metrics_builder.rb | `app/builders/v2/reports/bot_metrics_builder.rb` | ビルダー | ボットメトリクス集計 |
| metric_builder.rb | `app/builders/v2/reports/conversations/metric_builder.rb` | ビルダー | サマリー集計 |
| count_report_builder.rb | `app/builders/v2/reports/timeseries/count_report_builder.rb` | ビルダー | カウント系集計 |
| date_range_helper.rb | `app/helpers/date_range_helper.rb` | ヘルパー | 日付範囲処理 |
| reporting_event.rb | `app/models/reporting_event.rb` | モデル | レポートイベントデータ |
| inbox.rb | `app/models/inbox.rb` | モデル | インボックス（active_bot?） |
| report_policy.rb | `app/policies/report_policy.rb` | ポリシー | 認可制御 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（438, 446行目） |
