# 機能設計書 76-マクロ実行

## 概要

本ドキュメントは、Chatwootにおけるマクロの手動実行機能の仕様を定義する機能設計書である。

### 本機能の処理概要

定義済みのマクロを選択した会話に対して実行する機能。エージェントが会話画面からマクロを選択し、指定した会話（複数可）に対してマクロに定義されたアクションを順次実行する。

**業務上の目的・背景**：マクロは定義しただけでは効果がなく、実際に会話に対して適用することで初めて業務効率化を実現できる。本機能により、エージェントはワンクリックで複数のアクションを一括実行でき、手作業による操作ミスの削減と対応スピードの向上を図る。

**機能の利用シーン**：
- 会話詳細画面でマクロを選択して実行
- 会話一覧から複数の会話を選択して一括実行
- 問い合わせ対応完了時に定型処理を実行

**主要な処理内容**：
1. マクロIDと対象会話ID群を受け取る
2. マクロの実行権限を検証
3. バックグラウンドジョブ（MacrosExecutionJob）をキューイング
4. 対象会話ごとにマクロアクションを順次実行
5. 各アクションの実行結果を処理

**関連システム・外部連携**：
- Webhook送信による外部システム通知
- メール送信（send_email_transcript）
- メッセージ送信

**権限による制御**：
- グローバルマクロ：すべてのユーザーが実行可能
- パーソナルマクロ：作成者本人のみ実行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 64 | マクロ編集画面 | 補助画面 | マクロのテスト実行 |
| 11 | 会話詳細画面 | 主画面 | マクロの選択・実行 |

## 機能種別

バッチ処理 / バックグラウンドジョブ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | マクロID | 存在確認、実行権限確認 |
| conversation_ids | Array[Integer] | Yes | 対象会話のdisplay_id配列 | 存在確認 |

### 入力データソース

- POST /api/v1/accounts/:account_id/macros/:id/execute
- リクエストボディ（JSON）

## 出力仕様

### 出力データ

即時レスポンスは成功ステータスのみ（200 OK、ヘッダーのみ）

実際のアクション実行はバックグラウンドで行われ、以下の影響を与える：
- 会話のステータス変更
- ラベルの付与・削除
- チーム・エージェントの割り当て
- メッセージの送信
- プライベートノートの追加
- Webhookの発火

### 出力先

- バックグラウンドジョブ経由で各種処理

## 処理フロー

### 処理シーケンス

```
1. 実行リクエスト受信
   └─ POST /api/v1/accounts/:account_id/macros/:id/execute
2. マクロ取得・権限検証
   └─ MacroPolicy#execute? でglobal? || author?を検証
3. ジョブキューイング
   └─ MacrosExecutionJob.perform_later(macro, conversation_ids, user)
4. 会話取得（バックグラウンド）
   └─ account.conversations.where(display_id: conversation_ids)
5. 会話ごとにアクション実行
   └─ Macros::ExecutionService.new(macro, conversation, user).perform
6. 各アクションの順次実行
   └─ send(action[:action_name], action[:action_params])
```

### フローチャート

```mermaid
flowchart TD
    A[POST /macros/:id/execute] --> B[マクロ取得]
    B --> C{マクロ存在?}
    C -->|No| D[404 Not Found]
    C -->|Yes| E[権限チェック]
    E --> F{実行権限あり?}
    F -->|No| G[403 Forbidden]
    F -->|Yes| H[ジョブキューイング]
    H --> I[200 OK 返却]
    H --> J[バックグラウンド処理開始]
    J --> K[会話取得]
    K --> L{会話あり?}
    L -->|No| M[処理終了]
    L -->|Yes| N[各会話にアクション実行]
    N --> O[ExecutionService.perform]
    O --> P[actions.each で順次実行]
    P --> Q[処理完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-76-01 | 権限検証 | globalマクロまたは作成者本人のみ実行可能 | 実行リクエスト時 |
| BR-76-02 | 非同期実行 | 実行はバックグラウンドジョブで処理 | 常時 |
| BR-76-03 | 順次実行 | actionsは定義順に実行される | アクション実行時 |
| BR-76-04 | エラー継続 | 1つのアクションが失敗しても他のアクションは実行継続 | アクション実行時 |
| BR-76-05 | 複数会話対応 | 複数会話を指定して一括実行可能 | 実行リクエスト時 |
| BR-76-06 | selfエージェント | assign_agentで'self'を指定すると実行ユーザーに割り当て | アクション実行時 |

### 計算ロジック

アクション実行のループ処理：
```ruby
def perform
  @macro.actions.each do |action|
    action = action.with_indifferent_access
    begin
      send(action[:action_name], action[:action_params])
    rescue StandardError => e
      ChatwootExceptionTracker.new(e, account: @account).capture_exception
    end
  end
ensure
  Current.reset
end
```

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| マクロ取得 | macros | SELECT | IDでマクロ取得 |
| 会話取得 | conversations | SELECT | display_idsで会話取得 |
| ステータス変更 | conversations | UPDATE | change_statusアクション |
| ラベル付与 | taggings | INSERT | add_labelアクション |
| 割り当て変更 | conversations | UPDATE | assign_agent, assign_teamアクション |
| メッセージ送信 | messages | INSERT | send_message, add_private_noteアクション |

### テーブル別操作詳細

アクションの種類によって操作対象が異なる。代表的なアクションの操作：

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | status | 指定ステータス | change_status |
| UPDATE | assignee_id | 指定エージェントID | assign_agent |
| UPDATE | team_id | 指定チームID | assign_team |
| UPDATE | muted | true | mute_conversation |
| UPDATE | priority | 指定優先度 | change_priority |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | 指定マクロが存在しない | 正しいIDを指定 |
| 403 | Forbidden | マクロ実行権限がない | 権限のあるマクロを選択 |
| 401 | Unauthorized | 未認証 | ログイン後に再試行 |

### リトライ仕様

- バックグラウンドジョブはActivejobの標準リトライ機構に依存
- 個別アクションのエラーは例外キャプチャのみでリトライなし

## トランザクション仕様

- 各会話へのアクション実行は独立して処理
- 1会話の処理でエラーが発生しても他の会話への処理は継続

## パフォーマンス要件

- APIレスポンス：200ms以内（ジョブキューイングのみ）
- バックグラウンド処理：会話数 x アクション数に依存

## セキュリティ考慮事項

- MacroPolicyによる実行権限検証
- Current.userを設定してユーザーコンテキストを維持
- 処理完了後にCurrent.resetでコンテキストをクリア

## 備考

- ジョブキューは'medium'キューを使用
- ツイート会話に対してはsend_message, add_private_noteがスキップされる

---

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

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

### 推奨読解順序

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

マクロのアクション構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | macro.rb | `app/models/macro.rb` | ACTIONS_ATTRSでサポートされるアクション |

**読解のコツ**:
- **33-35行目**: ACTIONS_ATTRSでサポートされる全アクションを確認

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

executeアクションを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | macros_controller.rb | `app/controllers/api/v1/accounts/macros_controller.rb` | executeアクション |

**主要処理フロー**:
1. **4行目**: before_action :fetch_macroでマクロ取得
2. **5行目**: before_action :check_authorizationで権限検証
3. **50-54行目**: executeアクションでジョブキューイング

#### Step 3: バックグラウンドジョブを理解する

MacrosExecutionJobの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | macros_execution_job.rb | `app/jobs/macros_execution_job.rb` | ジョブの実装 |

**主要処理フロー**:
- **4-13行目**: performメソッドで会話取得→各会話にExecutionService実行

#### Step 4: アクション実行サービスを理解する

ExecutionServiceの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | execution_service.rb | `app/services/macros/execution_service.rb` | アクション実行ロジック |
| 4-2 | action_service.rb | `app/services/action_service.rb` | 基底アクションサービス |

**主要処理フロー**:
- **10-21行目**: performメソッドでactions.eachループ、send動的呼び出し
- **25-28行目**: assign_agentで'self'をcurrent_user.idに変換
- **30-47行目**: add_private_note, send_messageの実装

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

```
POST /api/v1/accounts/:account_id/macros/:id/execute
    │
    ├─ before_action :fetch_macro
    │      └─ Current.account.macros.find_by(id: params[:id])
    │
    ├─ before_action :check_authorization
    │      └─ MacroPolicy#execute?
    │             └─ global? || author?
    │
    └─ execute アクション
           │
           └─ MacrosExecutionJob.perform_later(macro, conversation_ids, user)
                  │
                  └─ [バックグラウンド]
                         │
                         ├─ account.conversations.where(display_id: conversation_ids)
                         │
                         └─ conversations.each
                                │
                                └─ Macros::ExecutionService.new(macro, conversation, user).perform
                                       │
                                       └─ macro.actions.each
                                              │
                                              └─ send(action_name, action_params)
                                                     │
                                                     ├─ add_label
                                                     ├─ assign_agent
                                                     ├─ send_message
                                                     └─ ... (他のアクション)
```

### データフロー図

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

APIリクエスト               コントローラー                  即時レスポンス
(macro_id,          ───▶ MacrosController#execute ───▶ 200 OK
 conversation_ids)          │
                            └─ ジョブキューイング
                                   │
                                   └─ [バックグラウンド]
                                          │
                                          ├─ 会話取得
                                          │
                                          └─ ExecutionService
                                                 │
                                                 └─ 各アクション実行
                                                        │
                                                        ├─ 会話更新
                                                        ├─ メッセージ送信
                                                        └─ Webhook発火等
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| macros_controller.rb | `app/controllers/api/v1/accounts/macros_controller.rb` | コントローラー | executeアクション（50-54行目） |
| macros_execution_job.rb | `app/jobs/macros_execution_job.rb` | ジョブ | バックグラウンド実行 |
| execution_service.rb | `app/services/macros/execution_service.rb` | サービス | アクション実行ロジック |
| action_service.rb | `app/services/action_service.rb` | サービス | 基底アクションサービス |
| macro_policy.rb | `app/policies/macro_policy.rb` | ポリシー | 実行権限検証（execute?） |
| macro.rb | `app/models/macro.rb` | モデル | ACTIONS_ATTRS定義 |
