# 通知設計書 14-Guest Order Double Opt-in

## 概要

本ドキュメントは、Shopwareにおけるゲスト注文ダブルオプトイン通知（Guest Order Double Opt-in）の設計仕様を記載したものです。ゲスト（未登録顧客）が注文を行う際に、メールアドレスの確認を求めるダブルオプトイン機能のメール通知について定義します。

### 本通知の処理概要

この通知は、ゲストユーザーが注文を行う際にメールアドレスの有効性を確認するためのダブルオプトイン機能です。ゲストが確認リンクをクリックすることで、注文処理を継続できるようになります。

**業務上の目的・背景**：ゲスト注文においても、メールアドレスの有効性を確認することは重要です。誤ったメールアドレスでの注文を防止し、注文確認メールや配送通知が確実に届くことを保証します。また、スパム注文やボットによる不正注文の防止にも貢献します。

**通知の送信タイミング**：ゲストがチェックアウト画面で注文情報を入力し、確認を求められた際に`DoubleOptInGuestOrderEvent`がディスパッチされ、確認メールが送信されます。

**通知の受信者**：ゲスト顧客が入力したメールアドレス。

**通知内容の概要**：確認用URL（confirmUrl）、ショップ名、確認の説明文が含まれます。

**期待されるアクション**：ゲストは受信したメールの確認リンクをクリックし、メールアドレスの有効性を証明します。クリック後、注文処理が継続され、最終確認画面に遷移します。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（Flow経由） |
| 優先度 | 高（注文フローを阻害するため） |
| リトライ | Flowの設定に依存 |

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

イベント発生時に`MailRecipientStruct`が構築されます。

```php
// DoubleOptInGuestOrderEvent.php 行56-65
public function getMailStruct(): MailRecipientStruct
{
    if (!$this->mailRecipientStruct instanceof MailRecipientStruct) {
        $this->mailRecipientStruct = new MailRecipientStruct([
            $this->customer->getEmail() => $this->customer->getFirstName() . ' ' . $this->customer->getLastName(),
        ]);
    }

    return $this->mailRecipientStruct;
}
```

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | `{{ salesChannel.name }}`（動的） |
| 送信元名称 | `{{ salesChannel.name }}` |
| 件名 | `Please confirm your email address at {{ salesChannel.name }}`（EN）/ `Bitte bestätigen Sie Ihre E-Mail-Adresse bei {{ salesChannel.name }}`（DE） |
| 形式 | HTML/テキスト |

### 本文テンプレート

**英語版（HTML）**:
```html
<div style="font-family:arial; font-size:12px;">
    <p>
        Hello {{ customer.salutation.displayName }} {{ customer.lastName }},<br/>
        <br/>
        Please confirm your email address via the following link:<br/>
        <br/>
        <a href="{{ confirmUrl }}">Confirm email</a><br/>
        <br/>
        After the confirmation, you will be directed to the checkout, where you can check and complete your order again.<br/>
        By this confirmation, you also agree that we may send you further emails as part of the fulfillment of the contract.
    </p>
</div>
```

**ドイツ語版（HTML）**:
```html
<div style="font-family:arial; font-size:12px;">
    <p>
        Hallo {{ customer.salutation.displayName }} {{ customer.lastName }},<br/>
        <br/>
        Bitte bestätigen Sie Ihre E-Mail-Adresse über den nachfolgenden Link:<br/>
        <br/>
        <a href="{{ confirmUrl }}">E-Mail bestätigen</a><br/>
        <br/>
        Nach der Bestätigung werden Sie in den Bestellabschluss geleitet, dort können Sie Ihre Bestellung nochmals überprüfen und abschließen.<br/>
        Durch diese Bestätigung erklären Sie sich ebenso damit einverstanden, dass wir Ihnen im Rahmen der Vertragserfüllung weitere E-Mails senden dürfen.
    </p>
</div>
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 本通知には添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `customer` | 顧客エンティティ（ゲスト） | CustomerEntity | Yes |
| `customer.salutation.displayName` | 敬称の表示名 | customer.salutation | No |
| `customer.lastName` | 顧客の姓 | customer.last_name | Yes |
| `customer.firstName` | 顧客の名 | customer.first_name | Yes |
| `customer.email` | 顧客のメールアドレス | customer.email | Yes |
| `confirmUrl` | メールアドレス確認用URL | イベント生成時に構築 | Yes |
| `salesChannel` | 販売チャネル | SalesChannelContext | Yes |
| `salesChannel.name` | 販売チャネル名 | sales_channel_translation.name | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | `checkout.customer.double_opt_in_guest_order` | ゲスト注文時のダブルオプトイン有効時 | チェックアウト画面での確認要求 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ダブルオプトインが無効 | システム設定でゲスト注文のダブルオプトインが無効の場合 |
| 登録済み顧客 | ログイン済みの登録顧客の場合は発火しない |
| Flowが設定されていない | Flowビルダーでメール送信アクションが設定されていない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ゲストがチェックアウト開始] --> B{ダブルオプトイン有効?}
    B -->|有効| C[DoubleOptInGuestOrderEvent発火]
    B -->|無効| D[通常の注文フロー]
    C --> E[Flowエンジンがイベントを検知]
    E --> F[SendMailAction実行]
    F --> G[確認メール送信]
    G --> H[ゲストがメール受信]
    H --> I{確認リンクをクリック}
    I -->|クリック| J[メールアドレス確認完了]
    I -->|未クリック| K[注文処理保留]
    J --> L[チェックアウト継続]
    D --> L
    K --> M[タイムアウト]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| customer | ゲスト顧客情報 | 一時的に作成されたゲスト顧客 |
| salutation | 敬称情報 | テンプレート変数 |
| sales_channel | 販売チャネル情報 | コンテキスト |
| sales_channel_translation | 販売チャネルの翻訳 | ショップ名取得 |
| mail_template | メールテンプレート | technical_name = 'guest_order.double_opt_in' |

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

#### customer

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 顧客識別 | ゲスト顧客ID |
| email | メール送信先、テンプレート変数 | - |
| first_name | テンプレート変数 | - |
| last_name | テンプレート変数 | - |
| salutation_id | 敬称取得 | JOIN salutation |
| guest | ゲストフラグ | true |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| customer | UPDATE | 確認完了時にdouble_opt_in_confirmationフラグ更新 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| メール送信失敗 | SMTPエラー等 | ログ記録、ユーザーへのエラー表示 |
| 確認URL期限切れ | 一定時間経過後のクリック | 再送信を促すエラーページ表示 |
| テンプレートエラー | 変数の未定義等 | ログ記録、フォールバックテンプレート使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Flowの設定に依存 |
| リトライ間隔 | Flowの設定に依存 |
| リトライ対象エラー | 一時的なネットワークエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | システム設定に依存 |
| 1日あたり上限 | システム設定に依存 |

### 配信時間帯

制限なし（リアルタイム送信）

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

- 確認URLにはユニークなトークンを含め、推測困難にする
- 確認URLには有効期限を設定し、期限切れ後は無効化
- 同一メールアドレスへの連続送信に対するレート制限
- 確認完了後はトークンを無効化し、再利用を防止

## 備考

- このイベントは`ScalarValuesAware`インターフェースを実装しており、`confirmUrl`を`getValues()`メソッドで取得可能
- 確認URLはイベント生成時にシステムが自動的に構築
- ゲスト注文のダブルオプトインはシステム設定で有効/無効を切り替え可能

---

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

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

### 推奨読解順序

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

まず、イベントで扱われるデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DoubleOptInGuestOrderEvent.php | `src/Core/Checkout/Customer/Event/DoubleOptInGuestOrderEvent.php` | イベントクラスの構造、confirmUrl、ScalarValuesAware実装 |
| 1-2 | CustomerEntity.php | `src/Core/Checkout/Customer/CustomerEntity.php` | ゲスト顧客の構造 |

**読解のコツ**: `ScalarValuesAware`インターフェースにより、`confirmUrl`がFlowアクションで利用可能になる点に注目。

#### Step 2: イベント発火の仕組みを理解する

処理の起点となるルートを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RegisterRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterRoute.php` | ゲスト顧客登録とダブルオプトインの発火 |

**主要処理フロー**:
- ゲスト顧客の作成
- ダブルオプトイン設定の確認
- 確認URLの生成
- DoubleOptInGuestOrderEventのディスパッチ

#### Step 3: テンプレートを理解する

メールテンプレートの内容を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Migration1573569685DoubleOptInGuestMailTemplate.php | `src/Core/Migration/V6_3/Migration1573569685DoubleOptInGuestMailTemplate.php` | テンプレート登録、内容定義 |

**主要処理フロー**:
1. **行56-66**: テンプレートタイプの登録（`guest_order.double_opt_in`）
2. **行110-174**: テンプレート翻訳の登録
3. **行176-189**: イベントアクションの登録

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

```
ゲストチェックアウト
    │
    ▼
RegisterRoute::register()
    │
    ├─ 顧客データ作成（guest=true）
    │
    ├─ ダブルオプトイン設定確認
    │
    └─ [ダブルオプトイン有効時]
           │
           ├─ 確認URL生成
           │
           └─ eventDispatcher->dispatch(DoubleOptInGuestOrderEvent)
                  │
                  └─ FlowExecutor (Subscriber)
                         │
                         └─ SendMailAction::handleFlow()
                                │
                                └─ emailService->send()
```

### データフロー図

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

チェックアウト情報          RegisterRoute
(email, name等) ───────────▶ ゲスト顧客作成
                                   │
                                   ▼
                            ダブルオプトイン確認
                                   │
                           ┌───────┴───────┐
                           │有効           │無効
                           ▼               ▼
                    確認URL生成       通常フロー
                           │
                           ▼
DoubleOptInGuestOrder   イベント発火
Event ◀────────────────────┘
      │
      ▼
Flow Engine            SendMailAction
      │                      │
      ▼                      ▼
MailTemplate           メール送信
(confirmUrl含む) ─────▶ (ゲストへ)
                              │
                              ▼
                       確認リンククリック
                              │
                              ▼
                       RegisterConfirmRoute
                              │
                              ▼
                       注文フロー継続
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DoubleOptInGuestOrderEvent.php | `src/Core/Checkout/Customer/Event/DoubleOptInGuestOrderEvent.php` | ソース | イベントクラス定義 |
| RegisterRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterRoute.php` | ソース | 顧客登録ルート |
| RegisterConfirmRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterConfirmRoute.php` | ソース | 確認ルート |
| SendMailAction.php | `src/Core/Content/Flow/Dispatching/Action/SendMailAction.php` | ソース | メール送信アクション |
| MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | ソース | テンプレートタイプ定数（行42） |
| Migration1573569685DoubleOptInGuestMailTemplate.php | `src/Core/Migration/V6_3/Migration1573569685DoubleOptInGuestMailTemplate.php` | マイグレーション | テンプレート登録 |
