# 機能設計書 82-メール管理

## 概要

本ドキュメントは、GitLabにおけるユーザーメールアドレス管理機能の設計を記述する。ユーザーは複数のメールアドレスを登録でき、プライマリメール以外のセカンダリメールを追加・削除・確認できる。

### 本機能の処理概要

**業務上の目的・背景**：ユーザーは仕事用、個人用など複数のメールアドレスを使い分けることが一般的である。GitLabでは複数のメールアドレスをアカウントに紐付けることで、異なるメールアドレスからのコミットを正しくユーザーに関連付けたり、通知先を柔軟に設定できるようにする。また、GPG署名の検証にもメールアドレスが使用されるため、適切なメール管理は開発ワークフローにおいて重要である。

**機能の利用シーン**：
- 新しい仕事用メールアドレスをGitLabアカウントに追加する場合
- コミット作成時に使用するメールアドレスをGitLabに登録してコミット紐付けを有効化
- 古いメールアドレスを削除してアカウントを整理する場合
- メールアドレス確認メールを再送信する場合
- 通知先メールアドレスを切り替える場合

**主要な処理内容**：
1. メールアドレスの追加（確認メール送信含む）
2. メールアドレスの削除（プライマリメール以外）
3. メールアドレスの確認（トークンによる検証）
4. 確認メールの再送信
5. 未確認メールアドレスの一覧表示

**関連システム・外部連携**：
- メール送信システム（Deviseによる確認メール）
- GPG署名検証システム（確認済みメールとGPG鍵の紐付け）
- 通知設定システム（通知先メールアドレス）

**権限による制御**：
- ユーザーは自身のメールアドレスのみ管理可能
- 管理者はskip_confirmationオプションで確認をスキップ可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | メール確認再送画面 | 主画面 | 確認メールの再送要求処理 |
| 208 | メール管理 | 主画面 | メールアドレスの管理 |

## 機能種別

CRUD操作 / メール送信 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| email | String | Yes | 追加するメールアドレス | 有効なメール形式、一意性 |
| skip_confirmation | Boolean | No | 確認スキップフラグ（管理者のみ） | - |

### 入力データソース

- 画面入力（Profiles::EmailsController経由）
- 確認トークン（メール内リンクからのコールバック）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | メールID |
| email | String | メールアドレス |
| confirmed_at | DateTime | 確認日時（nullの場合は未確認） |
| created_at | DateTime | 作成日時 |

### 出力先

- 画面表示（メール一覧）
- メール送信（確認メール）

## 処理フロー

### 処理シーケンス

```
1. メールアドレス追加リクエスト受信
   └─ Profiles::EmailsController#create
2. バリデーション
   └─ メール形式チェック、一意性チェック
3. メールレコード作成
   └─ Email.create
4. 確認メール送信
   └─ Deviseの確認機能による自動送信
5. 通知送信
   └─ NotificationService.new_email_address_added
6. 結果返却
   └─ 一覧画面へリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[メール追加リクエスト] --> B{バリデーション}
    B -->|失敗| C[エラー表示]
    B -->|成功| D[メールレコード作成]
    D --> E{skip_confirmation?}
    E -->|Yes かつ admin| F[即座に確認済み]
    E -->|No| G[確認メール送信]
    F --> H[通知送信]
    G --> H
    H --> I[一覧画面へリダイレクト]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-01 | プライマリメール削除禁止 | プライマリメールアドレスは削除できない | 削除時 |
| BR-82-02 | メール一意性 | 同一メールアドレスは複数ユーザーに登録不可 | 追加時 |
| BR-82-03 | メール正規化 | メールアドレスは小文字に正規化して保存 | 追加時 |
| BR-82-04 | 確認必須 | 確認されていないメールは一部機能で使用不可 | 常時 |
| BR-82-05 | detumbled_email | Gmail等のドット正規化処理を適用 | 追加時 |

### 計算ロジック

**メール正規化（detumble）**：
- `::Gitlab::Utils::Email.normalize_email(email)`によりドット除去、プラス記号以降除去等の正規化を適用

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 追加 | emails | INSERT | 新規メールレコード作成 |
| 削除 | emails | DELETE | メールレコード削除 |
| 確認 | emails | UPDATE | confirmed_at更新 |
| 削除後処理 | notification_settings | UPDATE | 通知設定のメールリセット |
| 削除後処理 | users | UPDATE | セカンダリメールの更新 |

### テーブル別操作詳細

#### emails

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | 対象ユーザーID | |
| INSERT | email | 入力値（小文字正規化） | |
| INSERT | detumbled_email | 正規化メールアドレス | |
| INSERT | confirmed_at | null（または即時確認時は現在日時） | |
| UPDATE | confirmed_at | 現在日時 | 確認時 |
| DELETE | - | 対象レコード削除 | プライマリメール以外 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 無効なメール形式 | フォームエラー表示 |
| - | 一意性エラー | 既存メールアドレス | エラーメッセージ表示 |
| - | 削除禁止エラー | プライマリメール削除試行 | StandardError発生 |
| - | レートリミット | 短時間での大量追加/再送 | リクエスト拒否 |

### リトライ仕様

確認メール送信失敗時は、ユーザーが手動で再送信をリクエスト可能。

## トランザクション仕様

- メール追加：単一レコードINSERTのため明示的トランザクション不要
- メール削除：削除後の通知設定・ユーザー更新は個別トランザクション

## パフォーマンス要件

- メール追加：2秒以内（メール送信含む）
- メール一覧取得：100ms以内

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

- メール確認必須によるなりすまし防止
- レートリミットによるスパム防止
- メールアドレス変更時の通知

## 備考

- Deviseの:confirmableモジュールを使用
- 非同期メール送信（AsyncDeviseEmail）に対応
- GPG署名検証はメール確認後に有効化

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | email.rb | `app/models/email.rb` | メールモデルの定義、バリデーション |

**読解のコツ**: Deviseの:confirmableモジュールがメール確認機能を提供している。

**主要処理フロー**:
- **12行目**: belongs_to :user - ユーザーとの関連
- **15行目**: バリデーション定義（presence, uniqueness, devise_email）
- **25-27行目**: confirmed/unconfirmedスコープ
- **29行目**: before_save :detumble_email! - 正規化処理
- **32行目**: devise :confirmable - Deviseモジュール適用
- **43-45行目**: email=メソッドでの正規化
- **52-54行目**: GPG署名更新処理

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | emails_controller.rb | `app/controllers/profiles/emails_controller.rb` | コントローラーアクション |

**主要処理フロー**:
- **15-19行目**: index - 一覧表示
- **25-29行目**: create - メール追加
- **32-38行目**: destroy - メール削除
- **41-48行目**: resend_confirmation_instructions - 確認メール再送

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/emails/create_service.rb` | 作成ロジック |
| 3-2 | destroy_service.rb | `app/services/emails/destroy_service.rb` | 削除ロジック |
| 3-3 | confirm_service.rb | `app/services/emails/confirm_service.rb` | 確認メール再送 |

**主要処理フロー（CreateService）**:
- **5-12行目**: execute - メール作成、確認スキップ、通知送信

**主要処理フロー（DestroyService）**:
- **6行目**: プライマリメール削除チェック
- **10-11行目**: 通知設定リセット、セカンダリメール更新

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

```
Profiles::EmailsController#create
    │
    ├─ Emails::CreateService#execute
    │      ├─ Email.create
    │      ├─ email.confirm (skip_confirmation時)
    │      └─ NotificationService#new_email_address_added
    │
Profiles::EmailsController#destroy
    │
    ├─ Emails::DestroyService#execute
    │      ├─ プライマリメールチェック
    │      ├─ email.destroy
    │      ├─ NotificationSetting.reset_email_for_user!
    │      └─ Users::UpdateService (セカンダリメール更新)
    │
Profiles::EmailsController#resend_confirmation_instructions
    │
    └─ Emails::ConfirmService#execute
           └─ email.resend_confirmation_instructions
```

### データフロー図

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

ユーザー入力         CreateService                    DB保存
(email)         ──▶ ├─バリデーション            ──▶  emails
                     ├─正規化(detumble)
                     └─レコード作成
                                                      ▼
                                                   確認メール送信
                                                   (Devise)
                                                      ▼
                                                   通知送信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| email.rb | `app/models/email.rb` | モデル | メールデータモデル |
| emails_controller.rb | `app/controllers/profiles/emails_controller.rb` | コントローラー | Web UI用コントローラー |
| create_service.rb | `app/services/emails/create_service.rb` | サービス | 作成ロジック |
| destroy_service.rb | `app/services/emails/destroy_service.rb` | サービス | 削除ロジック |
| confirm_service.rb | `app/services/emails/confirm_service.rb` | サービス | 確認メール再送 |
| base_service.rb | `app/services/emails/base_service.rb` | サービス | 基底クラス |
