# 機能設計書 116-サマリーレポート

## 概要

本ドキュメントは、Chatwootのサマリーレポート機能の設計を記述する。この機能は、指定期間の主要なパフォーマンス指標（KPI）を集計し、現在期間と前期間の比較データを提供する要約統計レポート機能である。

### 本機能の処理概要

サマリーレポート機能は、会話数、送受信メッセージ数、平均初回応答時間、平均解決時間、解決数、平均返信時間などの主要メトリクスを集計し、指定された期間と同じ長さの前期間のデータと比較できる形式で提供する機能である。これにより、パフォーマンスの経時変化を把握できる。

**業務上の目的・背景**：カスタマーサポート業務では、KPIの推移を継続的にモニタリングすることが重要である。サマリーレポートにより、週次・月次の主要指標を一覧で確認し、前期間との比較で改善・悪化を即座に把握できる。これにより、パフォーマンス低下の早期検知や改善施策の効果測定に活用できる。

**機能の利用シーン**：
- 週次・月次のKPIレビュー
- 経営層への報告用サマリーデータ取得
- 前期間比較によるトレンド分析
- ダッシュボードのサマリーカード表示

**主要な処理内容**：
1. 指定期間（since〜until）のメトリクスを集計
2. 前期間（同じ長さの直前期間）のメトリクスを自動計算
3. 現在期間のメトリクスに前期間のデータをマージして返却
4. 営業時間ベースの計算オプションに対応

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | 会話レポート画面 | 補助機能 | 要約統計の表示 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | String | Yes | スコープタイプ（account/inbox/agent/label/team） | 有効なタイプ値 |
| id | Integer | No | 対象ID（type=account以外の場合に必要） | 存在するID |
| since | String | Yes | 集計開始日時（UNIXタイムスタンプ文字列） | 数値変換可能な文字列 |
| until | String | Yes | 集計終了日時（UNIXタイムスタンプ文字列） | 数値変換可能な文字列 |
| group_by | String | No | グループ化単位（day/week/month/year/hour） | 有効な単位 |
| business_hours | Boolean | No | 営業時間ベースで計算するか | true/false |
| timezone_offset | Float | No | タイムゾーンオフセット | 数値 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| conversations_count | Integer | 会話数 |
| incoming_messages_count | Integer | 受信メッセージ数 |
| outgoing_messages_count | Integer | 送信メッセージ数 |
| avg_first_response_time | Float | 平均初回応答時間（秒） |
| avg_resolution_time | Float | 平均解決時間（秒） |
| resolutions_count | Integer | 解決数 |
| reply_time | Float | 平均返信時間（秒） |
| previous | Hash | 前期間の同一メトリクス |

### 出力先

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

## 処理フロー

### 処理シーケンス

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

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

3. パラメータ準備
   └─ 現在期間用と前期間用のパラメータを生成

4. 現在期間のサマリー取得
   └─ MetricBuilder#summary で現在期間のメトリクスを集計

5. 前期間のサマリー取得
   └─ MetricBuilder#summary で前期間のメトリクスを集計

6. データマージ
   └─ 現在期間のデータにprevious: 前期間のデータをマージ

7. レスポンス返却
   └─ JSON形式でサマリーを返却
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{認可チェック}
    B -->|権限あり| C[rangeパラメータを計算]
    B -->|権限なし| Z[403 Forbidden]
    C --> D[current_summary_params を生成]
    D --> E[previous_summary_params を生成]
    E --> F[MetricBuilder で現在サマリー取得]
    F --> G[MetricBuilder で前期サマリー取得]
    G --> H[current_summary.merge previous]
    H --> I[JSON レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-116-01 | 期間指定必須 | since/untilパラメータは必須 | 常時 |
| BR-116-02 | 前期間自動計算 | 前期間は現在期間と同じ長さで直前の期間 | 常時 |
| BR-116-03 | 営業時間計算 | business_hours=trueの場合、value_in_business_hoursカラムを使用 | business_hoursパラメータがtrue |
| BR-116-04 | スコープ対応 | type=account/inbox/agent/label/teamに応じてスコープを変更 | 常時 |

### 計算ロジック

**前期間の計算**：
```ruby
previous_since = since - (until - since)
previous_until = since
```

例：現在期間が2024-01-08〜2024-01-14（7日間）の場合
- 前期間：2024-01-01〜2024-01-07（7日間）

**メトリクスの集計**：
- MetricBuilderの各メトリクスビルダーを使用して集計
- CountReportBuilder：会話数、メッセージ数、解決数
- AverageReportBuilder：平均応答時間、平均解決時間、平均返信時間

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 会話数集計 | conversations | SELECT | 期間内の会話数をカウント |
| メッセージ数集計 | messages | SELECT | 期間内の送受信メッセージ数をカウント |
| イベント集計 | reporting_events | SELECT | 各種メトリクスの平均値・件数を算出 |

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

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | COUNT(*) | created_at BETWEEN since AND until | 会話数 |

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | COUNT(*) | created_at BETWEEN since AND until, message_type = incoming/outgoing | メッセージ数 |

#### reporting_events

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | AVG(value), COUNT(*) | created_at BETWEEN since AND until, name = イベント種別 | 各種メトリクス |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

- 複数のメトリクスを集計するため、適切なインデックスが必要
- 長期間の集計でもタイムアウトしないこと

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

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

## 備考

- 前期間との比較により、増減率の計算やトレンド分析がフロントエンドで可能
- CSV出力は別途conversations_summaryエンドポイントで提供

---

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

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

### 推奨読解順序

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

まず、レポートイベントモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reporting_event.rb | `app/models/reporting_event.rb` | value, value_in_business_hoursカラム |

**読解のコツ**: ReportingEventは各種イベント（first_response, conversation_resolved, reply_time）の値を格納している。

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

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

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

**主要処理フロー**:
1. **13-15行目**: `summary`アクションでbuild_summary(:summary)を呼び出し
2. **132-137行目**: `build_summary`で現在期間と前期間のサマリーを取得してマージ
3. **86-100行目**: `current_summary_params`と`previous_summary_params`でパラメータを生成
4. **119-130行目**: `range`で前期間の計算ロジック

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | metric_builder.rb | `app/builders/v2/reports/conversations/metric_builder.rb` | MetricBuilder#summary |
| 3-2 | base_report_builder.rb | `app/builders/v2/reports/conversations/base_report_builder.rb` | builder_class選択ロジック |
| 3-3 | count_report_builder.rb | `app/builders/v2/reports/timeseries/count_report_builder.rb` | カウント系メトリクスの集計 |
| 3-4 | average_report_builder.rb | `app/builders/v2/reports/timeseries/average_report_builder.rb` | 平均値系メトリクスの集計 |

**主要処理フロー**:
- **metric_builder.rb 3-12行目**: summaryで各メトリクスを集計
- **metric_builder.rb 21-25行目**: countで各メトリクスのビルダーを呼び出しaggregate_valueを取得
- **base_report_builder.rb 16-23行目**: builder_classでメトリクス種別に応じたビルダークラスを選択

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

```
ReportsController#summary
    │
    ├─ check_authorization
    │      └─ ReportPolicy#view?
    │
    └─ build_summary(:summary)
           │
           ├─ current_summary_params
           │      └─ range[:current][:since], range[:current][:until]
           │
           ├─ previous_summary_params
           │      └─ range[:previous][:since], range[:previous][:until]
           │
           ├─ MetricBuilder#summary (current)
           │      │
           │      └─ count (for each metric)
           │             │
           │             └─ builder_class(metric).new.aggregate_value
           │                    │
           │                    ├─ CountReportBuilder#aggregate_value
           │                    │      └─ object_scope.count
           │                    │
           │                    └─ AverageReportBuilder#aggregate_value
           │                           └─ object_scope.average(value_key)
           │
           ├─ MetricBuilder#summary (previous)
           │      └─ (同上)
           │
           └─ current_summary.merge(previous: previous_summary)
```

### データフロー図

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

since/until パラメータ ───▶ range 計算 ─────────────────────┐
                              │                              │
                              ├─▶ current: { since, until }  │
                              │                              │
                              └─▶ previous: {                │
                                   since - (until - since),  │
                                   since }                   │
                                                             │
type, id パラメータ ──────▶ scope 決定 ──────────────────────┤
                                                             │
business_hours ───────────▶ average_value_key 判定 ─────────┤
                                                             │
                              ┌──────────────────────────────┘
                              ▼
                         MetricBuilder#summary
                              │
                              ├─▶ conversations_count
                              ├─▶ incoming_messages_count
                              ├─▶ outgoing_messages_count
                              ├─▶ avg_first_response_time
                              ├─▶ avg_resolution_time
                              ├─▶ resolutions_count
                              └─▶ reply_time
                                    │
                                    ▼
                         { current_metrics,
                           previous: previous_metrics }
```

### 関連ファイル一覧

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