# 画面設計書 12-ラベル別会話一覧

## 概要

本ドキュメントは、Chatwootのラベル別会話一覧画面の設計仕様を記述したものです。特定のラベルが付与された会話のみを表示する、フィルタリングされた会話一覧画面です。

### 本画面の処理概要

**業務上の目的・背景**：
ラベルは会話を分類・整理するための重要な機能です。エージェントやチームは、特定のカテゴリ（例：「重要」「フォローアップ」「技術サポート」など）に分類された会話だけを集中的に処理したい場合があります。ラベル別会話一覧は、このような業務ニーズに応え、効率的な会話管理を実現します。

**画面へのアクセス方法**：
1. サイドバーのラベル一覧から特定のラベルをクリック
2. URL直接アクセス: `/app/accounts/:accountId/label/:label`

**主要な操作・処理内容**：
1. ラベルでフィルタリングされた会話一覧の表示
2. 担当者タブ（自分/未割り当て/すべて）による追加フィルタリング
3. ステータスフィルター（Open/Resolved/Pending/Snoozed）による絞り込み
4. 会話の選択と詳細表示
5. 一括操作（複数会話のステータス変更、割り当て変更など）
6. 会話の検索
7. 高度なフィルター機能

**画面遷移**：
- 遷移元: ダッシュボードホーム画面（サイドバーのラベルリンク）
- 遷移先: 会話詳細画面（会話クリック時）

**権限による表示制御**：
- administrator: 全機能へのフルアクセス
- agent: 基本的な会話閲覧・操作
- conversation_manage: 会話の管理操作が可能
- conversation_unassigned_manage: 未割り当て会話タブの表示
- conversation_participating_manage: 参加中会話の管理

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 会話CRUD | 主機能 | 特定ラベルの会話一覧表示 |
| 78 | ラベル作成・管理 | 補助機能 | ラベルによるフィルタリング |

## 画面種別

一覧

## URL/ルーティング

| ルート名 | パス | 説明 |
|---------|------|------|
| label_conversations | `/accounts/:accountId/label/:label` | ラベル別会話一覧（詳細なし） |
| conversations_through_label | `/accounts/:accountId/label/:label/conversations/:conversation_id` | ラベル別会話一覧（詳細あり） |

## 入出力項目

### ルートパラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| accountId | Number | Yes | アカウントID |
| label | String | Yes | フィルタリング対象のラベル名 |
| conversation_id | Number | No | 表示する会話ID（詳細表示時） |

### コンポーネントProps

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| label | String | Yes | フィルタリング用ラベル名 |
| conversationId | String/Number | No | 選択中の会話ID |

## 表示項目

### ヘッダー部

| 項目名 | 型 | 説明 |
|--------|-----|------|
| page_title | String | 「#ラベル名」形式でラベル名を表示 |
| conversation_count | Number | フィルタリング結果の会話数 |
| filter_button | Button | 高度なフィルターモーダル表示ボタン |

### 会話一覧

| 項目名 | 型 | 説明 |
|--------|-----|------|
| conversation_card | Component | 会話カード（ConversationItem） |
| inbox_icon | Icon | インボックスのアイコン |
| contact_name | String | 連絡先名 |
| last_message_preview | String | 最新メッセージのプレビュー |
| last_activity_time | DateTime | 最終活動時刻 |
| unread_count | Number | 未読メッセージ数 |
| labels | Array | 付与されているラベル一覧 |
| assignee_avatar | Image | 担当者アバター |

### 担当者タブ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| me_tab | Tab | 自分に割り当てられた会話 |
| unassigned_tab | Tab | 未割り当ての会話 |
| all_tab | Tab | すべての会話 |
| tab_count | Number | 各タブの会話数 |

## イベント仕様

### 1-ラベル切り替え

**トリガー**: サイドバーで別のラベルをクリック

**処理フロー**:
1. Vue Routerでルートパラメータ変更を検知
2. ChatList.vueのwatchでlabel propsの変更を検知
3. resetAndFetchData()を呼び出し
4. 会話リストをクリアしてAPIから再取得
5. 新しいラベルでフィルタリングされた会話を表示

**Vuexアクション**: `fetchAllConversations`

### 2-会話選択

**トリガー**: 会話カードのクリック

**処理フロー**:
1. ConversationItemコンポーネントでクリックイベント発火
2. Vue Routerで`conversations_through_label`ルートへ遷移
3. ConversationView.vueのpropsが更新
4. setActiveChat()で選択会話をストアに設定
5. ConversationBox.vueで会話詳細を表示

### 3-担当者タブ切り替え

**トリガー**: 担当者タブのクリック

**処理フロー**:
1. ChatTypeTabs.vueでタブ選択イベント発火
2. activeAssigneeTabの更新
3. conversationFiltersの再計算
4. 必要に応じてfetchConversations()実行

### 4-無限スクロール

**トリガー**: 会話一覧の下部へのスクロール

**処理フロー**:
1. IntersectionObserverで監視
2. loadMoreConversations()を呼び出し
3. 次ページの会話をAPIから取得
4. 既存リストに追加

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 会話一覧取得 | conversations | SELECT | ラベルでフィルタリングした会話取得 |
| 会話一覧取得 | conversation_labels | SELECT | ラベルとの関連付け確認 |

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

#### conversations（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | labels[]にlabelパラメータを含む | APIでlabels配列を指定 |
| SELECT | status | フィルター条件 | ステータスフィルター |
| SELECT | assignee_id | フィルター条件 | 担当者フィルター |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| CHAT_LIST.LIST.404 | 情報 | 会話が見つかりません | フィルタリング結果が0件 |
| CHAT_LIST.EOF | 情報 | すべての会話を表示しました | リスト末尾到達時 |

## 例外処理

| 例外状態 | 表示内容 | 処理 |
|---------|---------|------|
| ラベルが存在しない | 空の会話一覧 | 404は表示せず空状態を表示 |
| 会話が0件 | 「会話が見つかりません」メッセージ | |
| ネットワークエラー | ローディング継続または再試行 | |

## 備考

- ラベル名はURLエンコードされてルートパラメータに渡される
- 複数ラベルの同時フィルタリングはこの画面では不可（高度なフィルターを使用）
- ラベル名に`#`プレフィックスを付けてページタイトルに表示

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversation.routes.js | `app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` | 行65-86でラベル関連ルートを確認 |

**読解のコツ**: label propsがどのようにルートパラメータから渡されるかを確認してください。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ConversationView.vue | `app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue` | 行39-42でlabel propsの定義を確認 |

**主要処理フロー**:
1. **行39-42**: label propsの定義（デフォルト空文字列）
2. **行199-208**: ChatListへのlabel propsの受け渡し

#### Step 3: フィルタリングロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ChatList.vue | `app/javascript/dashboard/components/ChatList.vue` | labelによるフィルタリング処理 |

**主要処理フロー**:
- **行78**: label propsの定義
- **行277-288**: conversationFiltersでlabelをフィルター条件に含める
- **行297-323**: pageTitleでラベル名を「#ラベル名」形式で表示
- **行876-879**: watch(label)で変更時にresetAndFetchData()呼び出し

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

```
ConversationView.vue
    |
    +-- ChatList.vue (label props受け渡し)
    |       |
    |       +-- conversationFilters (computed)
    |       |       labels: [props.label]
    |       |
    |       +-- fetchConversations()
    |               |
    |               +-- ConversationApi.get({ labels: [label] })
    |
    +-- ConversationBox.vue (選択時)
```

### データフロー図

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

URL params          --> Vue Router                --> ConversationView.vue
(/label/:label)         (route matching)              (label props)
                                                          |
                                                          v
                    --> ChatList.vue              --> conversationFilters
                        (label props)                 ({ labels: [label] })
                                                          |
                                                          v
                    --> ConversationApi.get()     --> API Request
                        ({ labels: [label] })         (GET /conversations?labels[]=label)
                                                          |
                                                          v
                    --> Vuex Store                --> 会話一覧表示
                        (allConversations)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ConversationView.vue | `app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue` | ソース | ルートコンポーネント |
| conversation.routes.js | `app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` | ソース | ラベルルート定義 |
| ChatList.vue | `app/javascript/dashboard/components/ChatList.vue` | ソース | 会話一覧・フィルタリング |
| conversation.js | `app/javascript/dashboard/api/inbox/conversation.js` | ソース | API（labels パラメータ対応） |
