# 画面設計書 64-マクロ編集画面

## 概要

本ドキュメントは、Chatwootのマクロ編集画面の設計仕様を記述したものです。

### 本画面の処理概要

本画面は、既存のマクロを編集するための画面です。新規作成画面と同じ `MacroEditor.vue` コンポーネントを使用しますが、URLパラメータから `macroId` を取得し、既存のマクロデータを読み込んで編集します。

**業務上の目的・背景**：運用中にマクロの内容を変更する必要が生じた場合（アクションの追加・削除、パラメータの変更など）、本画面で既存マクロを編集できます。これにより、マクロの継続的な改善と最適化が可能になります。

**画面へのアクセス方法**：マクロ一覧画面から対象マクロの「編集」ボタンをクリックしてアクセスします。URLパスは `/app/accounts/:accountId/settings/macros/:macroId/edit` です。

**主要な操作・処理内容**：
1. 既存マクロデータの読み込みと表示
2. マクロ名の変更
3. 公開範囲の変更（権限に応じて）
4. アクションノードの追加・編集・削除
5. マクロの保存（更新）

**画面遷移**：
- 遷移元：マクロ一覧画面
- 遷移先：マクロ一覧画面（保存成功時）

**権限による表示制御**：全ロール（管理者・エージェント）がアクセス可能です。ただし、自分が作成したマクロまたはグローバルマクロのみ編集可能です（Punditポリシーで制御）。エージェントは公開範囲を「グローバル」に変更できません。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 75 | マクロ（ショートカット） | 主機能 | 既存マクロの編集 |
| 76 | マクロ実行 | 補助機能 | マクロのテスト実行 |

## 画面種別

編集

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| パス | `/app/accounts/:accountId/settings/macros/:macroId/edit` |
| ルート名 | `macros_edit` |
| コンポーネント | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroEditor.vue` |
| 権限 | `ROLES`, `CONVERSATION_PERMISSIONS` |
| フィーチャーフラグ | `MACROS` |

## 入出力項目

### URLパラメータ

| パラメータ名 | 型 | 説明 |
|-------------|-----|------|
| accountId | number | アカウントID |
| macroId | number | 編集対象のマクロID |

### 入力項目

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| マクロ名 | name | string | 必須 | マクロの名称 |
| 公開範囲 | visibility | enum | 必須 | `personal`（個人）または `global`（全体公開） |
| アクション配列 | actions | array | 必須 | 実行するアクションのリスト |

## 表示項目

### 左側：アクションノードエディタ

| 項目名 | 説明 |
|--------|------|
| アクションノード | 各アクションを視覚的なノードとして表示 |
| アクションタイプ | ドロップダウンでアクションを選択 |
| アクションパラメータ | アクションに応じた入力フィールド（既存値をプリセット） |
| 追加ボタン | 新しいアクションノードを追加 |
| 削除ボタン | アクションノードを削除 |

### 右側：プロパティパネル

| 項目名 | 説明 |
|--------|------|
| マクロ名入力 | マクロの名称を入力（既存値をプリセット） |
| 公開範囲選択 | 個人/グローバルを選択（既存値をプリセット） |
| 保存ボタン | マクロを更新 |

## イベント仕様

### 1-マクロデータ読み込み

画面表示時に、URLパラメータの `macroId` から既存マクロデータを取得します。

**処理フロー**：
1. `watch` でルート変更を検知
2. `route.params.macroId` が存在する場合、`fetchMacro()` が呼び出される
3. `mode` が `'EDIT'` に設定される
4. `store.dispatch('macros/getSingleMacro', macroId)` でマクロを取得
5. `formatMacro(singleMacro)` でアクションパラメータを整形
6. `macro` に整形されたデータを設定

### 2-アクションパラメータの整形

取得したマクロデータのアクションパラメータを、フォームで扱える形式に変換します。

**処理フロー**：
1. `formatMacro(macroData)` が呼び出される
2. 各アクションの `inputType` を `MACRO_ACTION_TYPES` から取得
3. `inputType` に応じてパラメータを変換
   - `multi_select` / `search_select`: IDからオブジェクトに変換
   - `team_message`: team_ids と message を整形
   - その他: そのまま使用

### 3-マクロ更新

プロパティパネルの保存ボタンをクリックすると、マクロが更新されます。

**処理フロー**：
1. `MacroForm.submit()` が呼び出される
2. バリデーション実行
3. `$emit('submit', macro)` でマクロデータを親に渡す
4. `MacroEditor.saveMacro(macroData)` が呼び出される
5. `mode` が `'EDIT'` なので `'macros/update'` アクションをディスパッチ
6. 成功時：成功メッセージを表示し、マクロ一覧画面に遷移
7. 失敗時：エラーメッセージを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| マクロ取得 | macros | SELECT | 指定IDのマクロを取得 |
| マクロ更新 | macros | UPDATE | 既存マクロを更新 |
| ファイル添付 | active_storage_attachments | INSERT/DELETE | 添付ファイルの追加/削除 |

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

#### macros

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | WHERE id = :macroId | 編集対象のマクロを取得 |
| UPDATE | name | フォーム入力値 | マクロ名 |
| UPDATE | visibility | フォーム入力値 | 公開範囲 |
| UPDATE | actions | JSON形式のフォーム入力値 | アクション配列 |
| UPDATE | updated_by_id | current_user.id | 更新者ID |
| UPDATE | updated_at | 現在日時 | 更新日時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示タイミング |
|-------------|------|---------------|---------------|
| MACROS.EDIT.API.SUCCESS_MESSAGE | 成功 | マクロ更新成功 | 更新成功時 |
| MACROS.ERROR | エラー | マクロ保存エラー | 更新失敗時 |
| MACROS.EDITOR.LOADING | 情報 | 読み込み中 | データ取得中 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| マクロが見つからない | データ取得エラーを無視（空のデータを表示） |
| 権限不足 | Punditポリシーで認可エラー |
| バリデーションエラー | エラー表示し、保存処理を中断 |
| API呼び出し失敗 | エラーメッセージをアラート表示 |

## 備考

- 編集画面と新規作成画面は同じ `MacroEditor.vue` コンポーネントを使用
- `route.params.macroId` の有無で新規/編集を判定
- 編集時は `getSingleMacro` で個別取得（一覧取得とは別API）
- アクションパラメータは `formatMacro` で整形が必要（IDからオブジェクトへの変換など）
- `updated_by_id` で最終更新者を追跡
- Punditポリシー `MacroPolicy` で編集権限を制御

---

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

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

### 推奨読解順序

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

マクロとアクションタイプの構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | macro.rb | `app/models/macro.rb` | モデル定義、updated_by_id の存在を確認 |
| 1-2 | constants.js | `app/javascript/dashboard/routes/dashboard/settings/macros/constants.js` | MACRO_ACTION_TYPESの定義を確認 |

**読解のコツ**: 編集時は `action_params` の形式変換が重要です。APIから返されるIDベースのデータを、フォームで扱えるオブジェクト形式に変換する必要があります。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MacroEditor.vue | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroEditor.vue` | fetchMacro、formatMacro の処理を確認 |

**主要処理フロー**:
1. **99-110行目**: `watch` でルートを監視し、`macroId` 存在時に `fetchMacro()` を呼び出し
2. **80-83行目**: `fetchMacro()` で `mode` を `'EDIT'` に設定
3. **74-78行目**: `manifestMacro()` でマクロを取得し `formatMacro` で整形
4. **43-72行目**: `formatMacro()` でアクションパラメータを変換

#### Step 3: Vuex Store層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | macros.js | `app/javascript/dashboard/store/modules/macros.js` | getSingleMacro、update アクションを確認 |

**主要処理フロー**:
- **42-51行目**: `getSingleMacro` アクションで個別マクロ取得
- **74-84行目**: `update` アクションで更新処理

#### Step 4: バックエンド層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | macros_controller.rb | `app/controllers/api/v1/accounts/macros_controller.rb` | show、update アクション、check_authorization を確認 |

**主要処理フロー**:
- **11-13行目**: `show` アクションで個別取得
- **29-43行目**: `update` アクションでトランザクション使用の更新処理
- **73-75行目**: `check_authorization` で Pundit による認可

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

```
MacroEditor.vue (エントリーポイント)
    │
    ├─ watch(route)
    │      └─ fetchMacro()
    │             │
    │             ├─ mode = 'EDIT'
    │             │
    │             └─ manifestMacro()
    │                    │
    │                    ├─ store.dispatch('macros/getSingleMacro')
    │                    │      └─ MacrosAPI.show()
    │                    │             └─ GET /api/v1/accounts/:account_id/macros/:id
    │                    │
    │                    └─ formatMacro()
    │                           └─ アクションパラメータ変換
    │
    └─ saveMacro() [mode === 'EDIT']
           │
           ├─ actionQueryGenerator()
           │
           └─ store.dispatch('macros/update')
                  └─ MacrosAPI.update()
                         └─ PATCH /api/v1/accounts/:account_id/macros/:id
                                └─ macros_controller#update
```

### データフロー図

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

URL (macroId) ────────▶ MacroEditor ─────────────▶ fetchMacro()
                              │
                              ▼
                    store.dispatch('getSingleMacro')
                              │
                              ▼
                    MacrosAPI.show()
                              │
                              ▼
                    formatMacro()
                              │
                              ▼
                    MacroForm (プリセット表示)

ユーザー編集 ─────────▶ MacroForm ────────────────▶ macro オブジェクト
                              │
                              ▼
                    saveMacro()
                              │
                              ▼
                    store.dispatch('macros/update')
                              │
                              ▼
                    PostgreSQL (UPDATE)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MacroEditor.vue | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroEditor.vue` | ソース | エディタコンテナ |
| MacroForm.vue | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroForm.vue` | ソース | フォームコンポーネント |
| MacroNodes.vue | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroNodes.vue` | ソース | ノードエディタ |
| MacroProperties.vue | `app/javascript/dashboard/routes/dashboard/settings/macros/MacroProperties.vue` | ソース | プロパティパネル |
| constants.js | `app/javascript/dashboard/routes/dashboard/settings/macros/constants.js` | ソース | アクションタイプ定義 |
| useMacros.js | `app/javascript/dashboard/composables/useMacros.js` | ソース | マクロComposable |
| macros.js | `app/javascript/dashboard/store/modules/macros.js` | ソース | Vuexストアモジュール |
| macros.js | `app/javascript/dashboard/api/macros.js` | ソース | APIクライアント |
| macros_controller.rb | `app/controllers/api/v1/accounts/macros_controller.rb` | ソース | Railsコントローラ |
| macro.rb | `app/models/macro.rb` | ソース | モデル定義 |
| macro_policy.rb | `app/policies/macro_policy.rb` | ソース | Punditポリシー |
