# 帳票設計書 9-SLA違反レポート（CSV）

## 概要

本ドキュメントは、Chatwootシステム（Enterprise版）におけるSLA（Service Level Agreement）違反した会話の一覧レポート（CSV形式）の設計仕様を定義する。

### 本帳票の処理概要

SLA違反レポートは、指定期間内においてSLAポリシーに違反した会話の詳細データをCSV形式で出力する帳票である。Enterprise版でのみ利用可能な機能である。

**業務上の目的・背景**：SLA（サービスレベル合意）は、顧客に対するサポート品質の保証を定義するものであり、SLA違反は顧客満足度や契約上の問題に直結する。本帳票により、どの会話でSLA違反が発生したか、どのポリシーに違反したか、担当者は誰かを把握し、再発防止策の検討や運用改善に活用できる。

**帳票の利用シーン**：SLA遵守状況の定期報告、SLA違反の原因分析、エージェント・チーム別のSLAパフォーマンス評価、SLAポリシーの見直し検討時に利用される。

**主要な出力内容**：
1. 会話ID（違反が発生した会話の識別子）
2. 違反したSLAポリシー名
3. 担当者（割り当てられたエージェント名）
4. チーム（会話が割り当てられたチーム）
5. 受信トレイ（会話が発生したインボックス）
6. ラベル（会話に付与されたラベル一覧）
7. 会話リンク（該当会話へのURL）
8. 違反イベント（どのSLAイベントに違反したか）

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

**帳票の利用者**：アカウント管理者、SLA管理者、品質管理担当者（Enterprise版契約ユーザー）

## 帳票種別

一覧表

## 利用画面

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

## 出力形式

### 基本仕様

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

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | カンマ（,） |
| 囲み文字 | ダブルクォート（"） |
| ヘッダー行 | あり（1行目：カラムヘッダー） |
| BOM | なし |

## 帳票レイアウト

### レイアウト概要

CSVファイルは以下の構成で出力される。1行目にカラムヘッダー、2行目以降にSLA違反データが出力される。

```
┌─────────────────────────────────────┐
│        カラムヘッダー（1行目）         │
├─────────────────────────────────────┤
│         SLA違反データ                │
│          （2行目以降）                │
│       各違反レコード1行ずつ           │
└─────────────────────────────────────┘
```

### ヘッダー部（1行目）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Conversation ID | 会話ID | I18n翻訳キー | 文字列 |
| 2 | SLA Policy | 違反したSLAポリシー | I18n翻訳キー | 文字列 |
| 3 | Assignee | 担当者 | I18n翻訳キー | 文字列 |
| 4 | Team | チーム | I18n翻訳キー | 文字列 |
| 5 | Inbox | 受信トレイ | I18n翻訳キー | 文字列 |
| 6 | Labels | ラベル | I18n翻訳キー | 文字列 |
| 7 | Link to the Conversation | 会話リンク | I18n翻訳キー | 文字列 |
| 8 | Breached Events | 違反イベント | I18n翻訳キー | 文字列 |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | Conversation ID | 会話の表示ID | `conversations.display_id` | 整数 | - |
| 2 | SLA Policy | 違反したSLAポリシー名 | `sla_policies.name` | 文字列 | - |
| 3 | Assignee | 担当エージェント名 | `users.name` | 文字列 | - |
| 4 | Team | チーム名 | `teams.name` | 文字列 | - |
| 5 | Inbox | 受信トレイ名 | `inboxes.name` | 文字列 | - |
| 6 | Labels | 会話のラベル（カンマ区切り） | `conversations.cached_label_list` | 文字列 | - |
| 7 | Link to the Conversation | 会話へのURL | `app_account_conversation_url` | URL文字列 | - |
| 8 | Breached Events | 違反イベント種別（カンマ区切り） | `sla_events.event_type` | 文字列 | - |

### フッター部

フッターなし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| since | 集計開始日 | No（日付範囲） |
| until | 集計終了日 | No（日付範囲） |
| inbox_id | フィルタ対象の受信トレイID | No |
| team_id | フィルタ対象のチームID | No |
| sla_policy_id | フィルタ対象のSLAポリシーID | No |
| label_list | フィルタ対象のラベルリスト | No |
| assigned_agent_id | フィルタ対象のエージェントID | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | created_at | 降順（デフォルト） |

### 改ページ条件

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| applied_slas | SLA適用レコードの取得 | `applied_slas.account_id = Current.account.id` |
| conversations | 会話情報の取得 | `conversations.id = applied_slas.conversation_id` |
| sla_policies | SLAポリシー情報の取得 | `sla_policies.id = applied_slas.sla_policy_id` |
| sla_events | SLA違反イベントの取得 | `sla_events.applied_sla_id = applied_slas.id` |
| users | エージェント情報の取得 | `users.id = conversations.assignee_id` |
| teams | チーム情報の取得 | `teams.id = conversations.team_id` |
| inboxes | 受信トレイ情報の取得 | `inboxes.id = conversations.inbox_id` |

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

#### applied_slas

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| sla_status | フィルタ条件 | `sla_status = 'missed'` | - |
| conversation_id | conversations結合 | - | - |
| sla_policy_id | sla_policies結合 | - | - |

#### conversations

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| display_id | Conversation ID | - | - |
| assignee_id | Assignee | - | - |
| team_id | Team | - | - |
| inbox_id | Inbox | - | - |
| cached_label_list | Labels | - | - |

#### sla_policies

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

#### sla_events

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| event_type | Breached Events | - | カンマ区切りで結合 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| Link to the Conversation | `app_account_conversation_url(account_id, conversation.display_id)` | N/A | URLヘルパーで生成 |
| Breached Events | `sla_events.map(&:event_type).join(', ')` | N/A | カンマ区切りで結合 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ダウンロード要求] --> B[check_admin_authorization?]
    B --> C[set_applied_slas]
    C --> D[apply_filters]
    D --> E[missed_applied_slas]
    E --> F[download アクション]
    F --> G[ERBテンプレートでCSV出力]
    G --> H[ファイルダウンロード]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 認可エラー | 管理者権限がない場合 | HTTP 403 | 管理者権限を持つユーザーでログイン |
| Enterprise版未契約 | Enterprise版でない場合 | HTTP 404 / 機能非表示 | Enterprise版にアップグレード |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千件 |
| 目標出力時間 | 数秒以内 |
| 同時出力数上限 | 特に制限なし |

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

- Enterprise版のみで利用可能な機能
- レポート閲覧は管理者権限チェックを実施
- 会話リンクはアカウント内の正規URLとして生成される

## 備考

- Enterprise版のみで利用可能（`enterprise/` ディレクトリ配下に実装）
- `applied_slas` テーブルの `sla_status = 'missed'` でフィルタ
- 違反イベント（Breached Events）は複数の場合カンマ区切りで出力
- 各種フィルタ条件を組み合わせて絞り込みが可能

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | en.yml | `config/locales/en.yml` | reports.sla_csvセクション（行185-193）でCSVヘッダーの翻訳キーを確認 |
| 1-2 | applied_slas テーブル定義 | `db/schema.rb` | applied_slasテーブルのカラム定義（sla_status等） |
| 1-3 | sla_events テーブル定義 | `db/schema.rb` | sla_eventsテーブルのカラム定義（event_type等） |

**読解のコツ**: applied_slasテーブルはSLAポリシーが会話に適用された記録を保持し、sla_statusが'missed'のものがSLA違反となる。

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

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

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

**主要処理フロー**:
1. **行9**: `check_admin_authorization?` で管理者権限チェック
2. **行7**: `set_applied_slas` でデータ取得
3. **行24-29**: `download` アクションでCSVレスポンスを生成

#### Step 3: フィルタ処理を理解する

データ取得時のフィルタ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | applied_slas_controller.rb | `enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb` | `set_applied_slas` と `apply_filters` メソッド（行49-61） |

**主要処理フロー**:
- **行50**: 基本クエリでincludes(:conversation)
- **行51**: apply_filtersでフィルタを適用
- **行54-60**: 各フィルタを連鎖適用（date_range, inbox_id, team_id, sla_policy_id, label_list, assigned_agent_id）
- **行63-65**: missed_applied_slasでsla_status='missed'のみ抽出

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | download.csv.erb | `enterprise/app/views/api/v1/accounts/applied_slas/download.csv.erb` | CSVの行構造と出力形式（全27行） |

**主要処理フロー**:
- **行1-10**: ヘッダー行の定義（8カラム）
- **行11**: ヘッダー行をCSV出力
- **行13-26**: 各SLA違反をループして行を生成
- **行14**: sla_eventsからevent_typeを取得してカンマ区切りで結合
- **行16-25**: 行データの構築（conversation.display_id, sla_policy.name等）

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

```
Api::V1::Accounts::AppliedSlasController#download
    │
    ├─ check_admin_authorization? (before_action)
    │
    ├─ set_applied_slas (before_action)
    │      │
    │      ├─ applied_slas.includes(:conversation)
    │      │
    │      └─ #apply_filters
    │             ├─ filter_by_date_range
    │             ├─ filter_by_inbox_id
    │             ├─ filter_by_team_id
    │             ├─ filter_by_sla_policy_id
    │             ├─ filter_by_label_list
    │             └─ filter_by_assigned_agent_id
    │
    ├─ #missed_applied_slas
    │      └─ @applied_slas.missed
    │
    └─ render template: 'download'
           └─ download.csv.erb
                  │
                  └─ @missed_applied_slas.each
                         ├─ sla.sla_events.map(&:event_type)
                         ├─ sla.conversation.display_id
                         ├─ sla.sla_policy.name
                         ├─ conversation.assignee&.name
                         ├─ conversation.team&.name
                         ├─ conversation.inbox&.name
                         ├─ conversation.cached_label_list
                         └─ app_account_conversation_url
```

### データフロー図

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

params[:since]        ─────┐
params[:until]        ─────┤
params[:inbox_id]     ─────┼──▶  set_applied_slas          ──▶   @applied_slas
params[:team_id]      ─────┤           │
params[:sla_policy_id]─────┤           ├─▶ apply_filters (各フィルタ)
params[:label_list]   ─────┤           │
params[:assigned_agent_id]─┘           ▼
                                 missed_applied_slas
                                       │
                                       ▼
                                 @missed_applied_slas
                                       │
                              ┌────────┼────────┐
                              │        │        │
                         sla_events  conversation  sla_policy
                              │        │        │
                              ▼        ▼        ▼
                    Breached Events  会話情報  SLA Policy名
                                       │
                                       ▼
                           download.csv.erb
                                       │
                                       ▼
                           breached_conversation.csv
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| applied_slas_controller.rb | `enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb` | コントローラー | エントリーポイント、フィルタ処理 |
| download.csv.erb | `enterprise/app/views/api/v1/accounts/applied_slas/download.csv.erb` | テンプレート | CSV出力フォーマット定義 |
| applied_sla.rb | `enterprise/app/models/applied_sla.rb` | モデル | SLA適用データモデル |
| sla_policy.rb | `enterprise/app/models/sla_policy.rb` | モデル | SLAポリシーモデル |
| en.yml | `config/locales/en.yml` | 設定 | CSVヘッダーの翻訳定義 |
