# 帳票設計書 1-エージェントレポート（CSV）

## 概要

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

### 本帳票の処理概要

エージェントレポートは、指定期間内における各エージェントの対応実績を集計し、パフォーマンス分析のための統計データをCSV形式で出力する帳票である。

**業務上の目的・背景**：カスタマーサポート業務において、各エージェントの対応品質や効率性を定量的に評価することは、チームマネジメントや人員配置の最適化に不可欠である。本帳票は、管理者がエージェント個々のパフォーマンスを客観的なデータに基づいて評価し、改善点を特定するための基礎資料として活用される。また、エージェントへのフィードバックや人事評価の参考資料としても利用される。

**帳票の利用シーン**：週次・月次のチームミーティングでのパフォーマンスレビュー、個別エージェントへの1on1フィードバックセッション、管理者による業務改善計画の策定、リソース配分の最適化検討時に利用される。

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

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

**帳票の利用者**：アカウント管理者、チームリーダー、スーパーバイザー

## 帳票種別

集計表

## 利用画面

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

## 出力形式

### 基本仕様

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

### CSV固有設定

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

## 帳票レイアウト

### レイアウト概要

CSVファイルは以下の構成で出力される。1行目にレポート対象期間、2行目にカラムヘッダー、3行目以降にエージェント別の集計データが出力される。

```
┌─────────────────────────────────────┐
│          期間情報（1行目）            │
├─────────────────────────────────────┤
│        カラムヘッダー（2行目）         │
├─────────────────────────────────────┤
│         エージェントデータ             │
│           （3行目以降）               │
│         各エージェント1行ずつ          │
└─────────────────────────────────────┘
```

### ヘッダー部

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

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | Agent name | エージェント名 | `users.name` | 文字列 | - |
| 2 | Assigned conversations | 担当した会話数 | `conversations.count` | 整数 | - |
| 3 | Avg first response time | 平均初回応答時間 | `reporting_events.value`（first_response） | "X days Y hours" / "N/A" | - |
| 4 | Avg resolution time | 平均解決時間 | `reporting_events.value`（conversation_resolved） | "X days Y hours" / "N/A" | - |
| 5 | Avg customer waiting time | 平均顧客待ち時間 | `reporting_events.value`（reply_time） | "X days Y hours" / "N/A" | - |
| 6 | Resolution Count | 解決した会話数 | `reporting_events.count`（conversation_resolved） | 整数 | - |

### フッター部

フッターなし

## 出力条件

### 抽出条件

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

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | account_users の登録順 | - |

### 改ページ条件

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| users | エージェント情報の取得 | `account_users.user_id = users.id` |
| account_users | アカウントに所属するエージェント一覧取得 | `account_users.account_id = Current.account.id` |
| conversations | 会話数のカウント | `conversations.account_id = Current.account.id AND conversations.assignee_id = users.id` |
| reporting_events | 統計値の集計 | `reporting_events.account_id = Current.account.id AND reporting_events.user_id = users.id` |

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

#### users

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| name | Agent name | - | - |

#### conversations

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | Assigned conversations（COUNT） | `created_at BETWEEN since AND until` | assignee_id でグループ化 |

#### reporting_events

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| value / value_in_business_hours | Avg first response time | `name = 'first_response' AND created_at BETWEEN since AND until` | user_idでグループ化し平均値を算出 |
| value / value_in_business_hours | Avg resolution time | `name = 'conversation_resolved' AND created_at BETWEEN since AND until` | user_idでグループ化し平均値を算出 |
| value / value_in_business_hours | Avg customer waiting time | `name = 'reply_time' AND created_at BETWEEN since AND until` | user_idでグループ化し平均値を算出 |
| id | Resolution Count | `name = 'conversation_resolved' AND created_at BETWEEN since AND until` | user_idでグループ化し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で人間可読形式に変換 |
| Resolution Count | COUNT(reporting_events WHERE name='conversation_resolved') | 整数 | - |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ダウンロード要求] --> B[check_authorization]
    B --> C[generate_agents_report]
    C --> D[AgentSummaryBuilder.build]
    D --> E[load_data - 会話数取得]
    E --> F[load_reporting_events_data - 統計値取得]
    F --> G[prepare_report - エージェント別データ整形]
    G --> H[generate_readable_report_metrics - 時間フォーマット]
    H --> I[generate_csv - CSVレスポンス生成]
    I --> J[ERBテンプレートでCSV出力]
    J --> K[ファイルダウンロード]
```

## エラー処理

### エラーケース一覧

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

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | エージェント数：数十〜数百名 |
| 目標出力時間 | 数秒以内 |
| 同時出力数上限 | 特に制限なし |

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

- レポート閲覧は `report:view?` ポリシーで認可チェックを実施
- エージェント名は個人情報として取り扱い、アカウント内の権限を持つユーザーのみアクセス可能

## 備考

- 時間の表示形式は `Reports::TimeFormatPresenter` により「X days Y hours」形式に変換される
- 値が存在しない場合は「N/A」と表示される
- business_hoursパラメータがtrueの場合、`value_in_business_hours`カラムの値が使用される

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reporting_events テーブル定義 | `db/schema.rb` | reporting_eventsテーブルのカラム定義（value, value_in_business_hours, name, user_id等） |
| 1-2 | en.yml | `config/locales/en.yml` | reports.agent_csvセクションでCSVヘッダーの翻訳キーを確認（行148-154） |

**読解のコツ**: reporting_eventsテーブルはイベント駆動でデータが記録されるため、nameカラムの値（'first_response', 'conversation_resolved', 'reply_time'）がイベント種別を示す。

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

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

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

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

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

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

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

**主要処理フロー**:
- **行3-6**: `AgentSummaryBuilder` でレポートデータを構築
- **行8-11**: 各エージェントのデータを整形して配列に変換
- **行72-80**: `generate_readable_report_metrics` で時間を人間可読形式に変換

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | base_summary_builder.rb | `app/builders/v2/reports/base_summary_builder.rb` | 親クラスでの共通処理（行1-56）、特にload_reporting_events_data（行16-35） |
| 4-2 | agent_summary_builder.rb | `app/builders/v2/reports/agent_summary_builder.rb` | エージェント固有の処理、group_by_key = :user_id（行37） |

**主要処理フロー**:
- **base_summary_builder.rb 行16-35**: reporting_eventsテーブルから統計値を取得するSQLを構築
- **agent_summary_builder.rb 行14-16**: conversations テーブルからassignee_id でグループ化して会話数を取得
- **agent_summary_builder.rb 行24-34**: 各エージェントの統計情報をハッシュ形式で構築

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

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

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

**主要処理フロー**:
- **行1**: 期間情報を1行目に出力
- **行3-11**: ヘッダー行の定義（I18nで国際化対応）
- **行12**: ヘッダー行をCSV出力
- **行13-15**: @report_dataの各行をCSV出力

#### Step 6: 時間フォーマットを理解する

時間の表示形式変換処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | time_format_presenter.rb | `app/presenters/reports/time_format_presenter.rb` | 秒数を「X days Y hours」形式に変換（全33行） |

**主要処理フロー**:
- **行10-17**: formatメソッドで秒数を日・時間・分・秒に分解
- **行22-31**: format_componentsで上位2単位のみを文字列化

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

```
Api::V2::Accounts::ReportsController#agents
    │
    ├─ check_authorization (before_action)
    │      └─ ReportPolicy#view?
    │
    ├─ Api::V2::Accounts::ReportsHelper#generate_agents_report
    │      │
    │      ├─ V2::Reports::AgentSummaryBuilder#build
    │      │      │
    │      │      ├─ #load_data
    │      │      │      ├─ #fetch_conversations_count
    │      │      │      └─ #load_reporting_events_data (BaseSummaryBuilder)
    │      │      │
    │      │      └─ #prepare_report
    │      │             └─ #build_agent_stats (各エージェント分)
    │      │
    │      └─ Reports::TimeFormatPresenter#format (各メトリクス分)
    │
    └─ #generate_csv
           └─ render 'api/v2/accounts/reports/agents'
                  └─ agents.csv.erb
```

### データフロー図

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

params[:since]    ─────┐
params[:until]    ─────┼──▶  AgentSummaryBuilder          ──▶   @report_data
params[:business_hours]┘           │
                                   ├─▶ conversations (COUNT)
                                   └─▶ reporting_events (AVG)
                                              │
                                              ▼
                              TimeFormatPresenter#format
                                              │
                                              ▼
                                     agents.csv.erb
                                              │
                                              ▼
                                     agents_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` | ヘルパー | レポートデータ生成の補助 |
| agent_summary_builder.rb | `app/builders/v2/reports/agent_summary_builder.rb` | ビルダー | エージェント別集計処理 |
| base_summary_builder.rb | `app/builders/v2/reports/base_summary_builder.rb` | ビルダー | 集計処理の基底クラス |
| time_format_presenter.rb | `app/presenters/reports/time_format_presenter.rb` | プレゼンター | 時間表示形式変換 |
| agents.csv.erb | `app/views/api/v2/accounts/reports/agents.csv.erb` | テンプレート | CSV出力フォーマット定義 |
| en.yml | `config/locales/en.yml` | 設定 | CSVヘッダーの翻訳定義 |
| report_policy.rb | `app/policies/report_policy.rb` | ポリシー | レポート閲覧権限制御 |
