# 機能設計書 81-メールテンプレート

## 概要

本ドキュメントは、Chatwootのメールテンプレート機能の設計を記載する。EmailTemplateモデルを使用して、メール配信用のカスタムテンプレートを管理する機能である。

### 本機能の処理概要

メールテンプレート機能は、Chatwootシステムから送信されるメールのカスタマイズを可能にする機能である。

**業務上の目的・背景**：顧客とのメールコミュニケーションにおいて、企業ブランドに沿った一貫性のあるメールデザインを実現するため、メールテンプレートのカスタマイズが必要となる。デフォルトのテンプレートでは対応できない、企業固有のデザイン要件や多言語対応を実現する。

**機能の利用シーン**：管理者がアカウント固有のメールレイアウトやコンテンツテンプレートを設定する際に利用される。例えば、顧客への通知メール、パスワードリセットメール、会話トランスクリプトメールなどのカスタマイズ時に使用する。

**主要な処理内容**：
1. メールテンプレートの作成・保存（レイアウト/コンテンツ種別の管理）
2. 多言語対応（locale enumによる言語別テンプレート管理）
3. データベースからのテンプレート解決（DbResolverService）
4. Liquidテンプレートエンジンとの連携によるダイナミックコンテンツ生成

**関連システム・外部連携**：ActionMailerとの連携、Liquidテンプレートエンジン、ActionViewのテンプレート解決機構との統合が行われる。

**権限による制御**：アカウント管理者のみがテンプレートの作成・編集が可能である。テンプレートはアカウント単位またはインストール全体（account_id: nil）で管理される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | システム内部処理 | 主機能 | メール送信時のテンプレート適用 |

## 機能種別

CRUD操作 / テンプレート解決処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | テンプレート名 | アカウント内で一意 |
| body | Text | Yes | テンプレート本文（Liquid形式） | 空白不可 |
| locale | Integer | Yes | 言語コード（enum） | LANGUAGES_CONFIGに基づく |
| template_type | Integer | No | テンプレート種別（layout/content） | デフォルト: content |
| account_id | Integer | No | アカウントID | 存在する場合はアカウントに紐付け |

### 入力データソース

- 管理画面からの入力
- シードデータまたはマイグレーション

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | テンプレートID |
| name | String | テンプレート名 |
| body | Text | テンプレート本文 |
| locale | String | 言語コード |
| template_type | String | テンプレート種別 |
| account_id | Integer | アカウントID（nullable） |

### 出力先

- ActionMailerによるメール生成時のテンプレートソースとして使用

## 処理フロー

### 処理シーケンス

```
1. メール送信リクエスト
   └─ ActionMailerがテンプレートを要求
2. DbResolverService.find_templates呼び出し
   └─ テンプレート名とタイプでDB検索
3. アカウント固有テンプレート検索
   └─ Current.accountに紐付くテンプレートを優先
4. インストールテンプレート検索（フォールバック）
   └─ account_id: nilのテンプレートを検索
5. ActionView::Template生成
   └─ Liquidハンドラーで処理
```

### フローチャート

```mermaid
flowchart TD
    A[メール送信要求] --> B[DbResolverService.find_templates]
    B --> C{Current.account存在?}
    C -->|Yes| D[アカウントテンプレート検索]
    C -->|No| E[インストールテンプレート検索]
    D --> F{テンプレート発見?}
    F -->|Yes| G[ActionView::Template生成]
    F -->|No| E
    E --> H{テンプレート発見?}
    H -->|Yes| G
    H -->|No| I[空配列を返却]
    G --> J[Liquidハンドラーで処理]
    J --> K[メール本文生成完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-81-01 | テンプレート名の一意性 | name + account_id の組み合わせで一意 | テンプレート作成・更新時 |
| BR-81-02 | アカウント優先 | アカウント固有テンプレートがインストールテンプレートより優先 | テンプレート解決時 |
| BR-81-03 | テンプレート種別 | layoutとcontentの2種類が存在 | テンプレート作成時 |
| BR-81-04 | 多言語対応 | LANGUAGES_CONFIGに定義された言語をサポート | テンプレート作成時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| テンプレート作成 | email_templates | INSERT | 新規テンプレートレコード作成 |
| テンプレート更新 | email_templates | UPDATE | 既存テンプレートの更新 |
| テンプレート削除 | email_templates | DELETE | テンプレートレコード削除 |
| テンプレート検索 | email_templates | SELECT | name, template_type, account_idで検索 |

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

#### email_templates

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ユーザー入力値 | 必須 |
| INSERT | body | テンプレート本文 | 必須、Liquid形式 |
| INSERT | locale | 言語enum値 | デフォルト: en |
| INSERT | template_type | 種別enum値 | デフォルト: content |
| INSERT | account_id | アカウントID | nullable |
| SELECT | name, template_type, account_id | 検索条件として使用 | 複合インデックス |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | 名前が重複している | 別の名前を指定 |
| - | RecordNotFound | 指定テンプレートが存在しない | フォールバックテンプレート使用 |

### リトライ仕様

テンプレート取得失敗時はデフォルトテンプレート（ファイルシステム）にフォールバック

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

テンプレートの作成・更新は単一レコード操作のため、暗黙的トランザクション

## パフォーマンス要件

- テンプレート解決はメール送信のたびに実行されるため、高速である必要がある
- name + account_id の複合インデックスによる検索最適化

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

- テンプレート本文にはLiquid構文のみ使用可能（任意のRubyコード実行を防止）
- アカウント境界による分離（他アカウントのテンプレートにアクセス不可）
- XSS防止のためのHTMLエスケープ処理

## 備考

- Railsのテンプレート解決機構をオーバーライドしてDB検索を実現
- キャッシュは使用せず、毎回DB検索を行う設計（find_allメソッドのオーバーライド）

---

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

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

### 推奨読解順序

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

まず、メールテンプレートのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | email_template.rb | `app/models/email_template.rb` | テーブル構造、enum定義、バリデーション |

**読解のコツ**:
- enum :locale はLANGUAGES_CONFIGから動的に生成される
- enum :template_type は layout(0) と content(1) の2種類
- account_id がoptionalであることに注目（nilの場合はインストール全体のテンプレート）

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

テンプレート解決の起点となるサービスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | db_resolver_service.rb | `app/services/email_templates/db_resolver_service.rb` | ActionView::Resolverの拡張 |

**主要処理フロー**:
1. **17-21行目**: usingメソッドでモデルとオプションを設定
2. **26-29行目**: find_allメソッドでキャッシュをバイパス
3. **35-52行目**: find_templatesでDB検索とActionView::Template生成
4. **56-68行目**: アカウント優先のテンプレート検索ロジック

#### Step 3: Railsとの統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | email_template.rb | `app/models/email_template.rb` | resolverクラスメソッド |

**主要処理フロー**:
- **25-27行目**: resolver メソッドがDbResolverServiceのシングルトンインスタンスを返却

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

```
ActionMailer::Base
    │
    └─ EmailTemplate.resolver
           │
           └─ EmailTemplates::DbResolverService.using
                  │
                  ├─ find_all (キャッシュバイパス)
                  │
                  └─ find_templates
                         │
                         ├─ find_account_template
                         │      └─ Current.account による検索
                         │
                         └─ find_installation_template
                                └─ account_id: nil による検索
```

### データフロー図

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

テンプレート名 ───▶ DbResolverService ───▶ ActionView::Template
テンプレート種別          │
                         ├─ DBクエリ実行
                         │
                         └─ Liquidハンドラー設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| email_template.rb | `app/models/email_template.rb` | モデル | テンプレートデータモデル定義 |
| db_resolver_service.rb | `app/services/email_templates/db_resolver_service.rb` | サービス | ActionViewへのDB解決機能提供 |
| languages.yml | `config/languages/languages.yml` | 設定 | 言語設定定義 |
