# 通知設計書 42-pipeline_schedule_owner_unavailable_email

## 概要

本ドキュメントは、GitLabにおけるパイプラインスケジュールオーナー利用不可通知（pipeline_schedule_owner_unavailable_email）の設計仕様を定義するものである。

### 本通知の処理概要

パイプラインスケジュールのオーナーがプロジェクトへのアクセス権限を失った場合に、プロジェクトのOwnerおよびMaintainerに通知を送信し、スケジュールの再有効化を促す機能である。

**業務上の目的・背景**：CI/CDパイプラインスケジュールは特定のユーザー（オーナー）の権限で実行される。オーナーがプロジェクトから離脱したり、権限を失った場合、スケジュールは自動的に非アクティブ化される。この状態を関係者に通知し、適切な対応（新しいオーナーの設定とスケジュールの再有効化）を促すことで、重要なCI/CDプロセスの中断を最小限に抑える。

**通知の送信タイミング**：パイプラインスケジュールのオーナーがプロジェクトへの適切なアクセス権限を失ったことが検知されたタイミングで送信される。具体的には、スケジュール実行時または定期的なチェック処理でオーナーの権限が確認できない場合にトリガーされる。

**通知の受信者**：プロジェクトのOwnerおよびMaintainerロールを持つ全メンバー。これらのユーザーはスケジュールの所有権を引き継ぐ権限を持つ。

**通知内容の概要**：スケジュールの説明（名前）、スケジュールへのリンク、オーナーシップ取得方法へのドキュメントリンクが含まれる。

**期待されるアクション**：受信者はスケジュールの所有権を取得し、必要に応じてスケジュールを再アクティブ化する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 高（CI/CD運用に影響） |
| リトライ | Sidekiqのデフォルトリトライ機能に依存 |

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

1. スケジュールが関連するプロジェクトを取得
2. `project.owners_and_maintainers`メソッドでOwnerおよびMaintainerロールを持つメンバーを取得
3. 各メンバーに対して通知メールを送信

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンスのデフォルト送信アドレス |
| 送信元名称 | GitLab |
| 件名 | `Take ownership of the pipeline schedule: {スケジュール説明}` |
| 形式 | HTML/テキスト（マルチパート） |

### 本文テンプレート

```
The owner of the pipeline schedule "{スケジュール説明}" no longer has permission.

The schedule is deactivated and cannot run. Take ownership and reactivate the schedule to resume pipeline runs.

View pipeline schedule: {スケジュールURL}

Learn how to take ownership: {ヘルプドキュメントURL}
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @schedule | パイプラインスケジュール情報 | 引数schedule | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| スケジュール検証 | オーナー権限チェック | オーナーがプロジェクトアクセス権限を失った場合 | スケジュール実行前の権限検証で検知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | 特別な抑止条件はなし |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[スケジュール実行トリガー] --> B[オーナー権限チェック]
    B --> C{オーナーに権限あり?}
    C -->|Yes| D[スケジュール実行]
    C -->|No| E[スケジュール非アクティブ化]
    E --> F[owners_and_maintainers取得]
    F --> G[各受信者にメール送信]
    G --> H[pipeline_schedule_owner_unavailable_email呼び出し]
    H --> I[email_with_layout実行]
    I --> J[deliver_later]
    J --> K[終了]
    D --> K
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| ci_pipeline_schedules | スケジュール情報取得 | |
| projects | プロジェクト情報取得 | |
| members | OwnerおよびMaintainer取得 | |
| users | ユーザー情報取得 | |

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

#### ci_pipeline_schedules

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | スケジュールID | 引数から取得 |
| description | スケジュール説明（名前） | |
| project_id | プロジェクト参照 | |
| owner_id | オーナーユーザー参照 | |
| active | アクティブ状態 | |

#### members

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| user_id | ユーザーID | source_type='Project', access_level >= MAINTAINER |
| access_level | アクセスレベル | |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| ci_pipeline_schedules | UPDATE | activeをfalseに更新（別処理） |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

特に制限なし

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

- スケジュール情報にはプロジェクトのプライベート情報が含まれる可能性があるため、受信者はOwner/Maintainerに限定
- ヘルプドキュメントリンクは公開情報へのリンクのみ

## 備考

- スケジュールのオーナーシップ取得は別途UIまたはAPIで実行される
- 通知送信後、スケジュールは非アクティブ状態のままであり、手動での再有効化が必要

---

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

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

### 推奨読解順序

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

まず、パイプラインスケジュールモデルの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pipeline_schedule.rb | `app/models/ci/pipeline_schedule.rb` | スケジュールの基本属性、owner関連、active状態管理を確認 |

**読解のコツ**: `belongs_to :owner`と`belongs_to :project`の関連に注目し、オーナーとプロジェクトの関係を理解する。

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

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

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

**主要処理フロー**:
1. **586行目**: メソッド定義、scheduleを引数として受け取る
2. **587行目**: `schedule.project.owners_and_maintainers`で受信者を取得
3. **588行目**: 各受信者に対してメール送信をループ

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pipeline_schedules.rb | `app/mailers/emails/pipeline_schedules.rb` | pipeline_schedule_owner_unavailable_emailメソッドの実装 |

**主要処理フロー**:
- **5-13行目**: メソッド実装
- **6行目**: recipientがArrayでないことを確認
- **8行目**: @schedule変数の設定
- **10-12行目**: email_with_layoutでメール生成、件名設定

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pipeline_schedule_owner_unavailable_email.html.haml | `app/views/notify/pipeline_schedule_owner_unavailable_email.html.haml` | HTML版テンプレート |
| 4-2 | pipeline_schedule_owner_unavailable_email.text.erb | `app/views/notify/pipeline_schedule_owner_unavailable_email.text.erb` | テキスト版テンプレート |

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

```
NotificationService#pipeline_schedule_owner_unavailable (586-590行目)
    │
    ├─ schedule.project.owners_and_maintainers
    │      └─ OwnerおよびMaintainerメンバー取得
    │
    └─ Notify#pipeline_schedule_owner_unavailable_email
           └─ Emails::PipelineSchedules#pipeline_schedule_owner_unavailable_email (5-13行目)
                  └─ email_with_layout
                         └─ メール生成・送信キュー追加
```

### データフロー図

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

スケジュール検証イベント ───▶ NotificationService            ───▶ メール送信キュー
                              │                                    (Sidekiq)
                              ├─ schedule取得
                              │
                              ├─ 受信者決定
                              │   └─ owners_and_maintainers
                              │
                              └─ pipeline_schedule_owner_unavailable_email
                                   │
                                   └─ @schedule (スケジュール情報)
                                        ├─ description
                                        └─ project (プロジェクト参照)
```

### 関連ファイル一覧

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