# 通知設計書 60-enabled_two_factor_otp_email

## 概要

本ドキュメントは、GitLabにおけるワンタイムパスワード認証有効化通知（enabled_two_factor_otp_email）の設計内容を記載する。

### 本通知の処理概要

**業務上の目的・背景**：2要素認証（2FA）の設定変更は、アカウントセキュリティに直接影響する重要な操作である。ワンタイムパスワード（OTP）認証が有効化された際にユーザーに通知することで、意図しない設定変更や不正アクセスによる2FA有効化の検知を可能にし、アカウントの安全性を確保する。

**通知の送信タイミング**：ユーザーがOTP認証器（Google Authenticatorなど）を正常に登録し、2FAを有効化した時点で即座に通知が送信される。

**通知の受信者**：2FAを有効化したユーザー本人。ユーザーが通知を受信できる権限（receive_notifications）を持っている必要がある。

**通知内容の概要**：OTP認証器が登録されたことの通知と、2FA設定管理画面への案内が含まれる。

**期待されるアクション**：受信者は通知を受け取った後、自身による操作であれば確認のみ、心当たりがない場合はすぐにアカウントのセキュリティを確認する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 中 |
| リトライ | Sidekiq標準リトライ機構に依存 |

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

2FAを有効化したユーザーの`notification_email_or_default`メソッドで取得されるメールアドレスに送信される。ユーザーが`can?(:receive_notifications)`を満たす場合のみ送信が実行される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLab設定に基づく |
| 送信元名称 | GitLab |
| 件名 | "One-time password authenticator registered" |
| 形式 | テキスト |

### 本文テンプレート

```
Hi {username}!

A one-time password (OTP) authenticator was registered to your account.

{manage_two_factor_authentication_text}
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @user | 通知対象ユーザー | User | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | 2FA OTP有効化 | ユーザーが通知可能 | OTP認証器の登録成功時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ユーザーが通知不可 | user.can?(:receive_notifications)がfalseの場合 |
| ユーザーがnil | userが存在しない場合（メーラー内チェック） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[2FA設定画面] --> B[OTPコード入力・検証]
    B -->|成功| C[notify_on_success:otp]
    C --> D[NotificationService.enabled_two_factor]
    D --> E{通知可能?}
    E -->|No| F[処理スキップ]
    E -->|Yes| G{type判定}
    G -->|:otp| H[Emails::Profile.enabled_two_factor_otp_email]
    H --> I{ユーザー存在?}
    I -->|No| F
    I -->|Yes| J[email_with_layout]
    J --> K[deliver_later]
    K --> L[終了]
    F --> L
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| users | ユーザー情報取得 | |

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

#### users

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| name | ユーザー名 | メール本文の挨拶 |
| notification_email | 通知先メールアドレス | |

### 更新テーブル一覧

本通知処理では更新は行わない（2FA有効化処理は別処理）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | メール送信エラー | Sidekiqリトライ |
| ユーザー不存在 | ユーザーがnilの場合 | 処理スキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiq標準（25回） |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | 一時的なエラー全般 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | GitLab設定に依存 |
| 1日あたり上限 | 特になし |

### 配信時間帯

制限なし（イベント発生時に即座に送信）

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

- セキュリティ設定変更の通知として重要度が高い
- 通知により、不正な2FA有効化の検知が可能
- 2FA管理画面への案内を含める

## 備考

- NotificationService.enabled_two_factorでtype引数により分岐
- :otp, :webauthn, :passkeyの3種類の2FA有効化通知が存在
- manage_two_factor_authentication_textヘルパーで管理画面リンクを生成

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | otp_required_for_login、2FA関連メソッドを確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | two_factor_auths_controller.rb | `app/controllers/profiles/two_factor_auths_controller.rb` | createメソッドでの通知呼び出し |

**主要処理フロー**:
1. **24-52行目**: createメソッドでOTP検証
2. **29行目**: 検証成功時にnotify_on_success(:otp)呼び出し
3. **303-305行目**: notify_on_successメソッドでNotificationService呼び出し

#### Step 3: NotificationServiceを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | notification_service.rb | `app/services/notification_service.rb` | enabled_two_factorメソッド（49-60行目） |

**主要処理フロー**:
- **50行目**: user.can?(:receive_notifications)チェック
- **52-58行目**: typeによる分岐（:passkey, :webauthn, その他）
- **58行目**: :otp以外の場合はenabled_two_factor_otp_email

#### Step 4: メーラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | profile.rb | `app/mailers/emails/profile.rb` | enabled_two_factor_otp_emailメソッド（233-242行目） |

**主要処理フロー**:
- **234行目**: ユーザー存在チェック
- **236行目**: @userを設定
- **240行目**: 件名「One-time password authenticator registered」

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | enabled_two_factor_otp_email.text.erb | `app/views/notify/enabled_two_factor_otp_email.text.erb` | メール本文 |

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

```
Profiles::TwoFactorAuthsController#create
    │
    ├─ Users::ValidateManualOtpService.execute
    │      └─ OTP検証
    │
    ├─ notify_on_success(:otp)
    │      └─ NotificationService#enabled_two_factor(user, :otp)
    │             │
    │             ├─ user.can?(:receive_notifications) チェック
    │             │
    │             └─ mailer.enabled_two_factor_otp_email(user)
    │                    │
    │                    ├─ return unless user
    │                    │
    │                    └─ email_with_layout
    │                           └─ enabled_two_factor_otp_email.text.erb
    │
    └─ Users::UpdateService (otp_required_for_login: true)
```

### データフロー図

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

OTPコード入力          ──▶ TwoFactorAuthsController  ──▶ 2FA有効化
  (pin_code)               ├─ OTP検証                     │
                           ├─ notify_on_success           │
                           │      └─ NotificationService  ▼
                           │             └─ Emails::Profile ──▶ メール送信
                           │                  └─ テンプレート    (deliver_later)
                           │
                           └─ otp_required_for_login更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| two_factor_auths_controller.rb | `app/controllers/profiles/two_factor_auths_controller.rb` | ソース | 2FA設定コントローラー |
| notification_service.rb | `app/services/notification_service.rb` | ソース | 通知サービス |
| profile.rb | `app/mailers/emails/profile.rb` | ソース | メーラー |
| enabled_two_factor_otp_email.text.erb | `app/views/notify/enabled_two_factor_otp_email.text.erb` | テンプレート | メール本文 |
| notify_preview.rb | `app/mailers/previews/notify_preview.rb` | ソース | メールプレビュー |
