# 通知設計書 41-pipeline_fixed_email

## 概要

本ドキュメントは、GitLabにおけるパイプライン修正通知（pipeline_fixed_email）の設計仕様を定義するものである。

### 本通知の処理概要

パイプラインが以前の失敗状態から修正され、正常に成功した際にユーザーに通知を送信する機能である。

**業務上の目的・背景**：CI/CDパイプラインは継続的インテグレーションの要であり、パイプラインの失敗はプロジェクトの進行に影響を与える。パイプラインが修正されて成功状態に戻ったことを関係者に通知することで、開発チームは問題が解決されたことを即座に把握でき、次のアクションに移ることができる。また、修正の完了を確認するための手動確認作業を削減し、開発効率を向上させる。

**通知の送信タイミング**：パイプラインが以前失敗していた状態（CI Refが失敗状態）から、新しいパイプライン実行によって成功状態に復帰したタイミングで送信される。具体的には、パイプライン実行完了時にref_statusが「fixed」と判定された場合にトリガーされる。

**通知の受信者**：パイプラインの実行者（pipeline.user）が主な受信者となる。ユーザーの通知設定でカスタムアクション「fixed_pipeline」が有効になっている場合に通知が送信される。

**通知内容の概要**：プロジェクト名、ブランチ名、コミットSHA、コミットメッセージ、コミット作成者、パイプライン実行者、ジョブ数、ステージ数など、パイプラインの詳細情報が含まれる。

**期待されるアクション**：受信者はパイプラインが正常に戻ったことを確認し、必要に応じてマージリクエストの進行や次の開発作業を継続できる。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 中 |
| リトライ | Sidekiqのデフォルトリトライ機能に依存 |

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

1. パイプラインの実行ユーザー（pipeline.user）を取得
2. `notifiable_users`メソッドを使用して、通知設定で`:watch`レベル以上かつカスタムアクション`:fixed_pipeline`が有効なユーザーをフィルタリング
3. 各ユーザーの通知メールアドレスを取得（プロジェクトグループの通知設定を考慮）

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンスのデフォルト送信アドレス |
| 送信元名称 | GitLab |
| 件名 | `{プロジェクト名} | Fixed pipeline for {ブランチ名} | {コミットSHA}` |
| 形式 | HTML/テキスト（マルチパート） |

### 本文テンプレート

```
Pipeline has been fixed and {パイプライン名または#パイプラインID} has passed!

Project: {プロジェクト名} ( {プロジェクトURL} )
Branch: {ブランチ名} ( {コミット一覧URL} )
Merge request: {MRリファレンス} ( {MR URL} ) ※該当する場合
Commit: {コミットSHA} ( {コミットURL} )
Commit Message: {コミットメッセージ（50文字まで）}
Commit Author: {作成者名} ( {作成者URL} )
Committed by: {コミッター名} ( {コミッターURL} ) ※異なる場合

Pipeline {パイプライン名またはID} ( {パイプラインURL} ) triggered by {実行者名} ( {実行者URL} )
successfully completed {ジョブ数} jobs in {ステージ数} stages.
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @project | プロジェクト情報 | pipeline.project | Yes |
| @pipeline | パイプライン情報 | 引数pipeline | Yes |
| @merge_request | マージリクエスト情報 | pipeline.merge_request または pipeline.merge_requests_as_head_pipeline.first | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| パイプライン完了 | パイプラインの実行完了 | ref_statusが'fixed'、プロジェクトのメール無効設定がfalse | パイプラインが失敗状態から成功状態に復帰した場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| プロジェクトのメール無効設定 | project.emails_disabled?がtrueの場合は送信しない |
| ユーザー通知設定 | カスタムアクションfixed_pipelineが無効の場合は送信しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[パイプライン完了] --> B[pipeline_finished呼び出し]
    B --> C{emails_disabled?}
    C -->|Yes| D[送信スキップ]
    C -->|No| E[ref_status判定]
    E --> F{status == fixed?}
    F -->|No| G[他のステータス処理]
    F -->|Yes| H[notifiable_users取得]
    H --> I[pipeline_fixed_email呼び出し]
    I --> J[テンプレート展開]
    J --> K[email_with_layout実行]
    K --> L[deliver_later]
    L --> M[終了]
    D --> M
    G --> M
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| p_ci_pipelines | パイプライン情報取得 | パーティションテーブル |
| projects | プロジェクト情報取得 | |
| users | ユーザー情報取得 | |
| merge_requests | マージリクエスト情報取得 | 該当する場合 |
| ci_refs | Ref状態判定 | |
| notification_settings | 通知設定確認 | |

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

#### p_ci_pipelines

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | パイプラインID | 引数から取得 |
| project_id | プロジェクト参照 | |
| user_id | 実行ユーザー参照 | |
| ref | ブランチ/タグ名 | |
| sha | コミットSHA | |
| name | パイプライン名 | |
| status | ステータス | |

#### projects

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | プロジェクトID | pipeline.project_id |
| name | プロジェクト名 | |
| path | プロジェクトパス | |
| namespace_id | 名前空間参照 | |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | 本通知処理ではDB更新なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | メールサーバー接続エラー | Sidekiqリトライ |
| ArgumentError | recipientがArrayの場合 | 例外発生、処理中断 |
| 宛先不正 | ユーザーのメールアドレスが無効 | ログ記録、スキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト（25回） |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | ネットワークエラー、一時的なサーバーエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | GitLabインスタンス設定による |
| 1日あたり上限 | GitLabインスタンス設定による |

### 配信時間帯

特に制限なし

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

- パイプライン情報にはプロジェクトのプライベート情報が含まれる可能性があるため、受信者のアクセス権限を確認
- メール本文には機密情報（環境変数等）を含まない設計
- ユーザーの通知設定を尊重し、望まない通知は送信しない

## 備考

- パイプラインのステータス判定はCi::Refモデルの状態遷移に基づく
- マージリクエストパイプラインの場合、merge_requestが直接関連付けられる
- それ以外の場合、merge_requests_as_head_pipelineから最初のMRを取得

---

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

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

### 推奨読解順序

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

まず、パイプラインと関連モデルの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pipeline.rb | `app/models/ci/pipeline.rb` | パイプラインの基本属性、belongs_to/has_many関係、statusの定義を確認 |
| 1-2 | ref.rb | `app/models/ci/ref.rb` | Ci::Refのstatus管理、failing_state?メソッドの理解 |

**読解のコツ**: Railsのモデル定義では、belongs_to、has_manyなどの関連定義を最初に確認し、データの関係性を把握する。

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

処理の起点となるNotificationServiceを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notification_service.rb | `app/services/notification_service.rb` | pipeline_finishedメソッド（562-584行目）がエントリーポイント |

**主要処理フロー**:
1. **562-566行目**: emails_disabled?チェック
2. **568行目**: pipeline_notification_status呼び出しでステータス判定
3. **569行目**: email_template_name呼び出しで「pipeline_fixed_email」を生成
4. **573-579行目**: notifiable_usersで受信者を決定
5. **581-583行目**: 各受信者に対してmailer.pipeline_fixed_email呼び出し

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

メール生成処理の詳細を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pipelines.rb | `app/mailers/emails/pipelines.rb` | pipeline_fixed_email（13-15行目）、pipeline_mail（19-36行目）の実装 |
| 3-2 | notify.rb | `app/mailers/notify.rb` | 基底クラス、email_with_layoutメソッド、ヘッダー追加処理 |

**主要処理フロー**:
- **13-15行目**: pipeline_fixed_emailがpipeline_mailを'Fixed'ステータスで呼び出し
- **22-29行目**: @project、@pipeline、@merge_requestの設定
- **31行目**: add_headersでHTTPヘッダー追加
- **33-35行目**: email_with_layoutでメール生成

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

メール本文の生成を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pipeline_fixed_email.html.haml | `app/views/notify/pipeline_fixed_email.html.haml` | HTML版テンプレート、_successful_pipelineパーシャルの呼び出し |
| 4-2 | pipeline_fixed_email.text.erb | `app/views/notify/pipeline_fixed_email.text.erb` | テキスト版テンプレート |
| 4-3 | _successful_pipeline.html.haml | `app/views/notify/_successful_pipeline.html.haml` | 共通のパイプライン成功表示パーシャル |
| 4-4 | _successful_pipeline.text.erb | `app/views/notify/_successful_pipeline.text.erb` | テキスト版共通パーシャル |

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

```
NotificationService#pipeline_finished
    │
    ├─ pipeline_notification_status (950-958行目)
    │      └─ Ci::Ref.failing_state? で状態判定
    │
    ├─ email_template_name (558-560行目)
    │      └─ "pipeline_fixed_email" 文字列生成
    │
    ├─ notifiable_users (1037-1038行目)
    │      └─ NotificationRecipients::BuildService
    │
    └─ Notify#pipeline_fixed_email
           └─ Emails::Pipelines#pipeline_fixed_email (13-15行目)
                  └─ pipeline_mail (19-36行目)
                         ├─ add_headers (38-41行目)
                         └─ email_with_layout
```

### データフロー図

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

Pipeline完了イベント ───▶ NotificationService            ───▶ メール送信キュー
                         │                                    (Sidekiq)
                         ├─ ステータス判定
                         │   └─ ref_status: 'fixed'
                         │
                         ├─ 受信者決定
                         │   └─ notifiable_users
                         │
                         └─ Notify#pipeline_fixed_email
                              │
                              ├─ @project (プロジェクト情報)
                              ├─ @pipeline (パイプライン情報)
                              └─ @merge_request (MR情報)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notification_service.rb | `app/services/notification_service.rb` | ソース | 通知処理のオーケストレーション |
| pipelines.rb | `app/mailers/emails/pipelines.rb` | ソース | パイプライン関連メール定義 |
| notify.rb | `app/mailers/notify.rb` | ソース | メーラー基底クラス |
| pipeline.rb | `app/models/ci/pipeline.rb` | ソース | パイプラインモデル |
| pipeline_fixed_email.html.haml | `app/views/notify/pipeline_fixed_email.html.haml` | テンプレート | HTML版メールテンプレート |
| pipeline_fixed_email.text.erb | `app/views/notify/pipeline_fixed_email.text.erb` | テンプレート | テキスト版メールテンプレート |
| _successful_pipeline.html.haml | `app/views/notify/_successful_pipeline.html.haml` | テンプレート | 成功パイプライン共通HTML |
| _successful_pipeline.text.erb | `app/views/notify/_successful_pipeline.text.erb` | テンプレート | 成功パイプライン共通テキスト |
