# 画面設計書 71-パイプラインスケジュール一覧

## 概要

本ドキュメントは、GitLabのCI/CDパイプラインスケジュール一覧画面の設計を記述したものである。

### 本画面の処理概要

**業務上の目的・背景**：パイプラインスケジュール一覧画面は、プロジェクトに設定されているCI/CDパイプラインの定期実行スケジュールを一元管理するための画面である。開発チームが継続的インテグレーション・継続的デリバリーを自動化する際、特定の時間帯や頻度でパイプラインを自動実行したい場合にスケジュールを設定・管理する。これにより、毎晩のビルドやテスト、週次のセキュリティスキャンなど、定期的なCI/CD処理を効率的に運用できる。

**画面へのアクセス方法**：プロジェクト画面の左サイドメニューから「Build」>「Pipeline schedules」を選択、またはURL直接アクセス（`/:namespace/:project/-/pipeline_schedules`）によりアクセスする。

**主要な操作・処理内容**：
1. スケジュール一覧の表示（全て/アクティブ/非アクティブのタブ切り替え）
2. 新規スケジュール作成画面への遷移
3. 既存スケジュールの即時実行（Play）
4. スケジュールの所有権取得
5. スケジュールの編集・削除
6. ページネーションによる一覧のナビゲーション
7. スケジュールのソート機能

**画面遷移**：
- 遷移元：プロジェクトダッシュボード、CI/CDメニュー
- 遷移先：パイプラインスケジュール新規作成画面、パイプラインスケジュール編集画面、パイプライン一覧画面

**権限による表示制御**：
- `read_pipeline_schedule`権限がない場合はアクセス不可
- `create_pipeline_schedule`権限がある場合のみ「New schedule」ボタンが有効
- `update_pipeline_schedule`権限がある場合のみ編集リンクが表示
- `admin_pipeline_schedule`権限がある場合のみ削除・所有権取得が可能
- `play_pipeline_schedule`権限がある場合のみ即時実行ボタンが有効

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | パイプラインスケジュール | 主機能 | スケジュール一覧表示、即時実行、削除、所有権取得 |
| 47 | パイプライン実行 | 遷移先機能 | スケジュール実行後のパイプライン確認 |

## 画面種別

一覧

## URL/ルーティング

| パス | HTTPメソッド | アクション |
|------|-------------|-----------|
| `/:namespace/:project/-/pipeline_schedules` | GET | index |
| `/:namespace/:project/-/pipeline_schedules/:id/play` | POST | play |
| `/:namespace/:project/-/pipeline_schedules/:id/take_ownership` | POST | take_ownership |
| `/:namespace/:project/-/pipeline_schedules/:id` | DELETE | destroy |

## 入出力項目

### URL パラメータ

| 項目名 | 必須 | 型 | 説明 |
|--------|------|-----|------|
| scope | 任意 | string | 表示するスケジュールのスコープ（ALL/ACTIVE/INACTIVE） |
| page | 任意 | integer | 現在のページ番号 |
| prev | 任意 | string | 前ページカーソル |
| next | 任意 | string | 次ページカーソル |
| sort | 任意 | string | ソート順（ID_ASC, ID_DESC, DESCRIPTION_ASC等） |

## 表示項目

### スケジュール一覧テーブル

| 項目名 | 説明 | 型 |
|--------|------|-----|
| 説明 | スケジュールの説明文 | string |
| ターゲット | 対象ブランチまたはタグ | string |
| 次回実行予定 | 次にパイプラインが実行される日時 | datetime |
| 最後のパイプライン | 最後に実行されたパイプラインのステータスバッジ | string |
| オーナー | スケジュールの所有者アバターと名前 | User |
| アクション | 編集、即時実行、所有権取得、削除のボタン群 | - |

### タブカウント

| 項目名 | 説明 |
|--------|------|
| All | 全スケジュール数 |
| Active | アクティブなスケジュール数 |
| Inactive | 非アクティブなスケジュール数 |

## イベント仕様

### 1-タブ切り替え

**処理内容**：All/Active/Inactiveタブをクリックすると、対応するスコープのスケジュール一覧をGraphQL APIで再取得する。

**処理フロー**：
1. タブクリックイベント発火
2. `fetchPipelineSchedulesByStatus(scope)`メソッド呼び出し
3. GraphQL `getPipelineSchedulesQuery`でデータ取得
4. URLパラメータ更新（scope, page等）
5. テーブル再描画

### 2-即時実行（Play）

**処理内容**：スケジュールを即座に実行し、パイプラインを作成する。

**処理フロー**：
1. Playボタンクリック
2. `playPipelineScheduleMutation` GraphQL mutationを実行
3. 成功時：「Successfully scheduled a pipeline to run」メッセージ表示
4. 失敗時：エラーアラート表示
5. レート制限：1分以内の連続実行は制限される

### 3-所有権取得

**処理内容**：スケジュールの所有権を現在のユーザーに移譲する。

**処理フロー**：
1. 「Take ownership」ボタンクリック
2. 確認モーダル表示
3. 確認後、`takeOwnershipMutation` GraphQL mutationを実行
4. 成功時：「Successfully taken ownership from {owner}」メッセージ表示
5. 一覧を再取得して反映

### 4-削除

**処理内容**：スケジュールを削除する。

**処理フロー**：
1. 削除ボタンクリック
2. 確認モーダル表示
3. 確認後、`deletePipelineScheduleMutation` GraphQL mutationを実行
4. 成功時：「Pipeline schedule successfully deleted」メッセージ表示
5. 一覧を再取得して反映

### 5-ページネーション

**処理内容**：前後のページに移動する。

**処理フロー**：
1. 前/次ボタンクリック
2. カーソル情報を更新
3. GraphQL APIで対応ページのデータを取得
4. URLパラメータ更新
5. ページトップにスクロール

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 一覧表示 | ci_pipeline_schedules | SELECT | スケジュール一覧の取得 |
| 即時実行 | ci_pipelines | INSERT | 新規パイプラインの作成 |
| 即時実行 | ci_pipeline_schedule_variables | SELECT | 変数の取得 |
| 所有権取得 | ci_pipeline_schedules | UPDATE | owner_idの更新 |
| 削除 | ci_pipeline_schedules | DELETE | スケジュールの削除 |

### テーブル別更新項目詳細

#### ci_pipeline_schedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | project_idでフィルタ、scopeでactive状態フィルタ | ページネーション対応 |
| UPDATE | owner_id | 現在のユーザーID | 所有権取得時 |
| DELETE | - | idで特定 | 論理削除ではなく物理削除 |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| 成功 | Pipeline schedule successfully deleted. | 削除成功時 |
| 成功 | Successfully scheduled a pipeline to run. Go to the Pipelines page for details. | 即時実行成功時 |
| 成功 | Successfully taken ownership from {owner}. | 所有権取得成功時 |
| エラー | There was a problem fetching pipeline schedules. | 一覧取得失敗時 |
| エラー | There was a problem deleting the pipeline schedule. | 削除失敗時 |
| エラー | There was a problem playing the pipeline schedule. | 即時実行失敗時 |
| エラー | There was a problem taking ownership of the pipeline schedule. | 所有権取得失敗時 |
| 警告 | You have exceeded the maximum number of pipeline schedules for your plan. | プラン制限到達時 |
| エラー | You cannot play this scheduled pipeline at the moment. Please wait a minute. | レート制限時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| 権限不足 | 403 Forbiddenを返し、アクセス拒否画面にリダイレクト |
| スケジュール未検出 | 404 Not Foundを返す |
| レート制限超過 | フラッシュメッセージ表示後、一覧画面にリダイレクト |
| GraphQL エラー | 画面上部にエラーアラートを表示 |

## 備考

- スケジュールの実行は非同期で行われ、Sidekiqワーカー（PipelineScheduleWorker）により定期的に処理される
- スケジュール数の上限はプランの制限（ci_pipeline_schedules）に従う
- WebSocket/GraphQL Subscriptionによりスケジュールのステータス更新がリアルタイムで反映される

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pipeline_schedule.rb | `app/models/ci/pipeline_schedule.rb` | スケジュールの属性、バリデーション、関連モデル（owner, variables, pipelines）を確認 |
| 1-2 | pipeline_schedule_variable.rb | `app/models/ci/pipeline_schedule_variable.rb` | スケジュール変数の構造を確認 |

**読解のコツ**: `belongs_to :owner`, `has_many :pipelines`, `has_many :variables`の関連定義と、cronバリデーション、`daily_limit`メソッドに注目する。

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

処理の起点となるコントローラーとビューを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pipeline_schedules_controller.rb | `app/controllers/projects/pipeline_schedules_controller.rb` | indexアクション、before_actionによる認可処理を確認 |
| 2-2 | index.html.haml | `app/views/projects/pipeline_schedules/index.html.haml` | Vueアプリケーションのマウントポイントとデータ属性 |

**主要処理フロー**:
1. **18-22行目**: indexアクションでPipelineSchedulesFinderを使用してスケジュールを取得
2. **4行目**: Vue.jsコンポーネントにproject_path, pipelines_path等のデータを渡す

#### Step 3: フロントエンドコンポーネントを理解する

Vue.jsによるフロントエンドの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pipeline_schedules.vue | `app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue` | メインコンポーネント、Apollo Client設定、タブ切り替え、ページネーション |
| 3-2 | pipeline_schedules_table.vue | `app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue` | テーブルレンダリング、ソート機能 |
| 3-3 | get_pipeline_schedules.query.graphql | `app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql` | GraphQLクエリの構造 |

**主要処理フロー**:
- **96-185行目**: Apollo GraphQLクエリの設定と結果の処理
- **296-452行目**: 削除、所有権取得、即時実行の各メソッド

#### Step 4: GraphQL APIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pipeline_schedule_type.rb | `app/graphql/types/ci/pipeline_schedule_type.rb` | GraphQLでの型定義 |
| 4-2 | pipeline_schedules_resolver.rb | `app/graphql/resolvers/ci/pipeline_schedules_resolver.rb` | スケジュール取得のリゾルバー |

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

```
[ブラウザ] GET /project/-/pipeline_schedules
    │
    ├─ PipelineSchedulesController#index
    │      └─ Ci::PipelineSchedulesFinder#execute
    │             └─ PipelineSchedule.where(project_id: ...)
    │
    └─ [Vue.js] pipeline_schedules.vue
           │
           ├─ Apollo Client (GraphQL)
           │      └─ getPipelineSchedulesQuery
           │             └─ PipelineSchedulesResolver#resolve
           │
           ├─ playPipelineScheduleMutation
           │      └─ Ci::PipelineSchedules::PlayService#execute
           │
           ├─ takeOwnershipMutation
           │      └─ Ci::PipelineSchedules::TakeOwnershipService#execute
           │
           └─ deletePipelineScheduleMutation
                  └─ PipelineSchedule#destroy
```

### データフロー図

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

URLパラメータ ─────────────▶ PipelineSchedulesController#index ───▶ HTML + Vueマウント
  (scope, page)                     │
                                    └─ Finder
                                          │
GraphQL Query ────────────────────────────┴──────────────────────▶ JSON (schedules)
  (projectPath, status,                                              │
   first, last, cursor)                                              ▼
                                                               Vueコンポーネント描画
GraphQL Mutation ─────────▶ Mutation Resolver ─────────────────▶ 成功/失敗レスポンス
  (play/delete/takeOwnership)     │
                                  └─ Service Class
                                        └─ Model更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pipeline_schedules_controller.rb | `app/controllers/projects/pipeline_schedules_controller.rb` | コントローラー | HTTPリクエスト処理 |
| index.html.haml | `app/views/projects/pipeline_schedules/index.html.haml` | ビュー | Vueアプリマウントポイント |
| pipeline_schedule.rb | `app/models/ci/pipeline_schedule.rb` | モデル | データモデル定義 |
| pipeline_schedules.vue | `app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue` | Vueコンポーネント | メインUIコンポーネント |
| pipeline_schedules_table.vue | `app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue` | Vueコンポーネント | テーブル表示 |
| pipeline_schedules_helper.rb | `app/helpers/ci/pipeline_schedules_helper.rb` | ヘルパー | ビューヘルパー関数 |
| pipeline_schedules_finder.rb | `app/finders/ci/pipeline_schedules_finder.rb` | ファインダー | スケジュール検索ロジック |
| pipelines.rb | `config/routes/pipelines.rb` | ルーティング | URLルート定義 |
