# 画面設計書 73-パイプラインスケジュール編集

## 概要

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

### 本画面の処理概要

**業務上の目的・背景**：パイプラインスケジュール編集画面は、既存のCI/CDパイプラインスケジュールの設定を変更するための画面である。スケジュールの実行間隔の変更、対象ブランチの変更、変数の追加・削除、アクティブ状態の切り替えなど、運用中のスケジュールを柔軟に調整できる。継続的インテグレーションの運用要件変更に対応するために必要な機能である。

**画面へのアクセス方法**：パイプラインスケジュール一覧画面の「Edit」ボタンをクリック、またはURL直接アクセス（`/:namespace/:project/-/pipeline_schedules/:id/edit`）によりアクセスする。

**主要な操作・処理内容**：
1. 既存スケジュール情報の表示
2. スケジュールの説明（Description）の編集
3. cron式によるスケジュール間隔の変更
4. タイムゾーンの変更
5. 対象ブランチまたはタグの変更
6. スケジュール変数の追加・編集・削除
7. パイプライン入力値（inputs）の編集
8. アクティブ/非アクティブ状態の切り替え
9. スケジュールの更新保存

**画面遷移**：
- 遷移元：パイプラインスケジュール一覧画面
- 遷移先：パイプラインスケジュール一覧画面（保存成功時）、エラー時は同画面に留まる

**権限による表示制御**：
- `update_pipeline_schedule`権限がない場合はアクセス不可（403エラー）
- `set_pipeline_variables`権限がない場合は変数設定セクションが非表示
- スケジュールの所有者または管理者のみが編集可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | パイプラインスケジュール | 主機能 | スケジュールの編集・更新 |
| 50 | CI変数管理 | 補助機能 | スケジュール変数の編集 |

## 画面種別

編集

## URL/ルーティング

| パス | HTTPメソッド | アクション |
|------|-------------|-----------|
| `/:namespace/:project/-/pipeline_schedules/:id/edit` | GET | edit |
| `/:namespace/:project/-/pipeline_schedules/:id` | PATCH/PUT | update |

## 入出力項目

### URLパラメータ

| 項目名 | 必須 | 型 | 説明 |
|--------|------|-----|------|
| id | 必須 | integer | スケジュールID |

### 入力フォーム

| 項目名 | 必須 | 型 | 説明 | バリデーション |
|--------|------|-----|------|----------------|
| description | 必須 | string | スケジュールの説明 | 必須、最大255文字 |
| cron | 必須 | string | cron形式のスケジュール式 | cron形式バリデーション |
| cron_timezone | 必須 | string | タイムゾーン | 有効なタイムゾーン |
| ref | 必須 | string | 対象ブランチまたはタグ | 必須、存在するref |
| active | 任意 | boolean | アクティブ状態 | - |
| variables_attributes | 任意 | array | スケジュール変数 | ネスト属性、重複キー不可 |
| inputs_attributes | 任意 | array | パイプライン入力値 | 最大50件 |

### 変数（variables_attributes）

| 項目名 | 必須 | 型 | 説明 |
|--------|------|-----|------|
| id | 任意 | integer | 既存変数のID（更新時） |
| variable_type | 必須 | string | 変数タイプ（env_var/file） |
| key | 必須 | string | 変数キー |
| secret_value | 必須 | string | 変数値 |
| _destroy | 任意 | boolean | 削除フラグ |

## 表示項目

### フォームセクション（新規作成と同様）

| セクション | 項目 | 説明 |
|-----------|------|------|
| 基本情報 | Description | スケジュールの説明（既存値がプリセット） |
| スケジュール設定 | Interval Pattern | プリセット選択またはカスタムcron（既存値がプリセット） |
| スケジュール設定 | Cron timezone | タイムゾーン（既存値がプリセット） |
| ターゲット | Target branch or tag | ブランチ/タグ選択（既存値がプリセット） |
| 変数 | Variables | 既存変数の一覧と編集フォーム |
| 入力値 | Inputs | 既存入力値の一覧と編集フォーム |
| 状態 | Activated | アクティブ状態（既存値がプリセット） |

### 追加表示情報

| 項目 | 説明 |
|------|------|
| スケジュールID | ブレッドクラムに`#{id}`として表示 |
| 所有者情報 | 現在の所有者名を表示 |
| 次回実行予定 | cron設定に基づく次回実行日時 |

## イベント仕様

### 1-フォーム送信（更新）

**処理内容**：編集された情報でパイプラインスケジュールを更新する。

**処理フロー**：
1. フォームバリデーション実行
2. GraphQL `updatePipelineScheduleMutation`を実行
3. 成功時：パイプラインスケジュール一覧画面にリダイレクト
4. 失敗時：エラーメッセージを表示し、フォームに留まる

### 2-変数の更新

**処理内容**：既存変数の値を変更、または新規変数を追加する。

**処理フロー**：
1. 既存変数はidを保持して値を更新
2. 新規変数はidなしで追加
3. 削除する変数は`_destroy: true`をセット
4. フォーム送信時に一括処理

### 3-変数の削除

**処理内容**：既存の変数を削除する。

**処理フロー**：
1. 削除ボタンクリック
2. 変数に`_destroy: true`をセット
3. フォーム送信時にサーバー側で削除処理

### 4-キャンセル

**処理内容**：編集をキャンセルして一覧画面に戻る。

**処理フロー**：
1. キャンセルボタンクリック
2. 確認なしでパイプラインスケジュール一覧画面にリダイレクト

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| スケジュール更新 | ci_pipeline_schedules | UPDATE | スケジュール情報の更新 |
| 変数追加 | ci_pipeline_schedule_variables | INSERT | 新規変数の作成 |
| 変数更新 | ci_pipeline_schedule_variables | UPDATE | 既存変数の更新 |
| 変数削除 | ci_pipeline_schedule_variables | DELETE | 変数の削除 |
| 入力値更新 | ci_pipeline_schedule_inputs | INSERT/UPDATE/DELETE | 入力値の操作 |

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

#### ci_pipeline_schedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | description | フォーム入力値 | 変更があった場合のみ |
| UPDATE | cron | フォーム入力値 | 変更時にnext_run_atも再計算 |
| UPDATE | cron_timezone | フォーム入力値 | 変更時にnext_run_atも再計算 |
| UPDATE | ref | フォーム入力値 | 変更があった場合のみ |
| UPDATE | active | フォーム入力値 | 変更があった場合のみ |
| UPDATE | next_run_at | 自動計算 | cron/cron_timezone変更時 |
| UPDATE | updated_at | 現在時刻 | 自動設定 |

#### ci_pipeline_schedule_variables

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | key | フォーム入力値 | idで特定 |
| UPDATE | value | フォーム入力値（暗号化） | idで特定 |
| UPDATE | variable_type | フォーム入力値 | idで特定 |
| DELETE | - | _destroy: trueの場合 | idで特定 |
| INSERT | * | 新規変数 | idなしの場合 |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| 成功 | Schedule updated successfully | 更新成功時（一覧画面にリダイレクト） |
| エラー | The current user is not authorized to update the pipeline schedule | 権限不足時 |
| エラー | Cron is invalid | cron形式が不正な場合 |
| エラー | Cron timezone is invalid | タイムゾーンが不正な場合 |
| エラー | Ref can't be blank | ブランチ/タグ未選択時 |
| エラー | Description can't be blank | 説明未入力時 |
| エラー | Variables have duplicate keys | 変数キーが重複している場合 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| スケジュール未検出 | 404 Not Foundを返す |
| 権限不足 | 403 Forbiddenを返し、アクセス拒否画面にリダイレクト |
| バリデーションエラー | エラーメッセージを表示し、フォームを再表示 |
| 楽観的ロック失敗 | 競合エラーを表示 |

## 備考

- cron/cron_timezoneが変更された場合のみnext_run_atが再計算される
- 変数の値は暗号化されて保存される
- 既存変数の値は編集画面で復号化されて表示される
- 所有権は編集では変更されない（take_ownershipは別機能）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pipeline_schedule.rb | `app/models/ci/pipeline_schedule.rb` | set_next_run_at、allow_next_run_at_update?メソッド |
| 1-2 | pipeline_schedule_variable.rb | `app/models/ci/pipeline_schedule_variable.rb` | 変数の暗号化処理 |

**読解のコツ**: `cron_values_changed?`メソッドがnext_run_at更新のトリガーになることを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pipeline_schedules_controller.rb | `app/controllers/projects/pipeline_schedules_controller.rb` | edit/updateアクション、scheduleメソッド |
| 2-2 | edit.html.haml | `app/views/projects/pipeline_schedules/edit.html.haml` | Vueコンポーネントのマウントとスケジュールデータ |

**主要処理フロー**:
1. **37行目**: editアクションは空のメソッド
2. **39-46行目**: updateアクションでUpdateServiceを呼び出し
3. **93-95行目**: scheduleメソッドでスケジュールを取得

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_service.rb | `app/services/ci/pipeline_schedules/update_service.rb` | 更新処理のビジネスロジック |
| 3-2 | base_save_service.rb | `app/services/ci/pipeline_schedules/base_save_service.rb` | 共通の保存ロジック |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pipeline_schedules_form.vue | `app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue` | editing=trueの場合の処理、既存データの取得 |
| 4-2 | update_pipeline_schedule.mutation.graphql | `app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/update_pipeline_schedule.mutation.graphql` | 更新mutation |

**主要処理フロー**:
- **69-130行目**: Apollo queryでスケジュール情報を取得
- **91-108行目**: 取得したデータをフォームに反映

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

```
[ブラウザ] GET /project/-/pipeline_schedules/:id/edit
    │
    ├─ PipelineSchedulesController#edit
    │      └─ schedule (find by id)
    │
    └─ [Vue.js] pipeline_schedules_form.vue (editing=true)
           │
           └─ Apollo Query: getPipelineSchedulesQuery
                  └─ 既存スケジュール情報を取得

[フォーム送信]
    │
    └─ updatePipelineScheduleMutation (GraphQL)
           │
           └─ Mutations::Ci::PipelineSchedule::Update
                  │
                  └─ Ci::PipelineSchedules::UpdateService#execute
                         │
                         ├─ 権限チェック
                         ├─ バリデーション
                         └─ PipelineSchedule#update
                                │
                                └─ set_next_run_at (if cron changed)
```

### データフロー図

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

URL(schedule_id) ──────────▶ Controller#edit ───────────────────▶ HTML + Vueマウント
                                   │
                                   └─ schedule = find(id)
                                          │
                                          ▼
GraphQL Query ─────────────────────▶ Resolver ──────────────────▶ 既存データJSON
  (ids: schedule_id)                                                   │
                                                                       ▼
                                                              フォームにプリセット

フォーム編集 ─────────────▶ Vue.jsバリデーション ─────────────▶ フォームエラー表示
                                   │
                                   ▼
                           GraphQL Mutation
                                   │
                                   ▼
                           UpdateService#execute
                                   │
                           ┌───────┴───────┐
                           │               │
                           ▼               ▼
                        成功           失敗
                           │               │
                           ▼               ▼
                    一覧へリダイレクト   エラー表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pipeline_schedules_controller.rb | `app/controllers/projects/pipeline_schedules_controller.rb` | コントローラー | edit/updateアクション |
| edit.html.haml | `app/views/projects/pipeline_schedules/edit.html.haml` | ビュー | Vueマウントポイント |
| update_service.rb | `app/services/ci/pipeline_schedules/update_service.rb` | サービス | 更新ビジネスロジック |
| pipeline_schedule.rb | `app/models/ci/pipeline_schedule.rb` | モデル | next_run_at再計算ロジック |
| pipeline_schedules_form.vue | `app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue` | Vueコンポーネント | 編集フォーム |
| pipeline_schedules_helper.rb | `app/helpers/ci/pipeline_schedules_helper.rb` | ヘルパー | フォームデータ生成 |
| update_pipeline_schedule.mutation.graphql | `app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/update_pipeline_schedule.mutation.graphql` | GraphQL | 更新mutation |
