# 帳票設計書 8-連絡先エクスポート（CSV）

## 概要

本ドキュメントは、Chatwootシステムにおける連絡先（Contact）一覧のエクスポート機能（CSV形式）の設計仕様を定義する。

### 本帳票の処理概要

連絡先エクスポートは、アカウント内の連絡先データをCSV形式でエクスポートし、メール添付で送付する帳票である。出力カラムはカスタマイズ可能で、デフォルトではid、name、email、phone_numberが出力される。

**業務上の目的・背景**：CRM（顧客関係管理）業務において、連絡先データを外部システムと連携したり、バックアップを取得したり、データ分析ツールで処理するためには、エクスポート機能が不可欠である。本帳票により、ユーザーは必要なカラムを選択して連絡先データを一括出力し、様々な業務目的に活用できる。

**帳票の利用シーン**：外部CRMへのデータ移行、マーケティングキャンペーン用リスト作成、データバックアップ、顧客分析用データ抽出時に利用される。

**主要な出力内容**：
1. id（連絡先の内部識別子）
2. name（連絡先の名前）
3. email（メールアドレス）
4. phone_number（電話番号）
5. その他、指定されたカスタムカラム（Contactテーブルのカラム）

**帳票の出力タイミング**：ユーザーがエクスポート操作を実行すると、バックグラウンドジョブで処理され、完了後にメールで送付される。

**帳票の利用者**：アカウント管理者、CRM担当者、マーケティング担当者

## 帳票種別

一覧表

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | 連絡先一覧画面 | `/app/accounts/:account_id/contacts` | 「Export」ボタンクリック |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `{アカウント名}_{アカウントID}_contacts.csv` |
| 出力方法 | メール添付で送付 |
| 文字コード | UTF-8 |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | カンマ（,） |
| 囲み文字 | 自動（CSV.generate標準） |
| ヘッダー行 | あり（1行目：カラムヘッダー） |
| BOM | なし |

## 帳票レイアウト

### レイアウト概要

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

```
┌─────────────────────────────────────┐
│        カラムヘッダー（1行目）         │
│  （指定されたカラム名の列挙）          │
├─────────────────────────────────────┤
│          連絡先データ                │
│          （2行目以降）                │
│        各連絡先1行ずつ               │
└─────────────────────────────────────┘
```

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

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1-N | 指定されたカラム名 | ユーザーが選択したカラム | `column_names` パラメータ | 文字列（カラム名） |

### 明細部（デフォルトカラム）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | id | 連絡先ID | `contacts.id` | 整数 | - |
| 2 | name | 連絡先名 | `contacts.name` | 文字列 | - |
| 3 | email | メールアドレス | `contacts.email` | 文字列 | - |
| 4 | phone_number | 電話番号 | `contacts.phone_number` | 文字列 | - |

### フッター部

フッターなし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| column_names | 出力するカラム名の配列 | No（デフォルトあり） |
| payload | フィルタ条件（FilterServiceで使用） | No |
| label | タグフィルタ | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | デフォルト（contactsテーブルの順序） | - |

### 改ページ条件

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| contacts | 連絡先データの取得 | `contacts.account_id = account_id` |
| taggings | ラベルフィルタ時のタグ関連 | `taggings.taggable_id = contacts.id AND taggable_type = 'Contact'` |

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

#### contacts

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | id | - | - |
| name | name | - | - |
| email | email | - | - |
| phone_number | phone_number | - | - |
| 他の全カラム | 指定されたカラム | `Contact.column_names` に含まれるもののみ | - |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ファイル名 | `"#{account.name}_#{account.id}_contacts.csv"` | N/A | - |
| 有効ヘッダー | `(column_names || default_columns) & Contact.column_names` | N/A | 存在しないカラムを除外 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[エクスポート要求] --> B[ContactsExportJob.perform_later]
    B --> C[Account::ContactsExportJob#perform]
    C --> D[valid_headers - ヘッダー検証]
    D --> E[contacts - 連絡先取得]
    E --> F{フィルタ条件}
    F -->|payload| G[FilterService.perform]
    F -->|label| H[tagged_with]
    F -->|なし| I[resolved_contacts]
    G --> J[generate_csv]
    H --> J
    I --> J
    J --> K[attach_export_file - ファイル添付]
    K --> L[send_mail - メール送信]
    L --> M[完了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| アカウント不存在 | 指定されたaccount_idが存在しない場合 | RecordNotFound | 正しいアカウントIDを指定 |
| ユーザー不存在 | 指定されたuser_idが存在しない場合 | RecordNotFound | 正しいユーザーIDを指定 |
| メール送信失敗 | メール送信に失敗した場合 | ジョブ失敗 | メール設定を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数万件 |
| 目標出力時間 | バックグラウンドジョブのため即時性不要 |
| 同時出力数上限 | キュー設定による |

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

- エクスポートされるデータには個人情報（名前、メールアドレス、電話番号）が含まれる
- ファイルはActiveStorage経由でアカウントに紐づけて保存される
- ダウンロードURLはメールで正規ユーザーにのみ送信される
- ダウンロードURLはRails BlobURLとして署名付きで生成される

## 備考

- ジョブキューは `low` で実行される
- column_names パラメータで出力カラムをカスタマイズ可能
- 存在しないカラム名が指定された場合は自動的に除外される
- CRM V2機能が有効な場合、`resolved_contacts` スコープで crm_v2 オプションが適用される
- ラベルフィルタは `tagged_with` で any: true オプションが使用される

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | contacts テーブル定義 | `db/schema.rb` | contactsテーブルのカラム定義（id, name, email, phone_number等） |

**読解のコツ**: contactsテーブルの全カラムがエクスポート対象となりうる。カラム検証は `Contact.column_names` で行われる。

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

処理の起点となるジョブクラスを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | performメソッド（行4-12）がエントリーポイント |

**主要処理フロー**:
1. **行5**: アカウントを取得
2. **行7**: ユーザーを取得
3. **行9**: valid_headers でヘッダー検証
4. **行10**: generate_csv でCSV生成
5. **行11**: send_mail でメール送信

#### Step 3: CSV生成処理を理解する

CSV生成の詳細処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | `generate_csv` メソッド（行16-25） |

**主要処理フロー**:
- **行17-22**: CSV.generateでCSVデータを生成
- **行18**: ヘッダー行を出力
- **行19-21**: 各連絡先をループしてデータ行を出力
- **行24**: attach_export_fileでファイルを添付

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

連絡先取得時のフィルタ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | `contacts` メソッド（行27-36） |

**主要処理フロー**:
- **行28-30**: payloadパラメータがある場合、FilterServiceを使用
- **行31-32**: labelパラメータがある場合、tagged_withでフィルタ
- **行33-35**: それ以外はresolved_contactsスコープを使用

#### Step 5: ファイル添付とメール送信を理解する

生成されたCSVのファイル添付とメール送信処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | `attach_export_file` と `send_mail` メソッド（行42-60） |

**主要処理フロー**:
- **行45-49**: ActiveStorageでアカウントにファイルを添付
- **行52-56**: メール送信処理（AdministratorNotifications::AccountNotificationMailer）
- **行58-60**: ダウンロードURL生成（rails_blob_url）

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

```
Account::ContactsExportJob#perform
    │
    ├─ Account.find(account_id)
    ├─ account.users.find(user_id)
    │
    ├─ #valid_headers
    │      └─ (column_names || default_columns) & Contact.column_names
    │
    ├─ #generate_csv
    │      │
    │      ├─ CSV.generate
    │      │      ├─ csv << headers
    │      │      └─ contacts.each { csv << row }
    │      │
    │      ├─ #contacts
    │      │      ├─ [payload] Contacts::FilterService.perform
    │      │      ├─ [label] tagged_with(label, any: true)
    │      │      └─ [else] resolved_contacts
    │      │
    │      └─ #attach_export_file
    │             └─ account.contacts_export.attach(...)
    │
    └─ #send_mail
           └─ AdministratorNotifications::AccountNotificationMailer
                  #contact_export_complete
```

### データフロー図

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

account_id      ─────┐
user_id         ─────┼──▶  ContactsExportJob#perform       ──▶   CSV生成
column_names    ─────┤           │
params[:payload]─────┤           ├─▶ valid_headers (カラム検証)
params[:label]  ─────┘           ├─▶ contacts (フィルタ適用)
                                 │
                                 ▼
                          CSV.generate
                                 │
                                 ▼
                     contacts_export.attach
                                 │
                                 ▼
                          send_mail
                                 │
                                 ▼
                    {アカウント名}_{アカウントID}_contacts.csv
                          (メール添付)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | ジョブ | CSV生成・メール送信のバックグラウンドジョブ |
| filter_service.rb | `app/services/contacts/filter_service.rb` | サービス | 連絡先のフィルタリング |
| account_notification_mailer.rb | `app/mailers/administrator_notifications/account_notification_mailer.rb` | メーラー | エクスポート完了通知メール |
| contact.rb | `app/models/contact.rb` | モデル | 連絡先モデル |
| account.rb | `app/models/account.rb` | モデル | アカウントモデル（contacts_export添付ファイル） |
