# 画面設計書 78-カスタムロール一覧画面

## 概要

本ドキュメントはChatwootのカスタムロール一覧画面に関する設計書です。管理者が独自の権限セットを持つカスタムロールを作成・管理する画面について記述しています。

### 本画面の処理概要

本画面では、デフォルトのロール（管理者、エージェント）以外に、企業固有の権限セットを持つカスタムロールを作成・管理します。カスタムロールを使用することで、組織の役割に応じた細かなアクセス制御が可能になります。

**業務上の目的・背景**：大規模な組織では、単純な「管理者」「エージェント」の2分類では不十分な場合があります。例えば、「レポート閲覧のみ可能なスーパーバイザー」「特定インボックスのみ担当するエージェント」など、より細かな権限制御が必要です。カスタムロールにより、組織の階層構造や業務分担に合わせた柔軟なアクセス制御を実現できます。

**画面へのアクセス方法**：サイドバーの「設定」から「カスタムロール」メニューを選択してアクセスします。または、URLで直接 `/app/accounts/:accountId/settings/custom-roles/list` にアクセスすることもできます。

**主要な操作・処理内容**：
1. カスタムロールの一覧表示：名前、説明、付与された権限を表示
2. 新しいカスタムロールの追加：名前、説明、権限を選択して作成
3. 既存カスタムロールの編集：ロール情報の更新
4. カスタムロールの削除：不要なロールを削除

**画面遷移**：
- 遷移元：設定ホーム画面
- 遷移先：なし（モーダルで操作完結）

**権限による表示制御**：管理者（administrator）権限を持つユーザーのみがアクセス可能です。Cloud/Enterprise版でのみ利用可能で、機能が無効なプランではPaywallが表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | カスタムロール | 主機能 | カスタムロールの一覧表示と管理 |

## 画面種別

一覧

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| パス | `/app/accounts/:accountId/settings/custom-roles/list` |
| ルート名 | `custom_roles_list` |
| コンポーネント | `Index.vue` |

## 入出力項目

### カスタムロール追加/編集フォーム（CustomRoleModal）

| 項目名 | 項目ID | 種別 | 型 | 必須 | バリデーション | 説明 |
|--------|--------|------|-----|------|---------------|------|
| ロール名 | name | 入力 | String | Yes | required | カスタムロールの名前 |
| 説明 | description | 入力 | String | No | - | カスタムロールの説明 |
| 権限 | permissions | 入力 | Array | Yes | required | 付与する権限のリスト |

## 表示項目

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| ロール一覧 | records (customRole/getCustomRoles) | 登録済みカスタムロールのリスト |
| ロール名 | role.name | カスタムロールの名前 |
| 説明 | role.description | カスタムロールの説明 |
| 権限 | role.permissions | 付与された権限のリスト |

## イベント仕様

### 1-ロール追加ボタン押下

**トリガー**: 「Add Custom Role」ボタンのクリック

**処理フロー**:
1. `isBehindAPaywall`をチェック、Paywall状態なら処理中断
2. `customRoleModalMode`を'add'に設定
3. `selectedRole`をnullに設定
4. `showCustomRoleModal`をtrueに設定
5. CustomRoleModalを表示
6. フォーム入力後、送信時に`customRole/createCustomRole`アクションを呼び出し
7. 成功時、アラートを表示しモーダルを閉じる

### 2-ロール編集ボタン押下

**トリガー**: 各ロール行の「Edit」ボタンのクリック

**処理フロー**:
1. `customRoleModalMode`を'edit'に設定
2. `selectedRole`に対象ロールを設定
3. `showCustomRoleModal`をtrueに設定
4. CustomRoleModalを表示（既存値をプリフィル）
5. フォーム編集後、送信時に`customRole/updateCustomRole`アクションを呼び出し
6. 成功時、アラートを表示しモーダルを閉じる

### 3-ロール削除ボタン押下

**トリガー**: 各ロール行の「Delete」ボタンのクリック

**処理フロー**:
1. `openDeletePopup`で`activeResponse`に対象ロールを設定
2. `showDeleteConfirmationPopup`をtrueに設定
3. 削除確認モーダルを表示
4. 確認後、`confirmDeletion`を実行
5. `customRole/deleteCustomRole`アクションを呼び出し
6. 成功時、アラートを表示しモーダルを閉じる

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ロール追加 | custom_roles | INSERT | 新しいカスタムロールの作成 |
| ロール編集 | custom_roles | UPDATE | カスタムロール情報の更新 |
| ロール削除 | custom_roles | DELETE | カスタムロールの削除 |

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

#### custom_roles

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | account_id | 現在のアカウントID | - |
| INSERT | name | フォーム入力値 | ロール名 |
| INSERT | description | フォーム入力値 | 説明 |
| INSERT | permissions | フォーム選択値 | 権限配列 |
| UPDATE | name | フォーム入力値 | 編集時 |
| UPDATE | description | フォーム入力値 | 編集時 |
| UPDATE | permissions | フォーム選択値 | 編集時 |
| DELETE | id | activeResponse.id | 削除対象ID |

## メッセージ仕様

| 種別 | キー | メッセージ | 表示条件 |
|------|-----|-----------|---------|
| 成功 | CUSTOM_ROLE.DELETE.API.SUCCESS_MESSAGE | カスタムロールが正常に削除されました | ロール削除成功時 |
| エラー | CUSTOM_ROLE.DELETE.API.ERROR_MESSAGE | カスタムロールの削除に失敗しました | ロール削除失敗時 |
| 確認 | CUSTOM_ROLE.DELETE.CONFIRM.TITLE | カスタムロールを削除しますか？ | 削除確認ダイアログタイトル |
| 確認 | CUSTOM_ROLE.DELETE.CONFIRM.MESSAGE | この操作は取り消せません | 削除確認ダイアログメッセージ |
| 空状態 | CUSTOM_ROLE.LIST.404 | カスタムロールが見つかりません | ロールが0件の場合 |
| ローディング | CUSTOM_ROLE.LOADING | 読み込み中... | データ取得中 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 権限不足 | 管理者権限がない場合、画面にアクセスできない |
| 機能制限（Paywall） | Cloud/Enterprise版でカスタムロール機能が無効な場合、Paywall表示 |
| API通信エラー | エラーメッセージをアラートで表示 |
| 使用中のロール削除 | バックエンドエラーをアラートで表示 |

## 備考

- Cloud/Enterprise版でのみ利用可能
- カスタムロールは既存のユーザーに割り当て可能
- 削除時、そのロールを持つユーザーがいる場合は警告またはエラーになる可能性
- 権限は複数選択可能（チェックボックス形式）

---

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

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

### 推奨読解順序

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

まず、カスタムロールのデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | customRole.js (store) | `app/javascript/dashboard/store/modules/customRole.js` | stateのrecords配列構造、permissionsの形式 |

**読解のコツ**: カスタムロールオブジェクトにはname, description, permissions等のプロパティがある。permissionsは文字列の配列として管理される。

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

処理の起点となるVueコンポーネントを理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Index.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/Index.vue` | Paywall判定、モーダル管理 |

**主要処理フロー**:
1. **行23-24**: `useMapGetter`でカスタムロール一覧とUIフラグを取得
2. **行38-49**: `isBehindAPaywall`でFeature Flag確認
3. **行59-61**: `onMounted`で`customRole/getCustomRole`アクションを呼び出し
4. **行78-83**: `openAddModal`でPaywall判定後にモーダル表示

#### Step 3: コンポーネント階層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CustomRoleModal.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRoleModal.vue` | ロール追加/編集フォーム |
| 3-2 | CustomRoleTableBody.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRoleTableBody.vue` | ロール一覧テーブル |
| 3-3 | CustomRolePaywall.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRolePaywall.vue` | Paywall表示 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | customRole.js (API) | `app/javascript/dashboard/api/customRole.js` | CRUD操作のAPIクライアント |

**主要処理フロー**:
- APIエンドポイントは `custom_roles`（accountScoped）

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

```
Index.vue (エントリーポイント)
    │
    ├─ onMounted
    │      └─ fetchCustomRoles
    │             └─ store.dispatch('customRole/getCustomRole')
    │                    └─ CustomRoleAPI.get()
    │
    ├─ computed: isBehindAPaywall
    │      └─ isFeatureEnabledonAccount('custom_roles')
    │
    ├─ CustomRolePaywall (条件付き表示)
    │      └─ Paywall状態の場合に表示
    │
    ├─ CustomRoleTableBody
    │      ├─ @edit → openEditModal
    │      └─ @delete → openDeletePopup
    │
    ├─ CustomRoleModal (追加/編集モーダル)
    │      ├─ 追加: store.dispatch('customRole/createCustomRole')
    │      │        └─ CustomRoleAPI.create()
    │      └─ 編集: store.dispatch('customRole/updateCustomRole')
    │               └─ CustomRoleAPI.update()
    │
    └─ woot-delete-modal
           └─ confirmDeletion()
                  └─ deleteCustomRole()
                         └─ store.dispatch('customRole/deleteCustomRole')
                                └─ CustomRoleAPI.delete()
```

### データフロー図

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

ロールフォーム ──────────▶ createCustomRole ────────────▶ ロール作成
      │                        │
      │                        ▼
      │                 ADD_CUSTOM_ROLE mutation ─────▶ records更新
      │
      └── permissions選択 ─▶ 配列として送信 ──────────────▶ 権限設定

[Paywall判定]

accountId ─────────────▶ isFeatureEnabledonAccount ───▶ boolean
      │                        │
      │                        ▼
      └────────────────── isBehindAPaywall ───────────▶ 条件付き表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Index.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/Index.vue` | ソース | メイン画面コンポーネント |
| CustomRoleModal.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRoleModal.vue` | ソース | ロール追加/編集モーダル |
| CustomRoleTableBody.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRoleTableBody.vue` | ソース | ロール一覧テーブル |
| CustomRolePaywall.vue | `app/javascript/dashboard/routes/dashboard/settings/customRoles/component/CustomRolePaywall.vue` | ソース | Paywall表示 |
| customRole.js (API) | `app/javascript/dashboard/api/customRole.js` | ソース | API通信クラス |
| customRole.js (store) | `app/javascript/dashboard/store/modules/customRole.js` | ソース | Vuexストアモジュール |
| customRole.routes.js | `app/javascript/dashboard/routes/dashboard/settings/customRoles/customRole.routes.js` | ソース | ルーティング定義 |
