# 画面設計書 60-チームメンバー編集画面

## 概要

本ドキュメントは、Chatwootのチームメンバー編集画面の設計書です。既存チームのメンバー（エージェント）を編集する画面です。

### 本画面の処理概要

既存チームのメンバー構成を編集する画面です。現在のメンバーが選択済みの状態で表示され、追加・削除が可能です。

**業務上の目的・背景**：チームメンバーの異動や退職、新規加入に対応するため、チームに所属するエージェントを変更する必要があります。この画面により、チームの人員構成を柔軟に管理できます。

**画面へのアクセス方法**：チーム編集画面でチーム基本情報更新後に自動遷移

**主要な操作・処理内容**：
1. 現在のチームメンバーを選択済みで表示
2. エージェント一覧から追加・削除
3. 全選択機能
4. 更新ボタンでメンバー一覧を更新して完了画面へ遷移

**画面遷移**：
- 遷移元: チーム編集画面（EditTeam）
- 遷移先: チーム設定完了画面（settings_teams_edit_finish）

**権限による表示制御**：管理者（administrator）のみがこの画面にアクセス可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | チーム管理 | 主機能 | チームメンバーの編集 |

## 画面種別

編集（ウィザード形式の第2ステップ）

## URL/ルーティング

- パス: `/app/accounts/:accountId/settings/teams/:teamId/edit/agents`
- ルート名: `settings_teams_edit_members`
- 権限: administrator

## 入出力項目

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| selectedAgents | Array<Number> | Yes | 選択されたエージェントIDのリスト |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|------|------|
| agentList | Array<Agent> | 全エージェント一覧 |
| teamMembers | Array<Agent> | 現在のチームメンバー（初期選択用） |
| agent.id | Number | エージェントID |
| agent.name | String | エージェント名 |
| agent.email | String | メールアドレス |
| agent.thumbnail | String | アバター画像URL |
| agent.availability_status | String | オンライン状態 |
| selectedAgentCount | Number | 選択済みエージェント数 |
| currentTeam.name | String | 現在のチーム名（ヘッダー表示用） |

## イベント仕様

### 1-エージェント選択（handleSelectAgent）

**トリガー**: エージェント行のチェックボックスをクリック

**処理フロー**:
1. 既に選択済みかどうかを判定（`isAgentSelected`）
2. 選択済みの場合: `selectedAgents`から削除
3. 未選択の場合: `selectedAgents`に追加
4. `updateSelectedAgents()`で親コンポーネントへ通知

### 2-フォーム送信（addAgents）

**トリガー**: 「更新」ボタン押下

**処理フロー**:
1. `isCreating`フラグをtrueに設定
2. `store.dispatch('teamMembers/update', { teamId, agentsList })`を実行
3. 成功時: `settings_teams_edit_finish`へ遷移、チーム一覧を再取得
4. 失敗時: エラーメッセージをアラート表示
5. `isCreating`フラグをfalseに設定

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| メンバー更新 | team_members | UPDATE（全置換） | チームメンバーを更新 |

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

#### team_members

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | team_id | URLパラメータのteamId | 既存メンバーを削除 |
| INSERT | team_id | URLパラメータのteamId | 新しいメンバーを追加 |
| INSERT | user_id | 選択されたエージェントのID | 複数レコード |

## メッセージ仕様

| 種別 | キー | 表示条件 | メッセージ内容 |
|------|------|----------|--------------|
| エラー | TEAMS_SETTINGS.ADD.AGENT_VALIDATION_ERROR | エージェント未選択時 | エージェント選択必須エラー |
| エラー | error.message | API呼び出し失敗時 | サーバーから返されたエラーメッセージ |
| 情報 | TEAMS_SETTINGS.AGENTS.SELECTED_COUNT | 常時（フッター） | 選択数 / 総数 |

## 例外処理

| 例外状況 | 対応処理 |
|----------|----------|
| エージェント未選択 | バリデーションエラーメッセージを表示、送信ボタン無効化 |
| API通信エラー | `useAlert(error.message)`でエラーメッセージをトースト表示 |
| チームメンバーデータ未取得 | Spinnerコンポーネントを表示 |
| 権限不足 | ルートガードにより画面アクセス自体をブロック |

## 備考

- AgentSelectorコンポーネントを使用（チーム作成・編集共通）
- マウント時に現在のチームメンバーを取得し、選択済み状態に設定
- `teamMembers/update`アクションはPATCHリクエストで全メンバーを置換
- showAgentsList computedでエージェント一覧表示条件を制御

---

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

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

### 推奨読解順序

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

チームメンバーの取得・更新を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | teamMembers.js | `app/javascript/dashboard/store/modules/teamMembers.js` | get/updateアクション |
| 1-2 | teams.js | `app/javascript/dashboard/api/teams.js` | getAgents/updateAgents APIメソッド |

**読解のコツ**: `teamMembers/get`で現在のメンバーを取得し、`teamMembers/update`でPATCHリクエストを送信。

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

Vueコンポーネントの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EditAgents.vue | `app/javascript/dashboard/routes/dashboard/settings/teams/Edit/EditAgents.vue` | メインコンポーネント |
| 2-2 | AgentSelector.vue | `app/javascript/dashboard/routes/dashboard/settings/teams/AgentSelector.vue` | エージェント選択コンポーネント |

**主要処理フロー**:
1. **EditAgents L60-72**: マウント時にエージェント一覧とチームメンバーを取得
2. **EditAgents L67-68**: 既存メンバーを選択済み状態に設定
3. **EditAgents L79-100**: `addAgents()`メソッドでチームメンバー更新
4. **EditAgents L84-87**: ストアディスパッチでチームメンバー更新

#### Step 3: ルーティング設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | teams.routes.js | `app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js` | 編集ウィザードのルート定義 |

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

```
EditAgents.vue (コンポーネント)
    │
    ├─ mounted()
    │      ├─ store.dispatch('agents/get')
    │      │
    │      └─ store.dispatch('teamMembers/get', { teamId })
    │             └─ TeamsAPI.getAgents({ teamId })
    │                    │
    │                    ▼
    │             teamMembers (既存メンバー)
    │                    │
    │                    ▼
    │             updateSelectedAgents(memberIds)
    │             (選択済み状態に設定)
    │
    └─ AgentSelector.vue (子コンポーネント)
           │
           ├─ selectedAgents (選択済みエージェントID)
           │
           └─ submit
                  │
                  ▼
           addAgents() [EditAgents.vue]
                  │
                  ├─ store.dispatch('teamMembers/update', { teamId, agentsList })
                  │      └─ TeamsAPI.updateAgents({ teamId, agentsList })
                  │             └─ PATCH /api/v1/accounts/:id/teams/:teamId/team_members
                  │
                  ├─ router.replace({ name: 'settings_teams_edit_finish' })
                  │
                  └─ store.dispatch('teams/get')
```

### データフロー図

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

mounted()
    │
    ├──▶ store.dispatch('agents/get')
    │           │
    │           ▼
    │    agentList (全エージェント)
    │
    └──▶ store.dispatch('teamMembers/get')
                │
                ▼
         teamMembers (既存メンバー)
                │
                ▼
         updateSelectedAgents()
                │
                ▼
         selectedAgents (選択済み状態)
                │
                ▼
         AgentSelector表示
         (既存メンバーがチェック済み)
                │
         ユーザー操作
                │
                ▼
         addAgents() submit
                │
                ▼
         store.dispatch('teamMembers/update')
                │
                ▼
         TeamsAPI.updateAgents()
                │
                ▼
         router.replace()
         (設定完了画面へ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditAgents.vue | `app/javascript/dashboard/routes/dashboard/settings/teams/Edit/EditAgents.vue` | ソース | メインコンポーネント |
| AgentSelector.vue | `app/javascript/dashboard/routes/dashboard/settings/teams/AgentSelector.vue` | ソース | エージェント選択コンポーネント |
| teamMembers.js | `app/javascript/dashboard/store/modules/teamMembers.js` | ソース | Vuexストア |
| teams.js | `app/javascript/dashboard/api/teams.js` | ソース | APIクライアント |
| teams.routes.js | `app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js` | ソース | ルーティング定義 |
| Spinner.vue | `app/javascript/shared/components/Spinner.vue` | ソース | ローディングスピナー |
| SettingsSubPageHeader.vue | `app/javascript/dashboard/routes/dashboard/settings/inbox/SettingsSubPageHeader.vue` | ソース | ヘッダーコンポーネント |
| Avatar.vue | `app/javascript/next/avatar/Avatar.vue` | ソース | アバターコンポーネント |
