# 通知設計書 2-メールアドレス確認通知

## 概要

本ドキュメントは、Payload CMSの認証機能におけるメールアドレス確認通知の設計仕様を記述する。新規ユーザー登録時にメールアドレス確認用トークン付きのURLをメールで送信し、本人確認を行う機能の詳細を定義する。

### 本通知の処理概要

この通知は、新規ユーザー登録時にメールアドレスの有効性を確認するためのワンタイムトークン付きURLをメールで送信する機能を提供する。コレクションのauth.verifyオプションが有効な場合に自動的に発火し、ユーザーがリンクをクリックすることでメールアドレスの所有権を確認する。

**業務上の目的・背景**：ユーザーが入力したメールアドレスが実際に本人のものであることを確認し、なりすまし登録や誤入力によるアカウント作成を防止することが目的である。これにより、重要な通知が正しい受信者に届くことを保証し、アカウントの不正使用リスクを軽減する。また、GDPRなどのデータ保護規制への準拠にも寄与する。

**通知の送信タイミング**：認証が有効なコレクションでドキュメント（ユーザー）が新規作成された直後、afterChangeフックの前に送信される。具体的には、createOperation内でユーザーがDBに保存された後、verifyオプションが有効で、かつメールアドレスが設定されている場合に発火する。

**通知の受信者**：新規登録されたユーザーのメールアドレス（result.email）に送信される。disableVerificationEmailパラメータがtrueの場合は送信されない。

**通知内容の概要**：メールアドレス確認用のURL（トークン含む）、サービスのサーバーURL、確認操作の説明が含まれる。

**期待されるアクション**：受信者はメール内のリンクをクリックし、メールアドレスの確認を完了することが期待される。確認完了後、_verifiedフラグがtrueに更新される。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | なし（メール送信失敗時は例外がスローされる） |

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

1. 新規ユーザー作成（createOperation）が実行される
2. コレクションのauth.verifyオプションがtrue（または設定オブジェクト）であることを確認
3. 作成されたユーザードキュメントにemailが存在することを確認
4. disableVerificationEmail引数がfalse（または未指定）であることを確認
5. 上記条件をすべて満たす場合にsendVerificationEmail関数を呼び出す

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | `email.defaultFromAddress`（Payload設定） |
| 送信元名称 | `email.defaultFromName`（Payload設定） |
| 件名 | `req.t('authentication:verifyYourEmail')` または カスタム関数による生成 |
| 形式 | HTML |

### 本文テンプレート

```html
${req.t('authentication:newAccountCreated', {
  serverURL: config.serverURL,
  verificationURL: verificationURL
})}
```

カスタマイズ例（`generateEmailHTML`関数を設定した場合）:
```html
<h1>メールアドレスの確認</h1>
<p>以下のリンクをクリックしてメールアドレスを確認してください：</p>
<a href="${verificationURL}">メールアドレスを確認</a>
<p>このリンクは一度使用すると無効になります。</p>
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| token | 確認トークン（20バイトのランダム16進数文字列） | `crypto.randomBytes(20).toString('hex')` | Yes |
| user | ユーザードキュメント | 新規作成されたドキュメント | Yes |
| verificationURL | メールアドレス確認URL | `serverURL + adminRoute + /{collection}/verify/{token}` | Yes |
| req | PayloadRequestオブジェクト | 実行コンテキスト | Yes |
| serverURL | サーバーのベースURL | config.serverURL または リクエストから導出 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | POST `/api/{collection}` | auth.verify === true かつ disableVerificationEmail !== true かつ result.email が存在 | 認証コレクションの新規作成エンドポイント |
| ローカルAPI | payload.create() | 同上 | サーバーサイドでの新規作成 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| auth.verify === false | コレクション設定でメール確認が無効 |
| disableVerificationEmail === true | APIリクエストでメール送信を明示的に無効化 |
| result.email が未設定 | メールアドレスがないユーザーには送信不可 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[createOperation実行] --> B[beforeOperationフック実行]
    B --> C[アクセス権限チェック]
    C --> D[beforeValidate/beforeChangeフック実行]
    D --> E{auth.verify === true?}
    E -->|No| F[通常のドキュメント作成]
    E -->|Yes| G[_verificationToken生成]
    G --> H[_verified = false 設定]
    H --> I[ユーザーをDBに保存]
    I --> J{disableVerificationEmail?}
    J -->|Yes| K[メール送信スキップ]
    J -->|No| L{result.email が存在?}
    L -->|No| K
    L -->|Yes| M[sendVerificationEmail呼び出し]
    M --> N[確認URL生成]
    N --> O{カスタムgenerateEmailHTML設定?}
    O -->|Yes| P[カスタムHTML生成]
    O -->|No| Q[デフォルトHTML生成]
    P --> R[件名生成]
    Q --> R
    R --> S[email.sendEmail実行]
    S --> T[afterRead/afterChangeフック実行]
    K --> T
    F --> T
    T --> U[afterOperationフック実行]
    U --> V[ドキュメントを返却]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | 新規作成のため参照なし | - |

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

新規作成操作のため、参照処理は発生しない。

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| {認証コレクション} | INSERT | 新規ユーザーの作成（確認トークン含む） |

#### 認証コレクション挿入

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | _verified | false | 初期状態は未確認 |
| INSERT | _verificationToken | crypto.randomBytes(20).toString('hex') | 20バイトのランダムトークン |
| INSERT | email | リクエストデータ | ユーザー入力値 |
| INSERT | その他フィールド | リクエストデータ | コレクション定義に基づく |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | メールサーバー接続エラー | 例外をスロー（ユーザー作成は完了済み） |
| テンプレートエラー | カスタムgenerateEmailHTMLがエラーを投げた場合 | 例外をスロー |
| 宛先不正 | メールアドレス形式が不正 | メールサーバーからのエラーとして処理 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Payload設定に依存（デフォルトなし） |
| 1日あたり上限 | Payload設定に依存（デフォルトなし） |

### 配信時間帯

制限なし（24時間送信可能）

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

1. **トークンのランダム性**: crypto.randomBytes(20)により暗号学的に安全なランダムトークンを生成
2. **ワンタイムトークン**: 確認完了後はトークンが無効化される
3. **_verifiedフラグ**: 確認完了前は_verified=falseとなり、ログイン制限などに利用可能
4. **HTTPS**: serverURLがHTTPSを使用することを推奨
5. **メールアドレス漏洩防止**: 確認メールは登録者本人にのみ送信

## 備考

- `verify.generateEmailHTML`関数と`verify.generateEmailSubject`関数により、メールの内容と件名をカスタマイズ可能
- 確認トークンには有効期限が設定されていない（永続的に有効）ため、セキュリティ要件に応じてカスタム実装が必要な場合がある
- _verifiedがfalseのユーザーに対するログイン制限は、アプリケーション側で実装する必要がある

---

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

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

### 推奨読解順序

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

まず、verify設定の型定義とオプションを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/payload/src/auth/types.ts` | VerifyConfig型（308-311行目）とverifyオプション（300-305行目） |

**読解のコツ**: verifyはbooleanまたはVerifyConfigオブジェクトを受け取る。VerifyConfigにはgenerateEmailHTMLとgenerateEmailSubjectのカスタム関数を指定可能。

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

createOperationからの呼び出しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | create.ts | `packages/payload/src/collections/operations/create.ts` | sendVerificationEmailの呼び出し条件（347-357行目） |

**主要処理フロー**:
1. **293-297行目**: auth.verify有効時の_verificationToken生成
2. **294行目**: _verified = false の設定
3. **296行目**: トークン生成 `crypto.randomBytes(20).toString('hex')`
4. **347-357行目**: sendVerificationEmail呼び出し条件判定
5. **348-356行目**: sendVerificationEmail関数呼び出し

#### Step 3: メール送信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sendVerificationEmail.ts | `packages/payload/src/auth/sendVerificationEmail.ts` | メール送信の実装詳細 |

**主要処理フロー**:
- **22-32行目**: 引数の分解と設定取得
- **34-80行目**: メール送信処理本体
- **35-39行目**: serverURL決定ロジック
- **41-45行目**: verificationURL生成
- **47-50行目**: デフォルトHTML生成
- **52-61行目**: カスタムgenerateEmailHTML呼び出し
- **63-72行目**: カスタムgenerateEmailSubject呼び出し
- **74-79行目**: email.sendEmail実行

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

```
createOperation (collections/operations/create.ts)
    │
    ├─ buildBeforeOperation (beforeOperationフック)
    │
    ├─ executeAccess (アクセス権限チェック)
    │
    ├─ beforeValidate / beforeChange フック
    │
    ├─ registerLocalStrategy または payload.db.create
    │      └─ _verificationToken, _verified を含むドキュメント保存
    │
    ├─ sendVerificationEmail (auth/sendVerificationEmail.ts)
    │      │
    │      ├─ formatAdminURL (確認URL生成)
    │      │
    │      ├─ generateEmailHTML (カスタムまたはデフォルト)
    │      │
    │      ├─ generateEmailSubject (カスタムまたはデフォルト)
    │      │
    │      └─ email.sendEmail (メール送信)
    │
    ├─ afterRead / afterChange フック
    │
    └─ buildAfterOperation (afterOperationフック)
```

### データフロー図

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

ユーザーデータ ───▶ createOperation ───▶ 新規ユーザードキュメント
(email含む)               │
                         ├─▶ DBにユーザー保存
                         │    (_verificationToken, _verified=false)
                         │
                         └─▶ sendVerificationEmail
                                  │
                                  └─▶ 確認URL含むHTML送信
                                         │
                                         └─▶ ユーザーのメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sendVerificationEmail.ts | `packages/payload/src/auth/sendVerificationEmail.ts` | ソース | メール送信処理の実装 |
| create.ts | `packages/payload/src/collections/operations/create.ts` | ソース | 新規作成操作（呼び出し元） |
| types.ts | `packages/payload/src/auth/types.ts` | ソース | 型定義（VerifyConfig） |
| formatAdminURL.ts | `packages/payload/src/utilities/formatAdminURL.ts` | ソース | URL生成ユーティリティ |
