# 機能設計書 56-連絡先検索・フィルタリング

## 概要

本ドキュメントは、Chatwootにおける連絡先の検索およびフィルタリング機能について記述する。本機能は、大量の連絡先データから条件に合致する連絡先を効率的に抽出するための検索・フィルタリング機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：カスタマーサポートにおいて、特定の条件に合致する顧客を素早く見つけることは業務効率化に不可欠である。名前やメールアドレスでの検索、カスタム属性によるセグメント分け、アクティブな顧客の抽出など、多様な条件での連絡先絞り込みが必要となる。

**機能の利用シーン**：
- 顧客名やメールアドレスで特定の連絡先を検索する
- カスタム属性（会員ランク、地域等）で連絡先をセグメント分けする
- 最近アクティブな連絡先を抽出する
- ラベルによる連絡先のグルーピング
- カスタムフィルタによる複合条件での絞り込み

**主要な処理内容**：
1. 検索クエリによる連絡先検索（ILIKE検索）
2. フィルタ条件による連絡先抽出（FilterService）
3. オンライン連絡先の抽出（アクティブ連絡先）
4. ソート機能（名前、メール、作成日時、最終アクティビティ等）
5. ページネーション処理

**関連システム・外部連携**：OnlineStatusTrackerによるリアルタイムオンライン状態の取得。

**権限による制御**：連絡先の検索・フィルタリングはエージェント権限以上が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | 連絡先一覧画面 | 主画面 | 連絡先の検索とフィルタリング |
| 21 | セグメント別連絡先一覧 | 主画面 | カスタムフィルタによる表示 |
| 22 | ラベル別連絡先一覧 | 主画面 | ラベルによるフィルタリング |
| 23 | アクティブ連絡先一覧 | 主画面 | アクティブ連絡先の表示 |

## 機能種別

検索・フィルタリング

## 入力仕様

### 入力パラメータ（検索）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| q | String | Yes | 検索クエリ文字列 | 空でないこと |

### 入力パラメータ（フィルタ）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| payload | Array | Yes | フィルタ条件の配列 | 有効なフィルタ構造 |
| labels | Array | No | ラベルによるフィルタ | - |

### 入力パラメータ（共通）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| page | Integer | No | ページ番号 | デフォルト: 1 |
| sort | String | No | ソートカラム | 許可されたカラム名 |
| order | String | No | ソート順 | asc/desc |

### 入力データソース

- 管理画面の検索フォーム
- APIリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| contacts | Array | 連絡先の配列 |
| contacts_count | Integer | 総件数 |
| has_more | Boolean | 次ページの有無（検索時） |

### 出力先

- API レスポンス

## 処理フロー

### 処理シーケンス（検索）

```
1. 検索リクエスト受信
   └─ qパラメータを取得
2. 検索クエリ構築
   └─ name, email, phone_number, identifierでILIKE検索
3. ソート・ページネーション適用
   └─ Siftによるソート、Kaminariによるページネーション
4. 結果返却
   └─ has_moreフラグ付きで返却
```

### 処理シーケンス（フィルタ）

```
1. フィルタリクエスト受信
   └─ payloadパラメータを取得
2. FilterService初期化
   └─ フィルタ条件をパース
3. クエリビルダー実行
   └─ 条件に基づくSQLクエリ構築
4. ソート・ページネーション適用
5. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[検索/フィルタリクエスト] --> B{検索 or フィルタ?}
    B -->|検索| C[ILIKEクエリ構築]
    B -->|フィルタ| D[FilterService#perform]
    C --> E[ソート適用]
    D --> E
    E --> F[ページネーション適用]
    F --> G[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-56-01 | 検索対象フィールド | name, email, phone_number, identifierを対象 | 検索時 |
| BR-56-02 | ILIKE検索 | 大文字小文字を区別しない部分一致検索 | 検索時 |
| BR-56-03 | 解決済み連絡先 | indexはresolved_contactsのみ対象 | 一覧取得時 |
| BR-56-04 | ページサイズ | 15件/ページ固定 | 全アクション |
| BR-56-05 | フィルタ演算子 | equal_to, not_equal_to, contains等をサポート | フィルタ時 |

### ソート可能カラム

| カラム名 | 内部名 | 説明 |
|----------|--------|------|
| email | email | メールアドレス順 |
| name | order_on_name | 名前順（特殊文字対応） |
| phone_number | phone_number | 電話番号順 |
| last_activity_at | order_on_last_activity_at | 最終アクティビティ順 |
| created_at | order_on_created_at | 作成日時順 |
| company | order_on_company_name | 会社名順 |
| city | order_on_city | 市区町村順 |
| country | order_on_country_name | 国名順 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 検索 | contacts | SELECT | 条件に合致する連絡先を取得 |
| フィルタ | contacts | SELECT | フィルタ条件で連絡先を取得 |
| アクティブ取得 | contacts | SELECT | オンライン連絡先を取得 |

### 使用インデックス

| インデックス名 | 用途 |
|---------------|------|
| index_contacts_on_name_email_phone_number_identifier | 検索用GINインデックス |
| index_contacts_on_account_id_and_last_activity_at | アクティビティ順ソート |
| index_contacts_on_lower_email_account_id | メール検索 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 422 | バリデーションエラー | 検索クエリが空 | エラーメッセージを返却 |
| 422 | 無効な属性 | フィルタの属性が存在しない | エラーメッセージを返却 |
| 422 | 無効な演算子 | フィルタの演算子が無効 | エラーメッセージを返却 |
| 422 | 無効なクエリ演算子 | AND/OR以外のクエリ演算子 | エラーメッセージを返却 |
| 422 | 無効な値 | フィルタの値が不正 | エラーメッセージを返却 |

### リトライ仕様

なし（同期処理）

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

読み取り専用のためトランザクション管理は不要。

## パフォーマンス要件

- GINインデックスにより検索は高速（100ms以内目標）
- ページネーションにより大量データでも効率的
- N+1問題を避けるためincludesで関連データをプリロード

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

- SQLインジェクション対策としてパラメータバインディングを使用
- アカウント単位でのスコープ制限

## 備考

- Sift gemを使用してソート機能を実装
- Kaminari gemを使用してページネーションを実装

---

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

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

### 推奨読解順序

#### Step 1: コントローラーの検索・フィルタアクションを理解する

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

**主要処理フロー**:
- **24-32行目**: searchアクションでILIKE検索を実行
- **52-58行目**: activeアクションでオンライン連絡先を取得
- **62-72行目**: filterアクションでFilterServiceを使用

**読解のコツ**: Sift gemの`sort_on`定義（2-10行目）でソート可能なカラムとその内部実装を確認できる。

#### Step 2: フィルタサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | filter_service.rb | `app/services/contacts/filter_service.rb` | フィルタ条件のパースとクエリ構築 |

**主要処理フロー**:
- **1行目**: FilterServiceを継承
- **11-18行目**: performメソッドでフィルタを実行
- **32-34行目**: base_relationでresolved_contactsを取得

#### Step 3: 連絡先モデルのスコープを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | contact.rb | `app/models/contact.rb` | order_on_*スコープの定義 |

**主要処理フロー**:
- **73-132行目**: 各種order_on_*スコープの定義
- **181-185行目**: resolved_contacts scopeの定義

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

```
Api::V1::Accounts::ContactsController
    │
    ├─ #search
    │      └─ ILIKE検索クエリ構築
    │             └─ fetch_contacts_with_has_more
    │
    ├─ #filter
    │      └─ Contacts::FilterService#perform
    │             └─ query_builder (条件構築)
    │
    └─ #active
           └─ OnlineStatusTracker.get_available_contact_ids
                  └─ fetch_contacts
```

### データフロー図

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

検索クエリq     ───▶ ILIKE検索          ───▶ contacts + has_more
                     name/email/phone/identifier

フィルタpayload ───▶ FilterService       ───▶ contacts + count
                     条件解析・クエリ構築

アクティブ要求  ───▶ OnlineStatusTracker ───▶ オンライン連絡先
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contacts_controller.rb | `app/controllers/api/v1/accounts/contacts_controller.rb` | コントローラー | 検索・フィルタAPIエンドポイント |
| filter_service.rb | `app/services/contacts/filter_service.rb` | サービス | フィルタ条件処理 |
| contact.rb | `app/models/contact.rb` | モデル | order_on_*スコープ定義 |
| online_status_tracker.rb | `app/services/online_status_tracker.rb` | サービス | オンライン状態追跡 |
