# 機能設計書 87-シナリオ管理

## 概要

本ドキュメントは、Chatwoot Captain AIアシスタントのシナリオ管理機能の設計を記載する。特定の会話パターンや状況に対応するためのシナリオを定義・管理するEnterprise機能である。

### 本機能の処理概要

シナリオ管理機能は、AIアシスタントが特定の状況やユースケースに対応するための指示とツール設定をまとめたシナリオを管理する機能である。

**業務上の目的・背景**：AIアシスタントは様々な顧客リクエストに対応する必要があるが、すべてのケースを単一の指示で対応することは困難である。シナリオ機能により、「返金リクエスト対応」「技術サポート」「営業問い合わせ」など、特定のユースケースに特化した対応を定義できる。

**機能の利用シーン**：
- 管理者が特定のユースケース向けシナリオを作成する際
- シナリオに使用するツールを指定する際
- シナリオの有効/無効を切り替える際
- シナリオの指示内容を更新する際

**主要な処理内容**：
1. シナリオの作成（タイトル、説明、指示、ツール）
2. シナリオの有効/無効管理
3. 指示内テンプレートツール参照の解決
4. アシスタントへのシナリオ紐付け

**関連システム・外部連携**：Captain Assistantとの関連、ツール管理機能との連携。

**権限による制御**：Captain::Scenarioポリシーによる権限制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 108 | シナリオ一覧画面 | 主画面 | シナリオの一覧と管理 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| assistant_id | Integer | Yes | 親アシスタントID | 存在するアシスタント |
| title | String | Yes | シナリオタイトル | presence: true |
| description | Text | Yes | シナリオ説明 | presence: true |
| instruction | Text | Yes | AIへの指示 | presence: true |
| enabled | Boolean | No | 有効/無効 | デフォルト: true |
| tools | Array | No | 使用するツールID配列 | - |

### 入力データソース

- 管理画面からのAPI呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | シナリオID |
| title | String | シナリオタイトル |
| description | Text | シナリオ説明 |
| instruction | Text | AIへの指示 |
| enabled | Boolean | 有効/無効 |
| tools | JSONB | 使用ツールID配列 |
| assistant_id | BigInt | 親アシスタントID |
| account_id | BigInt | アカウントID |
| created_at | DateTime | 作成日時 |
| updated_at | DateTime | 更新日時 |

### 出力先

- JSON APIレスポンス

## 処理フロー

### 処理シーケンス

```
1. シナリオ一覧取得（index）
   └─ アシスタントに紐付く有効シナリオを取得
2. シナリオ作成（create）
   └─ パラメータ検証
   └─ ツール参照検証
   └─ ツール参照解決（before_save）
   └─ captain_scenariosテーブルにINSERT
3. シナリオ更新（update）
   └─ パラメータ検証
   └─ ツール参照再解決
   └─ レコード更新
```

### フローチャート

```mermaid
flowchart TD
    A[シナリオ一覧画面] --> B[GET /captain/assistants/:assistant_id/scenarios]
    B --> C[ScenariosController#index]
    C --> D[assistant_scenarios.enabled取得]
    D --> E[JSON応答]

    F[シナリオ作成] --> G[POST /captain/assistants/:assistant_id/scenarios]
    G --> H[ScenariosController#create]
    H --> I{権限チェック}
    I -->|OK| J[scenario_params検証]
    I -->|NG| K[403 Forbidden]
    J --> L{ツール参照検証}
    L -->|無効ツール| M[422 ValidationError]
    L -->|OK| N[resolve_tool_references]
    N --> O[Captain::Scenario.create!]
    O --> P[JSON応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-01 | 必須フィールド | title, description, instructionは必須 | 作成・更新時 |
| BR-87-02 | アシスタント紐付け | シナリオは必ず1つのアシスタントに紐付く | 作成時 |
| BR-87-03 | ツール参照検証 | instruction内のツール参照は有効なツールのみ | 作成・更新時 |
| BR-87-04 | ツール参照解決 | instructionからツールIDを抽出してtoolsに保存 | 保存前 |
| BR-87-05 | 有効シナリオのみ | enabledがtrueのシナリオのみ一覧で取得 | 一覧取得時 |

### 計算ロジック

**ツール参照抽出**:
- instruction内の `[ツール名](tool://ツールID)` 形式を検出
- 正規表現: `TOOL_REFERENCE_REGEX` で抽出
- 抽出したツールIDをtools配列に保存

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | captain_scenarios | SELECT | 有効シナリオ取得 |
| 作成 | captain_scenarios | INSERT | 新規レコード作成 |
| 更新 | captain_scenarios | UPDATE | レコード更新 |
| 削除 | captain_scenarios | DELETE | レコード削除 |

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

#### captain_scenarios

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | assistant_id, enabled | アシスタントID, true | 有効シナリオ取得 |
| INSERT | title | ユーザー入力 | 必須 |
| INSERT | description | ユーザー入力 | 必須 |
| INSERT | instruction | ユーザー入力 | 必須 |
| INSERT | enabled | Boolean | デフォルト: true |
| INSERT | tools | JSONB | instruction から自動抽出 |
| INSERT | assistant_id | パスパラメータ | 必須 |
| INSERT | account_id | Current.account.id | 必須 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 権限がない | 管理者に連絡 |
| 404 | NotFound | アシスタント/シナリオが存在しない | IDを確認 |
| 422 | ValidationError | 無効なツール参照 | instructionを修正 |

### リトライ仕様

該当なし

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

単一レコード操作のため、暗黙的トランザクション

## パフォーマンス要件

- シナリオ一覧はページネーションなし（シナリオ数は限定的想定）
- enabledインデックスによる検索最適化

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

- Captain::Scenarioポリシーによる権限制御
- アカウント境界による分離

## 備考

- Enterprise版機能
- シナリオはAgentableをincludeしてエージェントとして動作可能
- Assistantの設定（temperature等）をdelegate

---

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

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

### 推奨読解順序

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

まず、シナリオのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | scenario.rb | `enterprise/app/models/captain/scenario.rb` | モデル定義、バリデーション |

**読解のコツ**:
- **23-27行目**: テーブル名、include設定
- **29-30行目**: belongs_to関連（assistant, account）
- **32-37行目**: バリデーション（必須フィールド、ツール参照検証）
- **39行目**: enabledスコープ
- **41行目**: delegateでassistantの設定を引き継ぎ
- **43行目**: before_saveでツール参照解決
- **105-117行目**: validate_instruction_tools（ツール参照検証）
- **133-138行目**: resolve_tool_references（ツールID抽出・保存）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | scenarios_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/scenarios_controller.rb` | CRUD操作 |

**主要処理フロー**:
- **7-9行目**: indexでenableスコープ使用
- **13-15行目**: createでaccount: Current.account追加
- **28-29行目**: set_assistantでアシスタント取得
- **44-46行目**: scenario_paramsでパラメータ許可（tools配列対応）

#### Step 3: ツール参照の仕組みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | scenario.rb | `enterprise/app/models/captain/scenario.rb` | ツール参照解決 |

**主要処理フロー**:
- **66-69行目**: resolved_instructionsでツール参照を表示形式に変換
- **71-77行目**: resolved_toolsで利用可能ツールとマッチング
- **79-89行目**: resolve_tool_instanceでツールインスタンス生成

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

```
ScenariosController
    │
    ├─ index
    │      └─ assistant_scenarios.enabled
    │
    ├─ create
    │      └─ assistant_scenarios.create!(scenario_params)
    │              │
    │              ├─ validate_instruction_tools
    │              │      └─ extract_tool_ids_from_text
    │              │      └─ assistant.available_tool_ids
    │              │
    │              └─ resolve_tool_references (before_save)
    │                     └─ extract_tool_ids_from_text
    │
    └─ update
           └─ @scenario.update!(scenario_params)
                   └─ (同上のバリデーション・解決処理)

Captain::Scenario (エージェント動作時)
    │
    └─ agent_tools
           └─ resolved_tools.map { resolve_tool_instance }
                   ├─ カスタムツール → CustomTool#tool
                   └─ 組み込みツール → tool_class.new
```

### データフロー図

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

scenario_params ───▶ ScenariosController ───▶ Captain::Scenario
    │                        │                        │
    └─ instruction          ├─ ツール参照検証         ├─ DB保存
         │                  │                        │
         └─ tool://xxx ───▶ extract_tool_ids ───▶ tools配列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| scenarios_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/scenarios_controller.rb` | コントローラー | CRUD API |
| scenario.rb | `enterprise/app/models/captain/scenario.rb` | モデル | シナリオデータモデル |
| scenario_policy.rb | `enterprise/app/policies/captain/scenario_policy.rb` | ポリシー | 権限制御 |
| assistant.rb | `enterprise/app/models/captain/assistant.rb` | モデル | 親アシスタント |
| captain_tools_helpers.rb | `app/models/concerns/captain_tools_helpers.rb` | Concern | ツール参照抽出 |
| agentable.rb | `app/models/concerns/agentable.rb` | Concern | エージェント機能 |
