# 帳票設計書 5-会話サマリーレポート（CSV）

## 概要

本ドキュメントは、Chatwootシステムにおける会話全体の統計サマリーレポート（CSV形式）の設計仕様を定義する。

### 本帳票の処理概要

会話サマリーレポートは、指定期間内におけるアカウント全体の会話統計をサマリーとして集計し、全体的なサポートパフォーマンスの概況をCSV形式で出力する帳票である。

**業務上の目的・背景**：カスタマーサポート業務の全体的な健全性を把握するためには、個別のエージェントやチームではなく、組織全体としての統計が必要である。本帳票は、経営層やマネジメントが全体のサポート品質を俯瞰し、KPI達成状況を確認するための基礎資料として活用される。前期比較や目標値との差異分析に利用できる。

**帳票の利用シーン**：経営会議でのサポート品質報告、月次・四半期のKPIレビュー、サポートチーム全体の目標設定と進捗確認、外部ステークホルダーへの報告資料作成時に利用される。

**主要な出力内容**：
1. 会話数（期間内に発生した会話の総数）
2. 受信メッセージ数（顧客から受信したメッセージの総数）
3. 送信メッセージ数（エージェントが送信したメッセージの総数）
4. 平均初回応答時間（顧客からの問い合わせに対する最初の返信までの平均時間）
5. 平均解決時間（会話開始から解決完了までの平均所要時間）
6. 解決数（解決済みとなった会話の総数）
7. 平均顧客待ち時間（顧客が返信を待った平均時間）

**帳票の出力タイミング**：管理者がレポート画面から任意のタイミングでダウンロードボタンをクリックした際にオンデマンドで生成・出力される。

**帳票の利用者**：アカウント管理者、経営層、事業責任者

## 帳票種別

集計表

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | レポート画面（会話サマリー） | `/app/accounts/:account_id/reports/conversations` | 「Download」ボタンクリック |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `conversations_summary_report.csv` |
| 出力方法 | ダウンロード |
| 文字コード | UTF-8 |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | カンマ（,） |
| 囲み文字 | ダブルクォート（"）- CSVSafeライブラリによる自動エスケープ |
| ヘッダー行 | あり（1行目：期間情報、2行目：カラムヘッダー） |
| BOM | なし |

## 帳票レイアウト

### レイアウト概要

CSVファイルは以下の構成で出力される。1行目にレポート対象期間、2行目にカラムヘッダー、3行目にサマリーデータが1行で出力される。

```
┌─────────────────────────────────────┐
│          期間情報（1行目）            │
├─────────────────────────────────────┤
│        カラムヘッダー（2行目）         │
├─────────────────────────────────────┤
│        サマリーデータ（3行目）         │
│            （1行のみ）               │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | レポート期間 | 集計対象期間 | `params[:since]`, `params[:until]` | "Reporting period YYYY-MM-DD to YYYY-MM-DD" |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | Conversations | 会話総数 | `conversations.count` | 整数 | - |
| 2 | Messages received | 受信メッセージ総数 | `messages.count` (incoming) | 整数 | - |
| 3 | Messages sent | 送信メッセージ総数 | `messages.count` (outgoing) | 整数 | - |
| 4 | Avg first response time | 平均初回応答時間 | `reporting_events.value`（first_response） | "X days Y hours" / "N/A" | - |
| 5 | Avg resolution time | 平均解決時間 | `reporting_events.value`（conversation_resolved） | "X days Y hours" / "N/A" | - |
| 6 | Resolution count | 解決した会話総数 | `reporting_events.count`（conversation_resolved） | 整数 | - |
| 7 | Avg customer waiting time | 平均顧客待ち時間 | `reporting_events.value`（reply_time） | "X days Y hours" / "N/A" | - |

### フッター部

フッターなし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| since | 集計開始日（UNIXタイムスタンプ） | Yes |
| until | 集計終了日（UNIXタイムスタンプ） | Yes |
| business_hours | 営業時間のみで計算するかどうか | No |

### ソート順

N/A（サマリー1行のみのため）

### 改ページ条件

N/A（CSV形式のため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| conversations | 会話数のカウント | `conversations.account_id = Current.account.id` |
| messages | メッセージ数のカウント | `messages.account_id = Current.account.id` |
| reporting_events | 統計値の集計 | `reporting_events.account_id = Current.account.id` |

### テーブル別参照項目詳細

#### conversations

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | Conversations（COUNT） | `created_at BETWEEN since AND until` | - |

#### messages

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | Messages received（COUNT） | `message_type = 0 AND created_at BETWEEN since AND until` | incoming messages |
| id | Messages sent（COUNT） | `message_type = 1 AND created_at BETWEEN since AND until` | outgoing messages |

#### reporting_events

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| value / value_in_business_hours | Avg first response time | `name = 'first_response' AND created_at BETWEEN since AND until` | 全体平均 |
| value / value_in_business_hours | Avg resolution time | `name = 'conversation_resolved' AND created_at BETWEEN since AND until` | 全体平均 |
| value / value_in_business_hours | Avg customer waiting time | `name = 'reply_time' AND created_at BETWEEN since AND until` | 全体平均 |
| id | Resolution count | `name = 'conversation_resolved' AND created_at BETWEEN since AND until` | COUNT |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| Avg first response time | AVG(reporting_events.value WHERE name='first_response') | 整数（秒） | TimeFormatPresenterで人間可読形式に変換 |
| Avg resolution time | AVG(reporting_events.value WHERE name='conversation_resolved') | 整数（秒） | TimeFormatPresenterで人間可読形式に変換 |
| Avg customer waiting time | AVG(reporting_events.value WHERE name='reply_time') | 整数（秒） | TimeFormatPresenterで人間可読形式に変換 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ダウンロード要求] --> B[check_authorization]
    B --> C[generate_conversations_report]
    C --> D[MetricBuilder.summary]
    D --> E[各メトリクスの集計]
    E --> F[generate_conversation_report_metrics - 時間フォーマット]
    F --> G[generate_csv - CSVレスポンス生成]
    G --> H[ERBテンプレートでCSV出力]
    H --> I[ファイルダウンロード]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 認可エラー | レポート閲覧権限がない場合 | HTTP 403 | 管理者権限を持つユーザーでログイン |
| パラメータ不足 | since/untilパラメータが不正な場合 | パラメータによる | 正しい期間パラメータを指定 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 出力は1行（サマリー） |
| 目標出力時間 | 数秒以内 |
| 同時出力数上限 | 特に制限なし |

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

- レポート閲覧は `report:view?` ポリシーで認可チェックを実施
- アカウント全体の統計情報へのアクセスは管理者権限を持つユーザーに限定

## 備考

- 時間の表示形式は `Reports::TimeFormatPresenter` により「X days Y hours」形式に変換される
- 値が存在しない場合は「N/A」と表示される
- business_hoursパラメータがtrueの場合、`value_in_business_hours`カラムの値が使用される
- 本レポートは1行のサマリーデータのみを出力する

---

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

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

### 推奨読解順序

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

まず、帳票出力に使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | en.yml | `config/locales/en.yml` | reports.conversation_csvセクションでCSVヘッダーの翻訳キーを確認（行175-182） |

**読解のコツ**: 会話サマリーはアカウント全体の集計であり、グループ化は行わない。

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

処理の起点となるコントローラーを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | conversations_summaryアクション（行41-44）がエントリーポイント |

**主要処理フロー**:
1. **行5**: `check_authorization` で権限チェック
2. **行41-44**: `conversations_summary` アクションで `generate_conversations_report` を呼び出し
3. **行43**: `generate_csv` でCSVレスポンスを生成

#### Step 3: Helperメソッドを理解する

レポートデータ生成のヘルパーメソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | reports_helper.rb | `app/helpers/api/v2/accounts/reports_helper.rb` | `generate_conversations_report` メソッド（行49-54）でデータ生成ロジックを確認 |

**主要処理フロー**:
- **行50**: `MetricBuilder` でサマリーデータを構築
- **行51**: `builder.summary` でサマリー統計を取得
- **行53**: `generate_conversation_report_metrics` で時間フォーマット変換

#### Step 4: ビルダークラスを理解する

集計処理の本体であるBuilderクラスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | metric_builder.rb | `app/builders/v2/reports/conversations/metric_builder.rb` | summaryメソッド（行2-12）で各メトリクスを取得 |

**主要処理フロー**:
- **行2-12**: summaryメソッドで conversations_count, incoming_messages_count, outgoing_messages_count, avg_first_response_time, avg_resolution_time, resolutions_count, reply_time を取得

#### Step 5: CSVテンプレートを理解する

最終的なCSV出力のテンプレートを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | conversations_summary.csv.erb | `app/views/api/v2/accounts/reports/conversations_summary.csv.erb` | CSVの行構造と出力形式（全17行） |

**主要処理フロー**:
- **行1**: 期間情報を1行目に出力
- **行3-11**: ヘッダー行の定義（7カラム）
- **行13**: ヘッダー行をCSV出力
- **行14-16**: @report_dataの各行（1行のみ）をCSV出力

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

```
Api::V2::Accounts::ReportsController#conversations_summary
    │
    ├─ check_authorization (before_action)
    │      └─ ReportPolicy#view?
    │
    ├─ Api::V2::Accounts::ReportsHelper#generate_conversations_report
    │      │
    │      ├─ V2::Reports::Conversations::MetricBuilder#summary
    │      │      │
    │      │      └─ #count (各メトリクス分)
    │      │             └─ builder_class(metric).aggregate_value
    │      │
    │      └─ #generate_conversation_report_metrics
    │             └─ Reports::TimeFormatPresenter#format (時間メトリクス分)
    │
    └─ #generate_csv
           └─ render 'api/v2/accounts/reports/conversations_summary'
                  └─ conversations_summary.csv.erb
```

### データフロー図

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

params[:since]    ─────┐
params[:until]    ─────┼──▶  MetricBuilder                 ──▶   summary hash
params[:business_hours]┘           │
                                   ├─▶ conversations (COUNT)
                                   ├─▶ messages (COUNT by type)
                                   └─▶ reporting_events (AVG, COUNT)
                                              │
                                              ▼
                      generate_conversation_report_metrics
                                              │
                                              ▼
                        TimeFormatPresenter#format
                                              │
                                              ▼
                           conversations_summary.csv.erb
                                              │
                                              ▼
                           conversations_summary_report.csv
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reports_controller.rb | `app/controllers/api/v2/accounts/reports_controller.rb` | コントローラー | エントリーポイント、CSV生成制御 |
| reports_helper.rb | `app/helpers/api/v2/accounts/reports_helper.rb` | ヘルパー | レポートデータ生成の補助 |
| metric_builder.rb | `app/builders/v2/reports/conversations/metric_builder.rb` | ビルダー | サマリー集計処理 |
| time_format_presenter.rb | `app/presenters/reports/time_format_presenter.rb` | プレゼンター | 時間表示形式変換 |
| conversations_summary.csv.erb | `app/views/api/v2/accounts/reports/conversations_summary.csv.erb` | テンプレート | CSV出力フォーマット定義 |
| en.yml | `config/locales/en.yml` | 設定 | CSVヘッダーの翻訳定義 |
| report_policy.rb | `app/policies/report_policy.rb` | ポリシー | レポート閲覧権限制御 |
