# 通知設計書 4-Newsletter Confirm

## 概要

本ドキュメントは、Shopwareのニュースレター登録確認完了時に送信される「Newsletter Confirm」メール通知の設計書である。この通知は、ユーザーがダブルオプトイン確認を完了した後、または直接登録が完了した際に送信される確認メールである。

### 本通知の処理概要

Newsletter Confirm通知は、ニュースレター登録が正式に完了したことをユーザーに通知するメールである。ダブルオプトイン確認後、または直接登録モードでの登録完了時に送信される。

**業務上の目的・背景**：ニュースレター登録が正式に完了したことをユーザーに明確に伝え、今後のニュースレター配信に対する期待と信頼を構築する。また、登録が完了した記録としてユーザーに保持してもらう目的もある。

**通知の送信タイミング**：NewsletterConfirmEventがディスパッチされた時点。このイベントは以下の2つのシナリオで発火する：
1. ユーザーが確認URLをクリックしてダブルオプトイン確認を完了した時（NewsletterConfirmRoute）
2. システム設定でダブルオプトインが無効な場合の直接登録完了時（NewsletterSubscribeRoute）

**通知の受信者**：ニュースレター登録を完了したユーザー。NewsletterRecipientEntityから取得したメールアドレスに送信される。

**通知内容の概要**：ニュースレター登録完了を伝えるメール。テンプレートタイプは「newsletter_confirmed」。受信者の名前やメールアドレス、販売チャネル情報を含む。

**期待されるアクション**：受信者は登録完了を確認し、今後のニュースレター配信を待つ。不正な登録の場合は、購読解除手続きを行う。

## 通知種別

メール通知

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

```
テンプレートタイプ: newsletter_confirmed

利用可能変数:
- newsletterRecipient: ニュースレター受信者エンティティ
- salesChannel: 販売チャネル情報
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| newsletterRecipient | ニュースレター受信者情報 | NewsletterRecipientEntity | Yes |
| salesChannel | 販売チャネル情報 | SalesChannelContext | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | POST /store-api/newsletter/confirm | hash検証成功、ステータス更新完了 | 確認API |
| API | POST /store-api/newsletter/subscribe | doubleOptIn無効、かつ未確認登録 | 直接登録 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 既に確認済み | confirmedAtが設定済み、かつstatusがoptOutでない場合 |
| ハッシュ不一致 | 確認URLのハッシュが一致しない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[確認URLクリック / 直接登録] --> B{処理ルート}
    B -->|確認URLクリック| C[POST /store-api/newsletter/confirm]
    B -->|直接登録| D[POST /store-api/newsletter/subscribe]
    C --> E[hash検証]
    E -->|OK| F[status=optIn, confirmedAt=now]
    E -->|NG| Z[エラーレスポンス]
    D --> G{doubleOptIn?}
    G -->|無効| H[status=direct]
    G -->|有効| I[Registerイベント発火]
    F --> J[NewsletterConfirmEventディスパッチ]
    H --> J
    J --> K[Flow/メール送信処理]
    K --> L[確認完了メール送信]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| newsletter_recipient | 受信者情報取得 | ハッシュ検証、メール送信 |
| salutation | 敬称情報 | アソシエーション |

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

#### newsletter_recipient

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 識別子 | PRIMARY KEY |
| hash | ハッシュ検証 | WHERE hash = :hash |
| email | メールアドレス | メール送信先 |
| first_name | 名 | 受信者名 |
| last_name | 姓 | 受信者名 |
| status | 現在状態 | 更新前確認 |
| confirmed_at | 確認日時 | 重複確認防止 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| newsletter_recipient | UPDATE | ステータスと確認日時の更新 |

#### newsletter_recipient

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | status | 'optIn' | 確認完了 |
| UPDATE | confirmed_at | new DateTime() | 確認日時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 受信者不存在 | ハッシュに対応するレコードなし | NewsletterException::recipientNotFound |
| ハッシュ不一致 | em（メールハッシュ）が不一致 | バリデーションエラー |
| 既に確認済み | status != notSet | 何もしない（エラーなし） |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（確認操作はレート制限対象外） |

### 配信時間帯

制限なし（確認操作発生時即時）

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

- SHA1ハッシュによるメールアドレス検証
- 確認用ハッシュによる正当なリクエスト検証
- 一度確認済みの場合は再確認しない（冪等性）

## 備考

- イベント名: newsletter.confirm
- テンプレートタイプ: newsletter_confirmed（MAILTYPE_NEWSLETTER_CONFIRMED）
- 確認URL形式: /newsletter-subscribe?em=%%HASHEDEMAIL%%&hash=%%SUBSCRIBEHASH%%

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | NewsletterConfirmEvent.php | `src/Core/Content/Newsletter/Event/NewsletterConfirmEvent.php` | イベントクラス、利用可能データを確認 |

**読解のコツ**: イベントクラスが実装するインターフェース（MailAware, FlowEventAware等）を確認することで、このイベントの用途がわかる。

#### Step 2: 確認APIエンドポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NewsletterConfirmRoute.php | `src/Core/Content/Newsletter/SalesChannel/NewsletterConfirmRoute.php` | 確認処理フローを確認 |

**主要処理フロー**:
1. **行49-71**: confirm() - 確認処理メイン
2. **行52**: hash検索
3. **行61**: em（メールハッシュ）検証
4. **行63-64**: ステータス更新
5. **行68-69**: イベントディスパッチ

#### Step 3: 直接登録時のイベント発火を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NewsletterSubscribeRoute.php | `src/Core/Content/Newsletter/SalesChannel/NewsletterSubscribeRoute.php` | doubleOptIn無効時の処理 |

**主要処理フロー**:
- **行170-175**: doubleOptIn無効時のConfirmイベント発火

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

```
[シナリオ1: 確認URLクリック]
POST /store-api/newsletter/confirm
    │
    └─ NewsletterConfirmRoute::confirm()
           │
           ├─ getNewsletterRecipient() ─── hash検索
           │
           ├─ DataValidator::validate() ─── em検証
           │
           ├─ newsletterRecipientRepository::update()
           │      - status: optIn
           │      - confirmedAt: now
           │
           └─ EventDispatcher::dispatch(NewsletterConfirmEvent)

[シナリオ2: 直接登録]
POST /store-api/newsletter/subscribe (doubleOptIn=false)
    │
    └─ NewsletterSubscribeRoute::subscribe()
           │
           ├─ newsletterRecipientRepository::upsert()
           │      - status: direct
           │
           └─ EventDispatcher::dispatch(NewsletterConfirmEvent)
```

### データフロー図

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

RequestDataBag           NewsletterConfirmRoute          NoContentResponse
- hash                   confirm()
- em (hashedEmail)            │
                              ▼
                         hash検索
                         newsletter_recipient
                              │
                              ▼
                         em検証（SHA1比較）
                              │
                              ▼
                         ステータス更新
                         - status: optIn
                         - confirmedAt: now
                              │
                              ▼
                         NewsletterConfirmEvent
                         - context
                         - newsletterRecipient
                         - salesChannelId
                              │
                              ▼
                         Flow/Mail送信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NewsletterConfirmRoute.php | `src/Core/Content/Newsletter/SalesChannel/NewsletterConfirmRoute.php` | ソース | 確認APIエンドポイント |
| NewsletterConfirmEvent.php | `src/Core/Content/Newsletter/Event/NewsletterConfirmEvent.php` | ソース | イベントクラス |
| NewsletterSubscribeRoute.php | `src/Core/Content/Newsletter/SalesChannel/NewsletterSubscribeRoute.php` | ソース | 直接登録時のイベント発火 |
| MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | ソース | テンプレートタイプ定義 |
| NewsletterRecipientDefinition.php | `src/Core/Content/Newsletter/Aggregate/NewsletterRecipient/NewsletterRecipientDefinition.php` | ソース | エンティティ定義 |
