# 画面設計書 83-エージェント割り当て編集

## 概要

本ドキュメントは、Chatwootのエージェント割り当てポリシー編集画面の設計を記述したものです。この画面では、既存のエージェント割り当てポリシーの設定変更およびインボックスの紐づけ管理を行います。

### 本画面の処理概要

**業務上の目的・背景**：作成済みの割り当てポリシーの設定を変更し、適用対象のインボックスを管理します。ポリシーとインボックスを紐づけることで、そのインボックスに届く会話に対して自動割り当てルールが適用されるようになります。

**画面へのアクセス方法**：エージェント割り当て一覧画面から各ポリシーカードの編集ボタンをクリック、または新規作成完了後に自動遷移でアクセスします。URLパスは `/app/accounts/:accountId/settings/assignment-policy/assignment/edit/:id` です。

**主要な操作・処理内容**：
1. ポリシー基本情報（名前、説明、ステータス）の編集
2. 割り当て順序・会話優先度の変更
3. 公平分配設定の変更
4. インボックスの追加（ポリシーへの紐づけ）
5. インボックスの削除（ポリシーからの紐づけ解除）
6. 設定変更の保存

**画面遷移**：
- 遷移元：エージェント割り当て一覧画面、エージェント割り当て作成画面（作成成功時）
- 遷移先：パンくずリストからエージェント割り当て一覧画面

**権限による表示制御**：管理者（administrator）ロールのユーザーのみがアクセス可能です。ASSIGNMENT_V2フィーチャーフラグが有効な場合にのみ表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 割り当てポリシー | 主機能 | 割り当てルールの編集 |

## 画面種別

編集

## URL/ルーティング

- **パス**: `/app/accounts/:accountId/settings/assignment-policy/assignment/edit/:id`
- **ルート名**: `agent_assignment_policy_edit`
- **パラメータ**: id（ポリシーID）

## 入出力項目

### 入力項目（フォーム）

| 項目名 | データ型 | 必須 | 初期値 | バリデーション | 説明 |
|--------|----------|------|--------|----------------|------|
| name | String | 必須 | 既存値 | 空でないこと | ポリシー名 |
| description | String | 任意 | 既存値 | なし | ポリシーの説明 |
| enabled | Boolean | 必須 | 既存値 | なし | 有効/無効状態 |
| assignmentOrder | String | 必須 | 既存値 | round_robin/balanced | 割り当て順序 |
| conversationPriority | String | 必須 | 既存値 | earliest_created/longest_waiting | 会話優先度 |
| fairDistributionLimit | Number | 必須 | 既存値 | 正の整数 | 公平分配制限値 |
| fairDistributionWindow | Number | 必須 | 既存値 | 正の整数（秒） | 公平分配ウィンドウ |

### インボックス管理

| 操作 | データ型 | 説明 |
|------|----------|------|
| インボックス追加 | Object | インボックスIDとポリシーIDの紐づけ |
| インボックス削除 | Number | インボックスIDの紐づけ解除 |

## 表示項目

### 基本情報セクション

作成画面と同一のフォームフィールドを表示（初期値は既存データ）

### インボックスセクション（showInboxSection=true）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| セクションタイトル | ラベル | 「インボックス」 |
| セクション説明 | テキスト | インボックス紐づけの説明 |
| 追加ボタン | ドロップダウン付きボタン | インボックス一覧から選択して追加 |
| インボックス一覧 | データテーブル | 紐づけ済みインボックスの一覧（削除ボタン付き） |

## イベント仕様

### 1-画面マウント/ルートID変更

watchでrouteIdの変化を監視し、以下を実行：
1. ポリシーがストアにない場合、`assignmentPolicies/show`でフェッチ
2. `assignmentPolicies/getInboxes`で紐づきインボックスを取得

### 2-フォーム送信

1. Vuex Action `assignmentPolicies/update` を実行
2. 成功時：成功メッセージを表示
3. 失敗時：エラーメッセージを表示

### 3-インボックス追加

1. `assignmentPolicies/getInboxPolicy`で対象インボックスの既存ポリシー確認
2. 既に別ポリシーに紐づいている場合：ConfirmInboxDialogで確認
3. 確認後、`assignmentPolicies/setInboxPolicy`を実行
4. 成功時：インボックス一覧を再取得

### 4-インボックス削除

1. `assignmentPolicies/removeInboxPolicy`を実行
2. Vuex Stateから該当インボックスを削除

### 5-パンくずリストクリック

パンくずリストの「エージェント割り当て」クリック時、一覧画面に遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | assignment_policies | SELECT | ポリシー情報取得 |
| 画面表示 | inboxes | SELECT | 紐づきインボックス取得 |
| フォーム送信 | assignment_policies | UPDATE | ポリシー情報更新 |
| インボックス追加 | inboxes | UPDATE | assignment_policy_id設定 |
| インボックス削除 | inboxes | UPDATE | assignment_policy_idをnull |

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

#### assignment_policies

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | id = URLパラメータのid | 単一ポリシー取得 |
| UPDATE | name, description, enabled, assignment_order, conversation_priority, fair_distribution_limit, fair_distribution_window | フォーム入力値 | 部分更新 |

#### inboxes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | assignment_policy_id = ポリシーID | 紐づきインボックス |
| UPDATE | assignment_policy_id | 対象ポリシーID or null | 紐づけ/解除 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|----------|--------------|
| EDIT.API.SUCCESS_MESSAGE | 成功 | ポリシー更新成功時 | ポリシーが正常に更新されました |
| EDIT.API.ERROR_MESSAGE | エラー | ポリシー更新失敗時 | ポリシーの更新に失敗しました |
| FORM.INBOXES.API.SUCCESS_MESSAGE | 成功 | インボックス追加成功時 | インボックスが正常に追加されました |
| FORM.INBOXES.API.ERROR_MESSAGE | エラー | インボックス追加失敗時 | インボックスの追加に失敗しました |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| ポリシーが見つからない | ストアからフェッチ試行、失敗時はエラー |
| 名前が空 | 送信ボタンを無効化 |
| API呼び出し失敗 | エラーメッセージをアラート表示 |
| インボックスが既に別ポリシーに紐づき | 確認ダイアログを表示 |

## 備考

- インボックスは1つのポリシーにのみ紐づけ可能（排他）
- 既に別ポリシーに紐づいているインボックスを追加する場合、確認ダイアログで意図を確認
- 編集画面ではインボックスセクションが表示される（作成画面では非表示）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | assignmentPolicies.js | `app/javascript/dashboard/store/modules/assignmentPolicies.js` | getters（getAssignmentPolicyById）、actions（show, update, getInboxes, setInboxPolicy） |

**読解のコツ**: 編集画面特有のアクション（show, update, インボックス関連）に注目

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AgentAssignmentEditPage.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/AgentAssignmentEditPage.vue` | watchによるデータフェッチ、formData computed、インボックス操作 |

**主要処理フロー**:
1. **行32-33**: routeIdとselectedPolicyのcomputed定義
2. **行66-75**: formDataの構築（既存値をフォームに反映）
3. **行155-166**: fetchPolicyDataでポリシーとインボックスをフェッチ
4. **行143-153**: handleSubmitでupdateアクションをディスパッチ
5. **行104-123**: handleAddInboxでインボックス追加処理
6. **行77-81**: handleDeleteInboxでインボックス削除処理

#### Step 3: インボックス確認ダイアログを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ConfirmInboxDialog.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/components/ConfirmInboxDialog.vue` | 既存紐づけインボックスの切り替え確認UI |

#### Step 4: フォームコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AgentAssignmentPolicyForm.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/components/AgentAssignmentPolicyForm.vue` | showInboxSection=true時のインボックスセクション表示（行227-255） |
| 4-2 | DataTable.vue | `app/javascript/dashboard/components-next/AssignmentPolicy/components/DataTable.vue` | インボックス一覧テーブル |
| 4-3 | AddDataDropdown.vue | `app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue` | インボックス追加ドロップダウン |

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

```
AgentAssignmentEditPage.vue (エントリーポイント)
    │
    ├─ watch(routeId) → fetchPolicyData
    │      ├─ assignmentPolicies/show（ポリシー未取得時）
    │      └─ assignmentPolicies/getInboxes
    │
    ├─ AgentAssignmentPolicyForm.vue
    │      │
    │      ├─ @submit → handleSubmit
    │      │      └─ assignmentPolicies/update
    │      │              └─ PUT /api/v1/accounts/:id/assignment_policies/:id
    │      │
    │      ├─ @add-inbox → handleAddInbox
    │      │      ├─ assignmentPolicies/getInboxPolicy
    │      │      │      └─ 既存紐づけ確認
    │      │      │
    │      │      └─ (紐づけあり) → ConfirmInboxDialog表示
    │      │              └─ @add → handleConfirmAddInbox
    │      │                      └─ assignmentPolicies/setInboxPolicy
    │      │
    │      └─ @delete-inbox → handleDeleteInbox
    │              └─ assignmentPolicies/removeInboxPolicy
    │
    └─ ConfirmInboxDialog.vue
```

### データフロー図

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

URL params.id ─────────▶ fetchPolicyData ──────────────▶
                              │
                              ▼
                      assignmentPolicies/show
                      assignmentPolicies/getInboxes
                              │
                              ▼
                      Vuex State更新
                              │
                              ▼
                      formData computed生成 ────────────▶ フォーム表示
                              │
フォーム入力 ─────────────────▶
                              │
                              ▼
                      @submit → handleSubmit
                              │
                              ▼
                      assignmentPolicies/update ────────▶ DB更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AgentAssignmentEditPage.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/AgentAssignmentEditPage.vue` | ソース | 編集ページコンポーネント |
| AgentAssignmentPolicyForm.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/components/AgentAssignmentPolicyForm.vue` | ソース | フォームコンポーネント |
| ConfirmInboxDialog.vue | `app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/components/ConfirmInboxDialog.vue` | ソース | インボックス確認ダイアログ |
| DataTable.vue | `app/javascript/dashboard/components-next/AssignmentPolicy/components/DataTable.vue` | ソース | データテーブル |
| AddDataDropdown.vue | `app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue` | ソース | 追加ドロップダウン |
| assignmentPolicies.js | `app/javascript/dashboard/store/modules/assignmentPolicies.js` | ソース | Vuexストア |
| assignmentPolicies.js | `app/javascript/dashboard/api/assignmentPolicies.js` | ソース | APIクライアント |
| assignment_policies_controller.rb | `app/controllers/api/v1/accounts/assignment_policies_controller.rb` | ソース | バックエンドコントローラー |
| inboxes_controller.rb | `app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb` | ソース | インボックス関連コントローラー |
