# 画面設計書 131-Runner新規登録

## 概要

本ドキュメントは、GitLabにおけるプロジェクトレベルのRunner新規登録画面の設計を定義するものである。

### 本画面の処理概要

**業務上の目的・背景**：プロジェクト固有のCI/CDジョブを実行するため、プロジェクト専用のRunner（ジョブ実行エージェント）を登録する必要がある。この画面では、プロジェクト管理者がプロジェクトスコープの新しいRunnerを作成し、CI/CDパイプラインで使用するための設定を行うことができる。Runnerはビルド、テスト、デプロイなどのCI/CDジョブを実際に実行するエージェントであり、プロジェクトごとに専用のRunnerを持つことで、セキュリティとリソース管理を向上させることができる。

**画面へのアクセス方法**：プロジェクト画面から「設定」>「CI/CD」>「Runners」セクションに移動し、「New project runner」ボタンをクリックすることでアクセスできる。URLパスは `/:namespace/:project/-/runners/new` となる。

**主要な操作・処理内容**：
1. Runnerの基本情報（説明、タグ、実行条件など）を入力
2. Runnerのアクセスレベル（保護ブランチのみか、すべてのブランチか）を設定
3. タグなしジョブの実行可否を設定
4. 最大タイムアウト時間を設定
5. Runnerを作成し、登録トークンを取得

**画面遷移**：
- 遷移元：CI/CD設定画面（Runnersセクション）
- 遷移先：Runner登録画面（トークン表示）、Runner詳細画面、CI/CD設定画面

**権限による表示制御**：プロジェクトのRunner管理権限（`admin_runners`）を持つユーザーのみがこの画面にアクセスできる。さらにRunnerを作成するには `create_runners` 権限が必要である。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 51 | Runnerレジストレーション | 主機能 | 新規Runnerの登録・設定処理 |

## 画面種別

登録

## URL/ルーティング

| メソッド | パス | コントローラ#アクション |
|---------|------|------------------------|
| GET | `/:namespace_id/:project_id/-/runners/new` | `projects/runners#new` |

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 入出力 | バリデーション | 説明 |
|--------|--------|-----|------|--------|---------------|------|
| プロジェクトID | project_id | String | Yes | 入力 | プロジェクト存在チェック | Runner登録対象のプロジェクト |
| 説明 | description | String | No | 入力 | 最大1024文字 | Runnerの説明文 |
| タグ | tag_list | Array | No | 入力 | 最大50個 | ジョブマッチング用タグ |
| アクセスレベル | access_level | Enum | Yes | 入力 | not_protected/ref_protected | 保護ブランチ制限 |
| タグなし実行 | run_untagged | Boolean | No | 入力 | - | タグなしジョブの実行可否 |
| ロック状態 | locked | Boolean | No | 入力 | - | プロジェクトへのロック |
| 最大タイムアウト | maximum_timeout_human_readable | String | No | 入力 | 10分以上 | ジョブの最大実行時間 |

## 表示項目

この画面はVue.jsコンポーネント（`#js-project-new-runner`）によりレンダリングされる。

| 項目名 | 説明 |
|--------|------|
| パンくずリスト | CI/CD Settings > Create |
| ページタイトル | Create a project runner |
| Runner設定フォーム | Vueコンポーネントでレンダリング |

## イベント仕様

### 1-Runner作成

**トリガー**：Vueコンポーネント内の「Create runner」ボタンクリック

**処理フロー**：
1. フロントエンドでフォームのバリデーション実行
2. GraphQL Mutation `runnerCreate` を呼び出し
3. バックエンドでRunner作成処理を実行
4. 作成成功時、登録トークンを含むRunner登録画面に遷移
5. 作成失敗時、エラーメッセージを表示

**データフロー**：
```
Vue Component -> GraphQL API -> Ci::Runners::CreateRunnerService -> Ci::Runner (create)
```

### 2-キャンセル

**トリガー**：「Cancel」ボタンまたはパンくずリストクリック

**処理フロー**：
1. CI/CD設定画面（Runnersセクション）へリダイレクト

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Runner作成 | ci_runners | INSERT | 新規Runnerレコード作成 |
| Runner作成 | ci_runner_projects | INSERT | RunnerとProject紐付け |

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

#### ci_runners

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動採番 | Primary Key |
| INSERT | token | 自動生成（glrt-プレフィックス） | 暗号化保存 |
| INSERT | description | 入力値 | 説明文 |
| INSERT | runner_type | 3 (project_type) | プロジェクトRunner |
| INSERT | access_level | 入力値 | 0=not_protected, 1=ref_protected |
| INSERT | run_untagged | 入力値 | デフォルトtrue |
| INSERT | locked | 入力値 | デフォルトfalse |
| INSERT | active | true | 有効状態 |
| INSERT | creation_state | 0 (started) | 登録待ち状態 |
| INSERT | registration_type | 1 (authenticated_user) | UIから作成 |
| INSERT | creator_id | current_user.id | 作成者 |
| INSERT | organization_id | project.organization_id | 所属組織 |
| INSERT | created_at | 現在時刻 | 作成日時 |

#### ci_runner_projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | runner_id | 作成されたRunner ID | FK |
| INSERT | project_id | 対象プロジェクトID | FK |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG001 | 成功 | Runner was successfully created. | Runner作成成功時 |
| MSG002 | エラー | Tags list can not be empty when runner is not allowed to pick untagged jobs | タグなし+untagged無効 |
| MSG003 | エラー | Too many tags specified. Please limit the number of tags to 50 | タグ数超過 |
| MSG004 | エラー | Maximum job timeout needs to be at least 10 minutes | タイムアウト10分未満 |

## 例外処理

| 例外条件 | 処理内容 | 遷移先 |
|---------|---------|--------|
| 権限不足 | 403 Forbidden | アクセス拒否画面 |
| プロジェクト未検出 | 404 Not Found | Not Found画面 |
| バリデーションエラー | エラーメッセージ表示 | 同一画面 |

## 備考

- この画面はVue.jsコンポーネント（`#js-project-new-runner`）によりレンダリングされる
- RunnerトークンはCREATED_RUNNER_TOKEN_PREFIX（`glrt-`）が付与される
- Runnerは作成後1時間以内に登録を完了する必要がある（REGISTRATION_AVAILABILITY_TIME）
- タグの最大数は50個に制限されている

---

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

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

### 推奨読解順序

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

Runnerのデータモデルと関連テーブル構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | runner.rb | `app/models/ci/runner.rb` | Runnerモデルの定義、バリデーション、enum定義を確認 |
| 1-2 | runner_project.rb | `app/models/ci/runner_project.rb` | RunnerとProjectの関連付けモデル |

**読解のコツ**: `enum :runner_type` でinstance_type/group_type/project_typeの区別、`enum :creation_state` でstarted/finishedの状態管理、`add_authentication_token_field :token` でトークン生成の仕組みを理解する。

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

ビューテンプレートとコントローラの処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | new.html.haml | `app/views/projects/runners/new.html.haml` | Vueコンポーネントのマウントポイント、data属性でproject_idを渡す |
| 2-2 | runners_controller.rb | `app/controllers/projects/runners_controller.rb` | before_action、権限チェック、newアクション |

**主要処理フロー**:
1. **行4-6**: `authorize_create_runners!` で権限チェック
2. **行30**: `new` アクションは空（ビューレンダリングのみ）

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

Vueコンポーネントの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | project_new_runner | `app/assets/javascripts/ci/runner/project_new_runner/` | Vueコンポーネントのエントリーポイント |

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

Runner作成のGraphQL Mutationを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | runner_create.rb | `app/graphql/mutations/ci/runner/create.rb` | GraphQL Mutation定義 |

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

Runner作成のビジネスロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | create_runner_service.rb | `app/services/ci/runners/create_runner_service.rb` | Runner作成のビジネスロジック |

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

```
projects/runners/new.html.haml
    │
    └─ #js-project-new-runner (Vue Component)
           │
           └─ GraphQL Mutation (runnerCreate)
                  │
                  └─ Ci::Runners::CreateRunnerService
                         │
                         ├─ Ci::Runner.create
                         │      └─ TokenAuthenticatable (token生成)
                         │
                         └─ Ci::RunnerProject.create
```

### データフロー図

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

project_id ──────▶ RunnersController#new ──────▶ Vue Component mount
                           │
Form Data ──────────────────────────────────▶ GraphQL Mutation
(description,                                        │
 tag_list,                                           ▼
 access_level, etc.)              Ci::Runners::CreateRunnerService
                                                     │
                                                     ▼
                                        ci_runners (INSERT)
                                        ci_runner_projects (INSERT)
                                                     │
                                                     ▼
                                        Runner Token ──────▶ Register Page
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| new.html.haml | `app/views/projects/runners/new.html.haml` | テンプレート | Runner新規登録画面のビュー |
| runners_controller.rb | `app/controllers/projects/runners_controller.rb` | コントローラ | HTTPリクエスト処理 |
| runner.rb | `app/models/ci/runner.rb` | モデル | Runnerエンティティ定義 |
| runner_project.rb | `app/models/ci/runner_project.rb` | モデル | Runner-Project関連 |
| create_runner_service.rb | `app/services/ci/runners/create_runner_service.rb` | サービス | Runner作成ロジック |
| project.rb | `config/routes/project.rb` | ルーティング | URLルーティング定義（行102-107） |
