# 画面設計書 27-検索画面

## 概要

本ドキュメントは、Chatwootの検索画面の設計仕様を記述したものである。

### 本画面の処理概要

検索画面は、会話、連絡先、メッセージ、記事を横断的に検索する機能を提供する画面である。

**業務上の目的・背景**：顧客サポート業務において、過去の対応履歴や顧客情報を迅速に検索することは効率的な対応に不可欠である。本画面により、オペレーターは単一の検索インターフェースから会話、連絡先、メッセージ内容、ヘルプセンター記事を横断的に検索でき、必要な情報に素早くアクセスできる。

**画面へのアクセス方法**：ダッシュボードのヘッダーにある検索ボックスをクリック、またはキーボードショートカット（Cmd/Ctrl + K）でアクセスする。URLは `/app/accounts/:accountId/search` の形式となる。

**主要な操作・処理内容**：
1. 検索クエリの入力
2. 検索タブの切り替え（全て、連絡先、会話、メッセージ、記事）
3. 検索結果の表示
4. 検索結果から各詳細画面への遷移
5. 高度な検索フィルタ（日付範囲、送信者、インボックスなど）
6. 追加結果の読み込み（Load More）

**画面遷移**：ダッシュボードの各画面からヘッダー経由でアクセス可能。検索結果をクリックすると対応する詳細画面（会話、連絡先、記事）に遷移する。

**権限による表示制御**：ロールと権限に応じて検索可能な対象が制限される。連絡先検索にはCONTACT_PERMISSIONS、会話検索にはCONVERSATION_PERMISSIONS、記事検索にはPORTAL_PERMISSIONSが必要。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 193 | 検索API | 主機能 | 会話・連絡先・記事の横断検索 |
| 194 | 検索サービス | 主機能 | 全文検索の実行 |
| 195 | 高度な検索 | 補助機能 | Searchkickによる高度な検索 |

## 画面種別

検索

## URL/ルーティング

| パス | ルート名 | 説明 |
|------|----------|------|
| `/app/accounts/:accountId/search` | search | 検索画面（全タブ） |
| `/app/accounts/:accountId/search/:tab` | search | 検索画面（特定タブ） |

## 入出力項目

### 入力項目

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| q | クエリパラメータ | 任意 | 検索キーワード |
| tab | パスパラメータ | 任意 | 検索タブ（all, contacts, conversations, messages, articles） |
| since | クエリパラメータ | 任意 | 検索開始日（高度な検索） |
| until | クエリパラメータ | 任意 | 検索終了日（高度な検索） |
| from | クエリパラメータ | 任意 | 送信者フィルタ（メッセージのみ） |
| inbox_id | クエリパラメータ | 任意 | インボックスフィルタ（メッセージのみ） |

### 出力項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| contactRecords | Array | 連絡先検索結果 |
| conversationRecords | Array | 会話検索結果 |
| messageRecords | Array | メッセージ検索結果 |
| articleRecords | Array | 記事検索結果 |

## 表示項目

### 検索ヘッダー

| 項目名 | 説明 |
|--------|------|
| 検索ボックス | 検索クエリ入力欄 |
| フィルタボタン | 高度な検索フィルタ（日付、送信者、インボックス） |
| 戻るボタン | 前の画面に戻る |

### 検索タブ

| タブ名 | 説明 | 権限 |
|--------|------|------|
| 全て（All） | 全種別の検索結果 | すべて |
| 連絡先（Contacts） | 連絡先検索結果 | CONTACT_PERMISSIONS |
| 会話（Conversations） | 会話検索結果 | CONVERSATION_PERMISSIONS |
| メッセージ（Messages） | メッセージ検索結果 | CONVERSATION_PERMISSIONS |
| 記事（Articles） | 記事検索結果 | PORTAL_PERMISSIONS（HELP_CENTER有効時） |

### 検索結果

| 項目名 | 説明 | 表示条件 |
|--------|------|----------|
| 連絡先カード | 連絡先の情報（名前、メール、電話） | 連絡先タブまたは全て |
| 会話カード | 会話の情報（件名、参加者、ステータス） | 会話タブまたは全て |
| メッセージカード | メッセージ内容と関連会話 | メッセージタブまたは全て |
| 記事カード | 記事タイトルと抜粋 | 記事タブまたは全て |

## イベント仕様

### 1-画面初期表示

画面マウント時、URLパラメータに検索クエリがあれば自動検索を実行。

**処理フロー**:
1. URLパラメータからq、フィルタ条件を取得
2. `parseURLParams`でフィルタを解析
3. qがあれば`onSearch`を実行
4. `agents/get`でエージェント一覧取得（フィルタ用）

### 2-検索実行

検索ボックスに入力して検索を実行する。

**処理フロー**:
1. `onSearch`を実行
2. `clearSearchResult`で前回結果をクリア
3. `updateURL`でURLを更新
4. `conversationSearch/fullSearch`を実行
5. 4種類の検索を並列実行（contactSearch, conversationSearch, messageSearch, articleSearch）

### 3-タブ切り替え

検索タブを切り替えて表示対象を変更する。

**処理フロー**:
1. `onTabChange`を実行
2. `selectedTab`を更新
3. `updateURL`でURLを更新
4. 表示するレコードをフィルタリング

### 4-追加読み込み

Load Moreボタンで追加結果を読み込む。

**処理フロー**:
1. `loadMore`を実行
2. 現在のタブのページを+1
3. 対応する検索アクション（contactSearch等）を実行
4. 結果をappend

### 5-検索結果クリック

検索結果をクリックして詳細画面に遷移する。

**処理フロー**:
1. 結果の種類に応じた画面に遷移
2. 連絡先→連絡先詳細、会話/メッセージ→会話詳細、記事→記事編集

### 6-フィルタ変更

高度な検索フィルタを変更する。

**処理フロー**:
1. `onFilterChange`を実行
2. フィルタ条件を更新
3. `onSearch`で再検索

### 7-戻る

戻るボタンで前の画面に戻る。

**処理フロー**:
1. `onBack`を実行
2. ブラウザ履歴があれば`router.go(-1)`
3. なければホーム画面に遷移
4. 検索結果をクリア

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 検索実行 | contacts, conversations, messages, articles | SELECT | 各種検索クエリ実行 |

### テーブル別更新項目詳細

#### contacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | 検索クエリに合致 | 全文検索 |

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | 検索クエリに合致 | 全文検索 |

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | 検索クエリに合致、from、inbox_id条件 | 全文検索 |

#### articles

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | 検索クエリに合致 | 全文検索 |

## メッセージ仕様

| 種別 | コード | メッセージ | 表示条件 |
|------|--------|-----------|----------|
| 情報 | SEARCH.EMPTY_STATE_DEFAULT | 検索キーワードを入力してください | 検索前 |
| 情報 | SEARCH.EMPTY_STATE_FULL | 「{query}」の検索結果が見つかりません | 検索結果0件 |
| ボタン | SEARCH.VIEW_MORE | もっと見る | 全てタブで5件以上ある場合 |
| ボタン | SEARCH.LOAD_MORE | さらに読み込む | 追加結果がある場合 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|---------|
| 検索結果0件 | 空状態メッセージを表示 |
| API通信エラー | ローディング状態を解除（エラーは無視） |
| 権限不足 | 対応するタブが非表示 |
| ヘルプセンター無効 | 記事タブが非表示 |

## 備考

- 全タブでは各種別最大5件を表示、View Moreで詳細タブに切り替え
- 高度な検索（ADVANCED_SEARCH）はフィーチャーフラグで制御
- 検索はAnalyticsでトラッキング（CONVERSATION_EVENTS.SEARCH_CONVERSATION）
- ページサイズは15件
- 記事検索はHELP_CENTERフィーチャーフラグが有効な場合のみ

---

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

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

### 推奨読解順序

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

まず、検索結果のデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversationSearch.js | `app/javascript/dashboard/store/modules/conversationSearch.js` | stateの構造（contactRecords, conversationRecords, messageRecords, articleRecords, uiFlags） |

**読解のコツ**: initialStateを見ることで、4種類の検索結果がそれぞれ別の配列で管理されていることがわかる。

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

処理の起点となるVueコンポーネントを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SearchView.vue | `app/javascript/dashboard/modules/search/components/SearchView.vue` | 画面のメインコンポーネント |

**主要処理フロー**:
1. **行43-49**: useMapGetterで4種類の検索結果を取得
2. **行92-119**: TABS_CONFIGでタブの権限設定を定義
3. **行248-269**: `buildSearchPayload`で検索パラメータ構築
4. **行288-297**: `onSearch`で検索実行
5. **行312-331**: `loadMore`で追加読み込み
6. **行338-352**: onMountedで初期処理

#### Step 3: Vuexストアアクションを理解する

検索のビジネスロジックを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | conversationSearch.js | `app/javascript/dashboard/store/modules/conversationSearch.js` | fullSearch, contactSearch, conversationSearch, messageSearch, articleSearchアクション |

**主要処理フロー**:
- **行60-84**: `fullSearch`アクションで4種類の検索を並列実行
- **行85-96**: `contactSearch`で連絡先検索
- **行97-108**: `conversationSearch`で会話検索
- **行109-120**: `messageSearch`でメッセージ検索
- **行121-132**: `articleSearch`で記事検索

#### Step 4: APIレイヤーを理解する

バックエンドとの通信処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | search.js | `app/javascript/dashboard/api/search.js` | contacts, conversations, messages, articlesメソッド |

**主要処理フロー**:
- **行17-26**: `contacts`メソッドで連絡先検索
- **行28-37**: `conversations`メソッドで会話検索
- **行39-50**: `messages`メソッドでメッセージ検索（from, inboxIdフィルタ対応）
- **行52-61**: `articles`メソッドで記事検索

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

```
SearchView.vue (View層)
    │
    ├─ onMounted
    │      ├─ parseURLParams (フィルタ解析)
    │      └─ onSearch (qパラメータがあれば)
    │
    ├─ onSearch (検索実行)
    │      ├─ clearSearchResult
    │      ├─ updateURL
    │      └─ store.dispatch('conversationSearch/fullSearch')
    │             │
    │             ├─ contactSearch
    │             │      └─ SearchAPI.contacts()
    │             ├─ conversationSearch
    │             │      └─ SearchAPI.conversations()
    │             ├─ messageSearch
    │             │      └─ SearchAPI.messages()
    │             └─ articleSearch
    │                    └─ SearchAPI.articles()
    │
    ├─ onTabChange (タブ切り替え)
    │      └─ updateURL
    │
    ├─ loadMore (追加読み込み)
    │      └─ store.dispatch('conversationSearch/[type]Search')
    │
    └─ onBack (戻る)
           ├─ router.go(-1) または router.push({ name: 'home' })
           └─ clearSearchResult
```

### データフロー図

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

q (クエリ) ─────────────▶ fullSearch
フィルタ                       │
                               ├─ contactSearch ───▶ contactRecords
                               ├─ conversationSearch ───▶ conversationRecords
                               ├─ messageSearch ───▶ messageRecords
                               └─ articleSearch ───▶ articleRecords
                                                            │
                                                            ▼
                                                     タブに応じて表示
                                                     ├─ SearchResultContactsList
                                                     ├─ SearchResultConversationsList
                                                     ├─ SearchResultMessagesList
                                                     └─ SearchResultArticlesList
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SearchView.vue | `app/javascript/dashboard/modules/search/components/SearchView.vue` | ソース | メイン画面コンポーネント |
| SearchHeader.vue | `app/javascript/dashboard/modules/search/components/SearchHeader.vue` | ソース | 検索ヘッダーコンポーネント |
| SearchTabs.vue | `app/javascript/dashboard/modules/search/components/SearchTabs.vue` | ソース | 検索タブコンポーネント |
| SearchResultContactsList.vue | `app/javascript/dashboard/modules/search/components/SearchResultContactsList.vue` | ソース | 連絡先結果コンポーネント |
| SearchResultConversationsList.vue | `app/javascript/dashboard/modules/search/components/SearchResultConversationsList.vue` | ソース | 会話結果コンポーネント |
| SearchResultMessagesList.vue | `app/javascript/dashboard/modules/search/components/SearchResultMessagesList.vue` | ソース | メッセージ結果コンポーネント |
| SearchResultArticlesList.vue | `app/javascript/dashboard/modules/search/components/SearchResultArticlesList.vue` | ソース | 記事結果コンポーネント |
| conversationSearch.js | `app/javascript/dashboard/store/modules/conversationSearch.js` | ソース | Vuexストア |
| search.js | `app/javascript/dashboard/api/search.js` | ソース | 検索API |
| searchHelper.js | `app/javascript/dashboard/modules/search/helpers/searchHelper.js` | ソース | URL/フィルタヘルパー |
| permissions.js | `app/javascript/dashboard/constants/permissions.js` | ソース | 権限定数 |
| featureFlags.js | `app/javascript/dashboard/featureFlags.js` | ソース | フィーチャーフラグ |
