# 通知設計書 53-access_token_revoked_email

## 概要

本ドキュメントは、GitLabにおける個人アクセストークン取り消し通知（access_token_revoked_email）の設計内容を記載する。

### 本通知の処理概要

**業務上の目的・背景**：個人アクセストークン（PAT）が取り消された際、ユーザーに通知を送ることで、意図しない取り消しや不正アクセスの検知を可能にする。特に、シークレット検出機能により自動的にトークンが取り消された場合、ユーザーが迅速に状況を把握し、必要な対応を取ることができる。

**通知の送信タイミング**：トークンが取り消された時点で即座に通知が送信される。取り消しの発生源は手動操作または自動検出（secret_detection）の場合がある。

**通知の受信者**：取り消されたトークンを所有するアクティブなユーザー本人。

**通知内容の概要**：取り消されたトークンの名前、取り消しの理由（シークレット検出の場合は追加説明）、個人アクセストークン設定画面へのリンクが含まれる。

**期待されるアクション**：受信者は通知を受け取った後、取り消しが意図したものか確認し、必要に応じて新しいトークンを作成する。シークレット検出による自動取り消しの場合は、漏洩したトークンを使用していたシステムの認証情報を更新する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 高（セキュリティ通知） |
| リトライ | Sidekiq標準リトライ機構に依存 |

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

トークンを所有するユーザーの`notification_email_or_default`メソッドで取得されるメールアドレスに送信される。ユーザーが`can?(:receive_notifications)`を満たし、かつ`active?`である場合のみ送信が実行される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLab設定に基づく |
| 送信元名称 | GitLab |
| 件名 | "Your personal access token has been revoked" |
| 形式 | テキスト |

### 本文テンプレート

```
Hi {username}!

A personal access token, named {token_name}, has been revoked.

（シークレット検出による取り消しの場合）
We found your token in a public project and have automatically revoked it to protect your account.

You can check your tokens or create a new one in your personal access tokens settings {pat_link}.
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @user | 通知対象ユーザー | User | Yes |
| @token_name | 取り消されたトークン名 | PersonalAccessToken.name | Yes |
| @source | 取り消し発生源 | パラメータ | No |
| @target_url | 個人アクセストークン設定URL | user_settings_personal_access_tokens_url | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API/画面操作 | トークン取り消し | トークン所有者がアクティブ | 手動または自動でトークンが取り消された時 |
| 自動処理 | シークレット検出 | 公開プロジェクトでトークンを検出 | source = :secret_detection |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ユーザーが通知不可 | user.can?(:receive_notifications)がfalseの場合 |
| ユーザーが非アクティブ | user.active?がfalseの場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[トークン取り消しイベント] --> B[NotificationService.access_token_revoked]
    B --> C{通知可能?}
    C -->|No| D[送信スキップ]
    C -->|Yes| E[Emails::Profile.access_token_revoked_email]
    E --> F{ユーザーアクティブ?}
    F -->|No| D
    F -->|Yes| G[email_with_layout]
    G --> H[deliver_later]
    H --> I[終了]
    D --> I
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| users | ユーザー情報取得 | |
| personal_access_tokens | トークン情報取得 | 取り消し時点で名前を取得 |

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

#### users

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

### 更新テーブル一覧

本通知処理では更新は行わない（トークン取り消し処理は別処理）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | メール送信エラー | Sidekiqリトライ |
| ユーザー非アクティブ | ユーザーが削除・無効化済み | 処理スキップ |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- トークン名のみを通知に含め、トークン値自体は含まれない
- シークレット検出による自動取り消しの場合は、漏洩の事実を明確に通知
- セキュリティ通知のため、通知設定にかかわらず重要な情報として扱う

## 備考

- シークレット検出機能と連携して自動取り消しが行われる場合がある
- source引数により取り消し理由を区別可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | personal_access_token.rb | `app/models/personal_access_token.rb` | トークンの取り消し関連メソッド |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notification_service.rb | `app/services/notification_service.rb` | access_token_revokedメソッド（142-146行目） |

**主要処理フロー**:
- **142行目**: user.can?(:receive_notifications)チェック
- **145行目**: mailer.access_token_revoked_email呼び出し

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

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

**主要処理フロー**:
- **139行目**: user.active?チェック
- **144行目**: @sourceに取り消し発生源を設定
- **148行目**: 件名「Your personal access token has been revoked」

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | access_token_revoked_email.text.erb | `app/views/notify/access_token_revoked_email.text.erb` | @sourceによる条件分岐 |

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

```
トークン取り消し処理
    │
    └─ NotificationService#access_token_revoked(user, token_name, source)
           │
           ├─ user.can?(:receive_notifications) チェック
           │
           └─ Notify#access_token_revoked_email(user, token_name, source)
                  │
                  ├─ user.active? チェック
                  │
                  └─ email_with_layout
                         └─ access_token_revoked_email.text.erb
```

### データフロー図

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

トークン取り消し要求   ──▶ PersonalAccessTokenService ──▶ トークン無効化
  (user, token_name,       ├─ トークン取り消し処理           │
   source)                 └─ NotificationService       ──▶ メール送信
                               └─ Emails::Profile           (deliver_later)
                                   └─ テンプレート展開
```

### 関連ファイル一覧

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