# 通知設計書 8-Customer Double Opt-in Registration

## 概要

本ドキュメントは、Shopwareの顧客登録におけるダブルオプトイン確認メール「Customer Double Opt-in Registration」の設計書である。この通知は、顧客登録時にダブルオプトイン方式が有効な場合に送信される確認メールである。

### 本通知の処理概要

Customer Double Opt-in Registration通知は、システム設定でダブルオプトインが有効な場合に、顧客登録時に送信される確認メールである。登録を完了するための確認リンクを含む。

**業務上の目的・背景**：GDPR対応およびスパム登録防止のため、顧客登録時にメールアドレスの所有者確認が必要な場合がある。ダブルオプトイン方式により、不正なアカウント作成を防止し、メールアドレスの正当な所有者のみが登録を完了できるようにする。

**通知の送信タイミング**：システム設定（core.loginRegistration.doubleOptInRegistration）が有効な場合、顧客登録処理完了後にCustomerDoubleOptInRegistrationEventがディスパッチされてメールが送信される。

**通知の受信者**：登録を試みた顧客。CustomerEntityから取得したメールアドレスに送信される。

**通知内容の概要**：登録確認を求めるメール。確認用URL（confirmUrl）が含まれる。テンプレートタイプは「customer_register.double_opt_in」。

**期待されるアクション**：受信者はメール内の確認リンクをクリックして、アカウント登録を確定する。確認しない場合、アカウントは有効化されない。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（Flow/イベント駆動） |
| 優先度 | 高（確認待ちのため） |
| リトライ | メール送信基盤の設定に依存 |

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

1. CustomerDoubleOptInRegistrationEventからMailRecipientStructを取得
2. customer.getEmail()でメールアドレスを取得
3. firstName + lastNameを受信者名として使用

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | システム設定による |
| 送信元名称 | システム設定による |
| 件名 | テンプレートによる |
| 形式 | HTML/テキスト |

### 本文テンプレート

```
テンプレートタイプ: customer_register.double_opt_in

利用可能変数:
- customer: 顧客エンティティ
- confirmUrl: 確認用URL（完全なURL）
- salesChannel: 販売チャネル情報
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| customer | 顧客情報 | CustomerEntity | Yes |
| confirmUrl | 確認用URL | getConfirmUrl()生成 | Yes |
| salesChannel | 販売チャネル情報 | SalesChannelContext | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | POST /store-api/account/register | doubleOptIn有効、guest=false | 顧客登録API |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| doubleOptIn無効 | 直接CustomerRegisterEventを発火 |
| ゲスト登録 | DoubleOptInGuestOrderEventを使用 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[顧客登録リクエスト] --> B[POST /store-api/account/register]
    B --> C[バリデーション]
    C --> D[顧客データ作成]
    D --> E{doubleOptIn設定?}
    E -->|有効| F{guest?}
    E -->|無効| G[CustomerRegisterEvent]
    F -->|false| H[CustomerDoubleOptInRegistrationEvent]
    F -->|true| I[DoubleOptInGuestOrderEvent]
    H --> J[Flow/メール送信処理]
    J --> K[確認メール送信]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| customer | 顧客情報取得 | 登録データ |
| system_config | 設定値取得 | doubleOptIn設定 |
| sales_channel_domain | ドメイン情報 | URL生成 |

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

#### customer

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 識別子 | 登録後取得 |
| email | メールアドレス | メール送信先、URL生成 |
| hash | 確認用ハッシュ | URL生成 |
| double_opt_in_registration | DOIフラグ | 確認要否判定 |
| double_opt_in_email_sent_date | DOI送信日時 | 記録 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| customer | INSERT | 顧客レコード作成（DOI情報含む） |

#### customer

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | double_opt_in_registration | true | DOIフラグ |
| INSERT | double_opt_in_email_sent_date | new DateTimeImmutable() | 送信日時 |
| INSERT | hash | Uuid::randomHex() | 確認用ハッシュ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バリデーションエラー | 必須項目不足 | ConstraintViolationException |
| URL不正 | storefrontUrlが許可リストにない | バリデーションエラー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | メール送信基盤設定に依存 |
| リトライ間隔 | メール送信基盤設定に依存 |
| リトライ対象エラー | 一時的な送信失敗 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし |

### 配信時間帯

制限なし

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

- SHA1ハッシュによるメールアドレスエンコード（URL用）
- 確認用ハッシュはUUID（推測困難）
- storefrontUrl検証
- 確認済みでないアカウントは一部機能制限

## 備考

- イベント名: checkout.customer.double_opt_in_registration（旧名）→ customer.double_opt_in_registration（EVENT_NAME定数）
- テンプレートタイプ: customer_register.double_opt_in（MAILTYPE_CUSTOMER_REGISTER_DOUBLE_OPT_IN）
- 確認URL形式: /registration/confirm?em=%%HASHEDEMAIL%%&hash=%%SUBSCRIBEHASH%%
- ゲスト注文の場合はDoubleOptInGuestOrderEventを使用

---

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

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

### 推奨読解順序

#### Step 1: イベントクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomerDoubleOptInRegistrationEvent.php | `src/Core/Checkout/Customer/Event/CustomerDoubleOptInRegistrationEvent.php` | イベント構造、confirmUrl変数を確認 |

**読解のコツ**: ScalarValuesAwareインターフェースにより、confirmUrlがメールテンプレートで利用可能になる。

#### Step 2: 登録処理でのイベント発火を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RegisterRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterRoute.php` | getDoubleOptInEvent()メソッドを確認 |

**主要処理フロー**:
1. **行269-290**: getDoubleOptInEvent() - イベント生成
2. **行276**: 確認URL生成
3. **行286**: CustomerDoubleOptInRegistrationEvent生成

#### Step 3: 確認URL生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | RegisterRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterRoute.php` | getConfirmUrl()メソッドを確認 |

**主要処理フロー**:
- **行622-642**: getConfirmUrl() - URL生成

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

```
POST /store-api/account/register
    │
    └─ RegisterRoute::register()
           │
           ├─ addDoubleOptInData()
           │      │
           │      └─ systemConfigService::get('core.loginRegistration.doubleOptInRegistration')
           │             │
           │             └─ [有効] customer['doubleOptInRegistration'] = true
           │                       customer['hash'] = Uuid::randomHex()
           │
           ├─ customerRepository::create()
           │
           └─ [doubleOptIn有効]
                  │
                  └─ getDoubleOptInEvent()
                         │
                         ├─ getConfirmUrl()
                         │      │
                         │      ├─ systemConfigService::get('core.loginRegistration.confirmationUrl')
                         │      │
                         │      └─ CustomerConfirmRegisterUrlEvent
                         │
                         └─ CustomerDoubleOptInRegistrationEvent
                                │
                                └─ EventDispatcher::dispatch()
```

### データフロー図

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

RequestDataBag           RegisterRoute                   CustomerResponse
- email                  register()                      (hashは空文字に設定)
- password                    │
- storefrontUrl               ▼
                         doubleOptIn判定
                         [有効]
                              │
                              ▼
                         顧客データ作成
                         - doubleOptInRegistration: true
                         - hash: UUID
                         - doubleOptInEmailSentDate: now
                              │
                              ▼
                         確認URL生成
                         storefrontUrl + /registration/confirm
                         ?em=%%HASHEDEMAIL%%
                         &hash=%%SUBSCRIBEHASH%%
                              │
                              ▼
                         CustomerDoubleOptInRegistrationEvent
                         - customer
                         - confirmUrl
                         - salesChannelContext
                              │
                              ▼
                         Flow/Mail送信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RegisterRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterRoute.php` | ソース | 登録APIエンドポイント |
| CustomerDoubleOptInRegistrationEvent.php | `src/Core/Checkout/Customer/Event/CustomerDoubleOptInRegistrationEvent.php` | ソース | イベントクラス |
| DoubleOptInGuestOrderEvent.php | `src/Core/Checkout/Customer/Event/DoubleOptInGuestOrderEvent.php` | ソース | ゲスト用イベント |
| CustomerConfirmRegisterUrlEvent.php | `src/Core/Checkout/Customer/Event/CustomerConfirmRegisterUrlEvent.php` | ソース | URL変更イベント |
| MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | ソース | テンプレートタイプ定義 |
| RegisterConfirmRoute.php | `src/Core/Checkout/Customer/SalesChannel/RegisterConfirmRoute.php` | ソース | 確認APIエンドポイント |
