# 通知設計書 42-Contact Form

## 概要

本ドキュメントは、Shopwareにおけるお問い合わせフォーム送信時のメール通知仕様を定義する設計書である。顧客がストアフロントからお問い合わせフォームを送信した際に、店舗管理者および顧客自身に通知メールを送信する機能について記載する。

### 本通知の処理概要

本通知は、ストアフロント上のお問い合わせフォームから送信されたメッセージを、指定された受信者（通常は店舗管理者）に転送するメール通知である。CMSのフォーム要素として実装されており、受信者や確認メッセージはCMS設定でカスタマイズ可能である。

**業務上の目的・背景**：顧客からの問い合わせ、フィードバック、サポートリクエストを受け付けるためのコミュニケーションチャネルを提供する。店舗運営において顧客対応は重要な業務であり、問い合わせ内容を確実に担当者へ届けることで、迅速な顧客対応を実現する。

**通知の送信タイミング**：顧客がストアフロントのお問い合わせフォームで「送信」ボタンをクリックし、バリデーションが成功した直後に送信される。ContactFormEventが発火されることでFlowビルダーのトリガーとなる。

**通知の受信者**：CMSスロット設定で指定されたメールアドレス、またはシステム設定の`core.basicInformation.email`で設定されたショップのメールアドレスが受信者となる。Flowビルダーの設定により、問い合わせ送信者への確認メール送信も可能。

**通知内容の概要**：送信者名、メールアドレス、電話番号、件名、メッセージ本文などのフォーム入力内容が含まれる。

**期待されるアクション**：店舗管理者は問い合わせ内容を確認し、顧客に対して適切な返信・対応を行う。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（Flowビルダー経由） |
| 優先度 | 中 |
| リトライ | 有・3回 |

### 送信先決定ロジック

1. CMSスロット設定の`mailReceiver`に指定されたメールアドレスを優先
2. カテゴリ・ランディングページ・商品ページのスロット設定を確認
3. 上記が未設定の場合、システム設定`core.basicInformation.email`のメールアドレスを使用

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | システム設定 `core.basicInformation.email` |
| 送信元名称 | 問い合わせ送信者名（設定可能） |
| 件名 | Contact form received |
| 形式 | HTML/テキスト |

### 本文テンプレート

```twig
<div style="font-family:arial; font-size:12px;">
    <p>
        The following Message was sent to you via the contact form.<br/>
        <br/>
        Contact name: {{ contactFormData.firstName }} {{ contactFormData.lastName }}
        <br/>
        Contact email address: {{ contactFormData.email }}
        <br/>
        Phone: {{ contactFormData.phone }}<br/>
        <br/>
        Subject: {{ contactFormData.subject }}<br/>
        <br/>
        Message:<br/>
        {{ contactFormData.comment|nl2br }}<br/>
    </p>
</div>
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイル機能は標準では未対応 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| contactFormData | フォーム送信データ全体 | ContactFormEvent | Yes |
| contactFormData.firstName | 送信者の名 | フォーム入力 | Yes |
| contactFormData.lastName | 送信者の姓 | フォーム入力 | Yes |
| contactFormData.email | 送信者メールアドレス | フォーム入力 | Yes |
| contactFormData.phone | 送信者電話番号 | フォーム入力 | No |
| contactFormData.subject | 件名 | フォーム入力 | Yes |
| contactFormData.comment | メッセージ本文 | フォーム入力 | Yes |
| contactFormData.salutation | 敬称 | salutationテーブル参照 | No |
| salesChannel | 販売チャネル情報 | sales_channel テーブル | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | POST /store-api/contact-form | バリデーション成功 | Store APIからのリクエスト |
| Flowアクション | contact_form.send | Flow条件一致 | ContactFormEvent発火時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| バリデーションエラー | 必須フィールド未入力時 |
| レート制限超過 | 短時間に大量送信を検知した場合 |
| メール受信者未設定 | CMSスロット設定とシステム設定の両方が空の場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[顧客がフォーム送信] --> B[ContactFormRoute::load]
    B --> C[メールアドレスIDN変換]
    C --> D[バリデーション実行]
    D -->|エラー| E[例外スロー]
    D -->|成功| F[レート制限チェック]
    F -->|超過| G[429エラー]
    F -->|OK| H[メール受信者取得]
    H --> I[ContactFormEvent発火]
    I --> J[Flowビルダー処理]
    J --> K[SendMailAction実行]
    K --> L[メール送信]
    L --> M{送信結果}
    M -->|成功| N[成功レスポンス]
    M -->|失敗| O[エラーログ記録]
    N --> P[終了]
    O --> P
    E --> P
    G --> P
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| cms_slot | スロット設定取得 | メール受信者設定 |
| salutation | 敬称マスタ | 送信者の敬称取得 |
| category | カテゴリ情報 | スロット設定取得 |
| landing_page | ランディングページ | スロット設定取得 |
| product | 商品情報 | 商品ページからの問い合わせ時 |
| mail_template | メールテンプレート | contact_form |
| mail_template_type | テンプレートタイプ | technical_name = 'contact_form' |

### テーブル別参照項目詳細

#### cms_slot

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| config | スロット設定JSON | id = slotId |
| translated.config | 翻訳済み設定 | 言語IDに基づく |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | データベースへの書き込みなし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バリデーションエラー | 必須フィールド未入力 | ConstraintViolationException |
| レート制限 | 短時間に大量リクエスト | RateLimiter::CONTACT_FORMで制御 |
| 送信失敗 | SMTPサーバーエラー | エラーログ記録、MailErrorEvent発火 |
| テンプレートエラー | Twigレンダリング失敗 | エラーログ記録 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 3回 |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | 一時的な送信エラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 3回（デフォルト設定） |
| 1日あたり上限 | システム設定に依存 |

### 配信時間帯

制限なし

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

- XSS対策：Twigのエスケープ機能による出力サニタイズ
- レート制限：RateLimiter::CONTACT_FORMによるスパム防止
- メールアドレスバリデーション：EmailIdnConverter使用
- CSRF対策：Store APIの標準トークン検証

## 備考

- MailTemplateTypes::MAILTYPE_CONTACT_FORM 定数で定義
- CMSフォーム要素として実装（cms-element-form.html.twig）
- 受信者をFlowビルダーで柔軟に設定可能（管理者/カスタム/送信者）

---

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

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

### 推奨読解順序

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

お問い合わせフォームで使用されるイベントクラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ContactFormEvent.php | `src/Core/Content/ContactForm/Event/ContactFormEvent.php` | イベント名 contact_form.send（21行目）、フォームデータの構造（26-35行目） |

**読解のコツ**: ContactFormEventはMailAware、SalesChannelAware、FlowEventAwareを実装しており、Flowビルダーでの利用が可能。contactFormDataプロパティにフォーム送信内容が格納される。

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

API経由でのフォーム送信処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ContactFormRoute.php | `src/Core/Content/ContactForm/SalesChannel/ContactFormRoute.php` | load()メソッド（67行目〜）がエントリーポイント |

**主要処理フロー**:
1. **69行目**: EmailIdnConverter::encodeDataBag() - メールアドレスのIDN変換
2. **71行目**: validateContactForm() - フォームバリデーション
3. **73-75行目**: レート制限チェック（RateLimiter::CONTACT_FORM）
4. **77行目**: getMailConfigs() - メール受信者設定取得
5. **86-88行目**: 受信者未設定時のフォールバック処理
6. **96-101行目**: ContactFormEvent生成
7. **103-106行目**: イベントディスパッチ

#### Step 3: メール受信者決定ロジックを理解する

CMSスロットからの設定取得を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ContactFormRoute.php | `src/Core/Content/ContactForm/SalesChannel/ContactFormRoute.php` | getMailConfigs()（160行目〜）、getSlotConfig()（129行目〜） |

**主要処理フロー**:
- **129-155行目**: カテゴリ/ランディングページ/商品からスロット設定取得
- **177-189行目**: CMSスロットから直接設定取得
- **151-152行目**: mailReceiver と confirmationText の取得

#### Step 4: メールテンプレートを理解する

テンプレートファイルの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | en-html.html.twig | `src/Core/Migration/Fixtures/mails/contact_form/en-html.html.twig` | テンプレート変数の使用方法 |

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

```
FormController (Storefront)
    │
    └─ ContactFormRoute::load()
           │
           ├─ EmailIdnConverter::encodeDataBag() - IDN変換
           │
           ├─ validateContactForm() - バリデーション
           │      └─ ContactFormValidationFactory
           │
           ├─ RateLimiter::ensureAccepted() - レート制限
           │
           ├─ getMailConfigs() - 受信者設定取得
           │      ├─ getSlotConfig() - スロット設定
           │      └─ SystemConfigService - フォールバック
           │
           └─ EventDispatcher::dispatch(ContactFormEvent)
                  │
                  └─ Flow Engine
                         │
                         └─ SendMailAction::handleFlow()
                                │
                                └─ MailService::send()
```

### データフロー図

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

POST /store-api/contact-form    ContactFormRoute::load()            ContactFormEvent
  │                                  │                                    │
  ├─ firstName                       ├─ バリデーション                     ├─ contact_form.send イベント
  ├─ lastName                        ├─ レート制限チェック                 │
  ├─ email                           ├─ 受信者決定                        ▼
  ├─ phone                           └─ イベント発火                  Flow Engine
  ├─ subject                                                              │
  └─ comment                                                              ▼
                                                                    SendMailAction
                                                                          │
                                                                          ▼
                                                                    Contact Form Email
                                                                    (to: 店舗管理者)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ContactFormEvent.php | `src/Core/Content/ContactForm/Event/ContactFormEvent.php` | ソース | お問い合わせフォームイベント |
| ContactFormRoute.php | `src/Core/Content/ContactForm/SalesChannel/ContactFormRoute.php` | ソース | Store API エンドポイント |
| ContactFormValidationFactory.php | `src/Core/Content/ContactForm/Validation/ContactFormValidationFactory.php` | ソース | バリデーション定義 |
| FormController.php | `src/Storefront/Controller/FormController.php` | ソース | Storefrontコントローラー |
| MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | ソース | MAILTYPE_CONTACT_FORM定数 |
| en-html.html.twig | `src/Core/Migration/Fixtures/mails/contact_form/en-html.html.twig` | テンプレート | 英語HTMLテンプレート |
| en-plain.html.twig | `src/Core/Migration/Fixtures/mails/contact_form/en-plain.html.twig` | テンプレート | 英語プレーンテキスト |
| de-html.html.twig | `src/Core/Migration/Fixtures/mails/contact_form/de-html.html.twig` | テンプレート | ドイツ語HTMLテンプレート |
| cms-element-form.html.twig | `src/Storefront/Resources/views/storefront/element/cms-element-form.html.twig` | テンプレート | CMSフォーム要素 |
| contact_form.xml | `src/Core/Content/DependencyInjection/contact_form.xml` | 設定 | DIコンテナ設定 |
