# 機能設計書 52-テンプレートメッセージ

## 概要

本ドキュメントは、Chatwootにおけるテンプレートメッセージ機能について記述する。本機能は、特定のイベントや条件に基づいて自動的にシステムが生成・送信する定型メッセージを管理する機能である。WhatsApp Business APIのテンプレートメッセージ（HSM）や、挨拶メッセージ、営業時間外メッセージ、CSAT調査メッセージ等を包含する。

### 本機能の処理概要

**業務上の目的・背景**：カスタマーサポートにおいて、顧客からの最初の問い合わせ時の挨拶メッセージ、営業時間外の自動応答、顧客満足度調査の送信など、定型的なコミュニケーションを自動化することで、エージェントの負担を軽減し、顧客体験を向上させる必要がある。また、WhatsApp Business APIでは事前承認されたテンプレートメッセージのみが送信可能であるため、テンプレートパラメータの管理機能も必要である。

**機能の利用シーン**：
- 顧客が初めてチャットを開始した際の挨拶メッセージの自動送信
- 営業時間外に問い合わせがあった場合の自動応答
- 会話解決時のCSAT（顧客満足度）調査の送信
- 会話の自動解決時の通知メッセージ
- WhatsAppなどでの事前承認テンプレートを使用したメッセージ送信

**主要な処理内容**：
1. メッセージ作成時のテンプレートフック実行判定
2. 条件に基づく適切なテンプレートの選択と実行
3. テンプレートメッセージの生成とデータベースへの保存
4. WhatsApp用テンプレートパラメータのJSONスキーマバリデーション
5. テンプレートメッセージのチャネルへの配信

**関連システム・外部連携**：WhatsApp Business API等のテンプレートメッセージ送信機能と連携。

**権限による制御**：テンプレートメッセージはシステムが自動生成するため、直接的な権限制御はない。ただし、インボックス設定（挨拶メッセージ、営業時間外メッセージ等）の変更には管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 会話詳細画面 | 結果表示画面 | テンプレートメッセージが会話に表示される |
| 50 | インボックス設定画面 | 設定画面 | 挨拶メッセージ、営業時間外メッセージの設定 |

## 機能種別

自動メッセージ生成 / データ連携

## 入力仕様

### 入力パラメータ（WhatsApp テンプレート用）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| template_params.name | String | Yes | テンプレート名 | 必須 |
| template_params.category | String | No | テンプレートカテゴリ | - |
| template_params.language | String | No | テンプレート言語 | - |
| template_params.namespace | String | No | テンプレート名前空間 | - |
| template_params.processed_params | Object | No | テンプレート内の変数置換パラメータ | - |

### 入力データソース

- インボックス設定（挨拶メッセージ、営業時間外メッセージ）
- アカウント設定（自動解決メッセージ）
- CSATテンプレート設定
- WhatsAppテンプレートライブラリ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| message.id | Integer | メッセージID |
| message.content | String | テンプレートコンテンツ |
| message.message_type | Enum | "template"（値: 3） |
| message.content_type | Enum | テンプレート種別（text, input_email, input_csat等） |

### 出力先

- messagesテーブル
- 各チャネルAPI（WebSocket配信）

## 処理フロー

### 処理シーケンス

```
1. メッセージ作成後コールバック
   └─ execute_message_template_hooksメソッド呼び出し
2. HookExecutionService初期化
   └─ 対象メッセージを受け取る
3. 前提条件チェック
   └─ キャンペーン会話でないこと
   └─ 最後の受信メッセージが存在すること
   └─ 自動返信メールでないこと
4. テンプレートトリガー判定
   └─ 営業時間外メッセージ判定
   └─ 挨拶メッセージ判定
   └─ メール収集メッセージ判定
5. テンプレートメッセージ生成
   └─ 各Templateクラスでメッセージ作成
6. データベース保存
   └─ トランザクション内でメッセージを保存
```

### フローチャート

```mermaid
flowchart TD
    A[メッセージ作成] --> B{キャンペーン会話?}
    B -->|Yes| Z[終了]
    B -->|No| C{受信メッセージあり?}
    C -->|No| Z
    C -->|Yes| D{自動返信メール?}
    D -->|Yes| Z
    D -->|No| E[テンプレートトリガー判定]
    E --> F{営業時間外?}
    F -->|Yes| G[OutOfOfficeテンプレート送信]
    F -->|No| H{初回メッセージ & 挨拶有効?}
    H -->|Yes| I[Greetingテンプレート送信]
    H -->|No| J{メール収集有効 & メールなし?}
    J -->|Yes| K[EmailCollectテンプレート送信]
    J -->|No| Z
    G --> Z
    I --> Z
    K --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | キャンペーン除外 | キャンペーンから発生した会話にはテンプレートを送信しない | 全テンプレート |
| BR-52-02 | 営業時間外優先 | 営業時間外の場合、他のテンプレートより先に営業時間外メッセージを送信 | 営業時間外設定有効時 |
| BR-52-03 | 初回メッセージ判定 | 挨拶メッセージは顧客からの最初のメッセージ時のみ送信 | 挨拶有効時 |
| BR-52-04 | 1日1回制限 | 営業時間外メッセージは1日1回まで | 営業時間外テンプレート |
| BR-52-05 | エージェント応答後制限 | エージェントが5分以内に応答済みの場合、営業時間外メッセージは送信しない | 営業時間外テンプレート |
| BR-52-06 | Tweet除外 | Twitter/Xのツイートメッセージにはテンプレートを送信しない | 全テンプレート |
| BR-52-07 | メッセージング窓判定 | 自動解決メッセージはメッセージング窓内でのみ送信 | 自動解決テンプレート |

### テンプレートタイプ一覧

| テンプレート名 | クラス | message_type | content_type | 用途 |
|---------------|--------|--------------|--------------|------|
| 挨拶 | Greeting | template | text | 初回問い合わせ時の挨拶 |
| 営業時間外 | OutOfOffice | template | text | 営業時間外の自動応答 |
| メール収集 | EmailCollect | template | input_email | 連絡先メールの収集 |
| CSAT調査 | CsatSurvey | template | input_csat | 顧客満足度調査 |
| 自動解決 | AutoResolve | template | text | 会話自動解決時の通知 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| テンプレートメッセージ作成 | messages | INSERT | テンプレートメッセージをDBに挿入 |

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

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | account_id | 会話のaccount_id | 必須 |
| INSERT | inbox_id | 会話のinbox_id | 必須 |
| INSERT | conversation_id | 会話のID | 必須 |
| INSERT | message_type | 3（template） | 固定値 |
| INSERT | content | テンプレートコンテンツ | インボックス設定から取得 |
| INSERT | content_type | テンプレート種別 | text/input_email/input_csat |
| INSERT | additional_attributes | template_params | WhatsApp用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | StandardError | テンプレート生成中の例外 | ChatwootExceptionTrackerで記録し、処理を継続 |
| - | バリデーションエラー | template_paramsのスキーマ不整合 | JSONスキーマバリデーションエラーを返却 |

### リトライ仕様

テンプレートメッセージ生成はリトライを行わない。失敗した場合は例外をトラッキングし、次のテンプレート処理へ進む。

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

各テンプレートメッセージの生成はActiveRecord::Base.transactionでラップされ、メッセージ作成の原子性を保証する。

## パフォーマンス要件

- メッセージ作成後のコールバックとして同期実行されるため、高速な処理が必要
- 通常100ms以内で完了

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

- テンプレートコンテンツはインボックス設定から取得されるため、管理者権限で設定された内容のみが使用される
- WhatsApp template_paramsはJSONスキーマでバリデーションされ、不正なパラメータは拒否される

## 備考

- message_typeのenum値: incoming=0, outgoing=1, activity=2, template=3
- テンプレートメッセージはprivate=falseで顧客に表示される

---

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

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

### 推奨読解順序

#### Step 1: メッセージモデルのテンプレート関連定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | message.rb | `app/models/message.rb` | message_type enumとTEMPLATE_PARAMS_SCHEMAの定義 |

**主要処理フロー**:
- **48-63行目**: TEMPLATE_PARAMS_SCHEMAでWhatsApp用テンプレートパラメータのJSONスキーマ定義
- **74-76行目**: JsonSchemaValidatorでtemplate_paramsをバリデーション
- **85行目**: message_type enumでtemplate=3を定義
- **408-409行目**: execute_message_template_hooksでHookExecutionServiceを呼び出し

#### Step 2: フック実行サービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hook_execution_service.rb | `app/services/message_templates/hook_execution_service.rb` | テンプレート送信の判定ロジック |

**主要処理フロー**:
- **4-10行目**: performメソッドで前提条件チェック（キャンペーン、受信メッセージ、自動返信）
- **17-21行目**: trigger_templatesで各テンプレートの送信判定と実行
- **23-33行目**: should_send_out_of_office_message?で営業時間外メッセージの条件判定
- **39-43行目**: should_send_greeting?で挨拶メッセージの条件判定
- **51-53行目**: should_send_email_collect?でメール収集の条件判定

#### Step 3: 各テンプレートクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | greeting.rb | `app/services/message_templates/template/greeting.rb` | 挨拶メッセージの生成 |
| 3-2 | out_of_office.rb | `app/services/message_templates/template/out_of_office.rb` | 営業時間外メッセージの生成 |
| 3-3 | email_collect.rb | `app/services/message_templates/template/email_collect.rb` | メール収集メッセージの生成 |
| 3-4 | csat_survey.rb | `app/services/message_templates/template/csat_survey.rb` | CSAT調査メッセージの生成 |
| 3-5 | auto_resolve.rb | `app/services/message_templates/template/auto_resolve.rb` | 自動解決メッセージの生成 |

**Greetingテンプレートの主要処理**:
- **4-11行目**: performメソッドでトランザクション内でメッセージ作成
- **18-27行目**: greeting_message_paramsでメッセージパラメータを構築

**EmailCollectテンプレートの主要処理**:
- **4-12行目**: 2つのメッセージ（説明テキストと入力フォーム）を連続して作成

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

```
Message (after_create_commit)
    │
    └─ execute_message_template_hooks
           │
           └─ MessageTemplates::HookExecutionService#perform
                  │
                  ├─ MessageTemplates::Template::OutOfOffice#perform
                  │      └─ conversation.messages.create!
                  │
                  ├─ MessageTemplates::Template::Greeting#perform
                  │      └─ conversation.messages.create!
                  │
                  └─ MessageTemplates::Template::EmailCollect#perform
                         └─ conversation.messages.create! (x2)
```

### データフロー図

```
[トリガー]              [判定]                    [生成]               [出力]

顧客メッセージ    HookExecutionService    Template Classes    messages
受信          ───▶  条件判定         ───▶  メッセージ生成  ───▶  テーブル
                                                             │
                                                             ▼
                                                        WebSocket配信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| message.rb | `app/models/message.rb` | モデル | テンプレートメッセージのスキーマ定義とenum |
| hook_execution_service.rb | `app/services/message_templates/hook_execution_service.rb` | サービス | テンプレート送信の判定・実行 |
| greeting.rb | `app/services/message_templates/template/greeting.rb` | テンプレート | 挨拶メッセージ生成 |
| out_of_office.rb | `app/services/message_templates/template/out_of_office.rb` | テンプレート | 営業時間外メッセージ生成 |
| email_collect.rb | `app/services/message_templates/template/email_collect.rb` | テンプレート | メール収集メッセージ生成 |
| csat_survey.rb | `app/services/message_templates/template/csat_survey.rb` | テンプレート | CSAT調査メッセージ生成 |
| auto_resolve.rb | `app/services/message_templates/template/auto_resolve.rb` | テンプレート | 自動解決メッセージ生成 |
