# 機能設計書 57-連絡先インポート・エクスポート

## 概要

本ドキュメントは、Chatwootにおける連絡先のCSVインポートおよびエクスポート機能について記述する。本機能は、外部システムからの連絡先データの一括取り込みや、分析・バックアップ目的での連絡先データの一括出力を行う機能である。

### 本機能の処理概要

**業務上の目的・背景**：カスタマーサポートにおいて、既存のCRMシステムや他のツールから連絡先データを移行したい場合、手動での入力は非効率である。また、連絡先データをExcelなどで分析したり、バックアップとして保存したい場合にエクスポート機能が必要となる。

**機能の利用シーン**：
- 既存システムから連絡先データをChatwootに移行する
- マーケティングキャンペーンのためのリードリストをインポートする
- 連絡先データをCSVでエクスポートして外部ツールで分析する
- 定期的なバックアップとして連絡先データをエクスポートする
- 特定のラベルやセグメントの連絡先のみをエクスポートする

**主要な処理内容**：
1. CSVファイルのアップロードとパース
2. 連絡先データのバリデーションと一括インポート
3. インポートエラーの記録と失敗レコードの出力
4. 連絡先データのCSV生成とダウンロード
5. 処理完了通知メールの送信

**関連システム・外部連携**：
- ActiveStorageによるファイル保存
- メール通知（インポート完了/失敗、エクスポート完了）

**権限による制御**：インポート・エクスポートは管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | 連絡先一覧画面 | 主画面 | インポート・エクスポートの実行 |

## 機能種別

データ連携 / バルク操作

## 入力仕様

### 入力パラメータ（インポート）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| import_file | File | Yes | CSVファイル | CSV形式、UTF-8エンコーディング推奨 |

### 入力パラメータ（エクスポート）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| column_names | Array | No | 出力カラム名 | Contactの有効なカラム名 |
| payload | Object | No | フィルタ条件 | - |
| label | String | No | ラベルフィルタ | - |

### CSVファイルフォーマット（インポート）

| カラム名 | 必須 | 説明 |
|----------|------|------|
| name | No | 連絡先名 |
| email | No | メールアドレス |
| phone_number | No | 電話番号（E.164形式） |
| identifier | No | 外部識別子 |
| custom_attributes.* | No | カスタム属性（プレフィックス付き） |

### 入力データソース

- 管理画面からのファイルアップロード
- APIリクエスト

## 出力仕様

### 出力データ（インポート）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| status | String | 処理ステータス（pending/processing/completed/failed） |
| processed_records | Integer | 処理成功件数 |
| total_records | Integer | 総件数 |
| failed_records | File | 失敗レコードのCSV |

### 出力データ（エクスポート）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| csv_file | File | エクスポートされたCSVファイル |
| download_url | String | ダウンロードURL |

### 出力先

- data_importsテーブル（インポートステータス）
- accounts.contacts_export（エクスポートファイル）
- メール通知

## 処理フロー

### 処理シーケンス（インポート）

```
1. ファイルアップロード
   └─ CSVファイルをActiveStorageに保存
2. DataImportレコード作成
   └─ status: pending で作成
3. 非同期ジョブ投入
   └─ DataImportJob を1分後に実行
4. CSVパース
   └─ UTF-8変換、ヘッダー解析
5. 連絡先検証・作成
   └─ 各行をパースしてContactを作成
6. バルクインポート実行
   └─ Contact.import で一括挿入
7. 失敗レコード保存
   └─ エラーのあった行をCSVで保存
8. 完了通知
   └─ 管理者にメール通知
```

### 処理シーケンス（エクスポート）

```
1. エクスポートリクエスト
   └─ フィルタ条件、カラム名を受け取る
2. 非同期ジョブ投入
   └─ ContactsExportJob を実行
3. 対象連絡先取得
   └─ フィルタ条件に基づいて取得
4. CSV生成
   └─ 指定カラムでCSVを生成
5. ファイル保存
   └─ ActiveStorageに添付
6. 完了通知
   └─ ダウンロードURLをメールで送信
```

### フローチャート（インポート）

```mermaid
flowchart TD
    A[CSVアップロード] --> B[DataImport作成]
    B --> C[DataImportJob投入]
    C --> D[CSVパース]
    D --> E{パース成功?}
    E -->|No| F[status: failed]
    E -->|Yes| G[連絡先検証]
    G --> H[バルクインポート]
    H --> I[失敗レコード保存]
    I --> J[status: completed]
    F --> K[失敗通知メール]
    J --> L[完了通知メール]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | ファイル必須 | インポート時はCSVファイルが必須 | インポート時 |
| BR-57-02 | UTF-8変換 | 非UTF-8ファイルは自動変換を試みる | インポート時 |
| BR-57-03 | 重複スキップ | 既存の連絡先（email/phone_number/identifier）は重複スキップ | インポート時 |
| BR-57-04 | バッチサイズ | 1000件単位でバルクインポート | インポート時 |
| BR-57-05 | 1分遅延 | ファイルアップロード完了を待つため1分後に処理開始 | インポート時 |
| BR-57-06 | デフォルトカラム | カラム未指定時はid, name, email, phone_number | エクスポート時 |
| BR-57-07 | 有効カラムのみ | Contact.column_namesに存在するカラムのみ出力 | エクスポート時 |

### data_importステータス

| 値 | 名称 | 説明 |
|----|------|------|
| 0 | pending | 処理待ち |
| 1 | processing | 処理中 |
| 2 | completed | 完了 |
| 3 | failed | 失敗 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| インポート | data_imports | INSERT | インポート管理レコード作成 |
| インポート | contacts | INSERT | 連絡先一括挿入 |
| エクスポート | contacts | SELECT | 連絡先データ取得 |

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

#### data_imports

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | account_id | Current.accountのID | 必須 |
| INSERT | data_type | 'contacts' | 固定値 |
| INSERT | status | 0（pending） | 初期値 |
| UPDATE | status | 1（processing） | 処理開始時 |
| UPDATE | status | 2（completed）または3（failed） | 処理完了時 |
| UPDATE | processed_records | 成功件数 | 処理完了時 |
| UPDATE | total_records | 総件数 | 処理完了時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 422 | ファイル未指定 | import_fileパラメータなし | エラーメッセージを返却 |
| - | CSVパースエラー | 不正なCSV形式 | status: failedで管理者に通知 |
| - | バリデーションエラー | 連絡先データ不正 | 失敗レコードCSVに記録 |

### リトライ仕様

- ActiveStorage::FileNotFoundError時は1分間隔で最大3回リトライ

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

DataImport作成とファイル添付はトランザクションでラップ。連絡先インポートは一括挿入で実行。

## パフォーマンス要件

- バッチサイズ1000件で効率的な一括挿入
- 非同期処理によりUIはブロックされない
- 大量データの場合はlow優先度キューで実行

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

- インポートファイルは一時保存後に処理
- エクスポートURLは時限付きでアクセス制限
- 管理者権限のみがインポート・エクスポート可能

## 備考

- activerecord-import gemを使用して高速な一括挿入を実現
- on_duplicate_key_ignore: trueで重複時はスキップ
- エクスポートはlow優先度キューで実行

---

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

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

### 推奨読解順序

#### Step 1: コントローラーのインポート・エクスポートアクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | contacts_controller.rb | `app/controllers/api/v1/accounts/contacts_controller.rb` | import, exportアクション |

**主要処理フロー**:
- **34-43行目**: importアクションでDataImport作成
- **45-49行目**: exportアクションでContactsExportJob投入

#### Step 2: DataImportモデルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | data_import.rb | `app/models/data_import.rb` | インポートステータス管理 |

**主要処理フロー**:
- **21行目**: data_typeバリデーション（'contacts'のみ）
- **22行目**: status enum定義
- **24-25行目**: ActiveStorage添付ファイル
- **31-33行目**: after_create_commitでDataImportJob投入

#### Step 3: インポートジョブを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | data_import_job.rb | `app/jobs/data_import_job.rb` | CSVパースと連絡先インポート処理 |

**主要処理フロー**:
- **6行目**: FileNotFoundErrorのリトライ設定
- **21-28行目**: process_import_fileでインポート実行
- **53-56行目**: Contact.importで一括挿入

#### Step 4: エクスポートジョブを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | CSV生成とファイル保存 |

**主要処理フロー**:
- **16-25行目**: generate_csvでCSV生成
- **27-36行目**: contactsでフィルタ条件を適用
- **42-50行目**: attach_export_fileでActiveStorageに添付

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

```
Api::V1::Accounts::ContactsController
    │
    ├─ #import
    │      └─ DataImport.create!
    │             └─ after_create_commit
    │                    └─ DataImportJob.set(wait: 1.minute).perform_later
    │                           ├─ CSVパース
    │                           ├─ Contact.import (一括挿入)
    │                           └─ 管理者通知メール
    │
    └─ #export
           └─ Account::ContactsExportJob.perform_later
                  ├─ CSV生成
                  ├─ ActiveStorage添付
                  └─ ダウンロードURLメール送信
```

### データフロー図

```
[インポート]
CSVファイル ───▶ DataImport ───▶ DataImportJob ───▶ contacts テーブル
                ActiveStorage         │
                                       ▼
                              失敗レコードCSV + 通知メール

[エクスポート]
フィルタ条件 ───▶ ContactsExportJob ───▶ CSVファイル ───▶ 通知メール
                       │                 ActiveStorage
                       ▼
                 contacts取得
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contacts_controller.rb | `app/controllers/api/v1/accounts/contacts_controller.rb` | コントローラー | import/exportエンドポイント |
| data_import.rb | `app/models/data_import.rb` | モデル | インポート管理 |
| data_import_job.rb | `app/jobs/data_import_job.rb` | ジョブ | インポート処理 |
| contacts_export_job.rb | `app/jobs/account/contacts_export_job.rb` | ジョブ | エクスポート処理 |
