# 画面設計書 63-MR詳細

## 概要

本ドキュメントは、GitLabプロジェクトのマージリクエスト詳細画面の設計仕様を定義するものである。

### 本画面の処理概要

本画面は、マージリクエスト（MR）の詳細情報を表示し、コードレビュー、議論、承認、マージなどのワークフロー全体を統括する画面である。開発チームのコラボレーションの中心的な役割を担い、コード変更の確認から最終的なマージまでのプロセスを一元管理する。

**業務上の目的・背景**：マージリクエストはGitLabにおけるコードレビューと変更管理の核となる機能である。開発者は本画面を通じて、変更内容の確認、コメントによる議論、修正提案（サジェスチョン）の作成・適用、承認の付与、そして最終的なマージを行う。複数のタブで情報を整理し、効率的なレビュープロセスを実現する。

**画面へのアクセス方法**：
1. MR一覧画面から対象のMRをクリック
2. ダッシュボードのMR一覧から選択
3. 通知メールのリンクから
4. MR作成直後のリダイレクト
5. URLに直接`/-/merge_requests/:iid`を入力

**主要な操作・処理内容**：
1. MRの基本情報（タイトル、説明、状態）の確認
2. ディスカッションへの参加（コメント、リプライ、解決）
3. コミット一覧の確認
4. CI/CDパイプラインの状態確認
5. コード差分の確認とラインコメント
6. サジェスチョンの作成・適用
7. 承認（Approve）の付与
8. マージの実行
9. 自動マージの設定
10. サイドバーでのメタデータ編集（アサイニー、レビュアー、ラベル等）

**画面遷移**：
- 遷移元：MR一覧、ダッシュボード、通知、検索結果、課題詳細
- 遷移先：MR編集画面、コンフリクト解決画面、パイプライン詳細、コミット詳細、ユーザープロフィール

**権限による表示制御**：
- ゲスト：MR閲覧、コメント
- レポーター：ラベル・マイルストーンの確認
- 開発者：承認、サジェスチョン適用、アサイン
- メンテナー：マージ実行、設定変更、MRクローズ

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | マージリクエスト編集 | 主機能 | マージリクエストの詳細表示 |
| 30 | マージリクエストマージ | 補助機能 | マージ実行 |
| 31 | コードレビュー | 補助機能 | コードレビューコメント |
| 33 | 自動マージ | 補助機能 | 自動マージ設定 |
| 35 | レビュアー・承認者管理 | 補助機能 | レビュアー・承認者の設定 |

## 画面種別

詳細

## URL/ルーティング

| メソッド | URL | アクション | 説明 |
|----------|-----|-----------|------|
| GET | `/:namespace_id/:project_id/-/merge_requests/:id` | show | MR詳細画面表示 |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id/diffs` | diffs | 差分タブ表示 |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id/commits` | commits | コミットタブ（AJAX） |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id/pipelines` | pipelines | パイプラインタブ（AJAX） |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id/discussions` | discussions | ディスカッション取得 |
| POST | `/:namespace_id/:project_id/-/merge_requests/:id/merge` | merge | マージ実行 |
| POST | `/:namespace_id/:project_id/-/merge_requests/:id/cancel_auto_merge` | cancel_auto_merge | 自動マージキャンセル |
| POST | `/:namespace_id/:project_id/-/merge_requests/:id/rebase` | rebase | リベース実行 |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id.json` | show | JSON形式データ取得 |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id.patch` | show | パッチ形式出力 |
| GET | `/:namespace_id/:project_id/-/merge_requests/:id.diff` | show | 差分形式出力 |

## 入出力項目

### サイドバー編集項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| assignee_ids | integer[] | アサイニーのユーザーID |
| reviewer_ids | integer[] | レビュアーのユーザーID |
| label_ids | integer[] | ラベルID |
| milestone_id | integer | マイルストーンID |
| time_estimate | string | 見積時間 |
| discussion_locked | boolean | ディスカッションロック |

### マージ実行パラメータ

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| sha | string | マージ対象のコミットSHA |
| squash | boolean | squashマージ有効化 |
| should_remove_source_branch | boolean | ソースブランチ削除 |
| auto_merge_strategy | string | 自動マージ戦略 |
| commit_message | string | マージコミットメッセージ |
| squash_commit_message | string | squashコミットメッセージ |

## 表示項目

### 基本情報

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| MR番号 | integer | マージリクエストのIID |
| タイトル | string | MRタイトル |
| 状態 | string | open/merged/closed |
| Draft状態 | boolean | Draft（WIP）フラグ |
| 説明 | text | Markdown形式の説明文 |
| 作成者 | object | 作成者情報 |
| 作成日時 | datetime | 作成日時 |
| 更新日時 | datetime | 最終更新日時 |

### タブ情報

| タブ名 | 表示内容 | バッジ |
|--------|---------|-------|
| Overview | ディスカッション、MRウィジェット | コメント数 |
| Commits | コミット一覧 | コミット数 |
| Pipelines | パイプライン一覧 | パイプライン数 |
| Changes | ファイル差分 | 変更ファイル数 |

### MRウィジェット

| 項目名 | 説明 |
|--------|------|
| マージ可能状態 | マージの可否と理由 |
| パイプライン状態 | 最新パイプラインの結果 |
| 承認状態 | 必要承認数と現在の承認数 |
| コンフリクト状態 | コンフリクトの有無 |
| ブランチ状態 | ソース/ターゲットブランチの状態 |

## イベント仕様

### 1-タブ切り替え

タブをクリックすると、対応するコンテンツがAJAXで読み込まれ表示される。URLのハッシュフラグメントが更新され、ブラウザ履歴に記録される。

### 2-コメント投稿

ディスカッション欄またはコード差分の行にコメントを投稿できる。投稿後は即座に表示に反映される。

### 3-サジェスチョン作成・適用

コード差分に対して修正提案（サジェスチョン）を作成できる。提案者以外のユーザーが「Apply suggestion」で即座に適用可能。

### 4-マージ実行

「Merge」ボタンをクリックすると、マージ処理が非同期で実行される。成功時はMRがmerged状態に更新され、画面が再描画される。

### 5-自動マージ設定

「Set to auto-merge」を選択すると、パイプライン成功後に自動でマージが実行されるよう設定される。

### 6-承認付与

「Approve」ボタンをクリックすると、現在のユーザーによる承認が記録される。必要承認数に達するとマージ可能になる（設定による）。

### 7-サイドバー編集

サイドバーの各項目（アサイニー、ラベル等）をクリックすると、ドロップダウンが表示され、選択後即座にサーバーに保存される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 詳細表示 | merge_requests | SELECT | MR情報の取得 |
| コメント投稿 | notes | INSERT | コメントレコード作成 |
| マージ実行 | merge_requests | UPDATE | state_idの更新 |
| マージ実行 | events | INSERT | マージイベント記録 |
| 承認付与 | approvals | INSERT | 承認レコード作成 |
| アサイン変更 | merge_request_assignees | INSERT/DELETE | アサイニー更新 |
| ラベル変更 | label_links | INSERT/DELETE | ラベル関連付け更新 |

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

#### merge_requests（マージ実行時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | state_id | 3 (merged) | マージ済み状態 |
| UPDATE | merged_at | 現在時刻 | |
| UPDATE | merged_by_id | 実行ユーザーID | |
| UPDATE | merge_commit_sha | マージコミットSHA | |
| UPDATE | updated_at | 現在時刻 | |

#### notes（コメント投稿時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | noteable_type | 'MergeRequest' | |
| INSERT | noteable_id | MRのID | |
| INSERT | author_id | コメント投稿者ID | |
| INSERT | note | コメント本文 | |
| INSERT | type | 'DiscussionNote'等 | |
| INSERT | created_at | 現在時刻 | |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| 成功 | Merged | マージ成功時 |
| 成功 | Set to auto-merge | 自動マージ設定時 |
| 警告 | This merge request has conflicts | コンフリクト発生時 |
| 警告 | The pipeline for this merge request failed | パイプライン失敗時 |
| エラー | This merge request cannot be merged | マージ不可時 |
| 情報 | This merge request is a draft | Draft状態時 |
| 情報 | This merge request has reached the maximum limit of versions | バージョン上限到達時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| MRが見つからない | 404エラーページを表示 |
| 閲覧権限がない | 403エラーページを表示 |
| マージ権限がない | マージボタン非表示またはエラーメッセージ |
| コンフリクト発生 | コンフリクト解決画面へのリンクを表示 |
| ソースブランチ削除済み | 警告メッセージとクローズ推奨 |

## 備考

- Vue.jsによるSPAコンポーネントで主要機能を実装
- ポーリング間隔は10秒（マージステータス更新）
- Diff表示はRapidDiffsコンポーネントで高速化可能
- リアルタイム更新はActionCableによるWebSocket通信

---

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

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

### 推奨読解順序

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

まず、マージリクエストの詳細表示に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | merge_request.rb | `app/models/merge_request.rb` | MRモデルの状態遷移、関連 |
| 1-2 | merge_request_serializer.rb | `app/serializers/merge_request_serializer.rb` | JSON APIレスポンス形式 |

**読解のコツ**: `state_machine`の定義、`has_many`関連、スコープ定義に注目する。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | showアクションの処理フロー |

**主要処理フロー**:
1. **行106-108**: `show`アクション - `show_merge_request`を呼び出し
2. **行410-465**: `show_merge_request` - マージ可能性チェック、レスポンス形式の分岐
3. **行467-503**: `render_html_page` - HTML表示用の変数設定

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

画面表示の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/projects/merge_requests/show.html.haml` | メインビュー（`_page`をレンダリング） |
| 3-2 | _page.html.haml | `app/views/projects/merge_requests/_page.html.haml` | タブ構成、ウィジェット配置（行1-117） |
| 3-3 | _mr_title.html.haml | `app/views/projects/merge_requests/_mr_title.html.haml` | タイトル・ヘッダー |
| 3-4 | _mr_box.html.haml | `app/views/projects/merge_requests/_mr_box.html.haml` | 基本情報ボックス |
| 3-5 | _widget.html.haml | `app/views/projects/merge_requests/_widget.html.haml` | マージウィジェット |

**主要処理フロー**:
- **行22**: メインコンテナ、`mr_action`でタブを制御
- **行31-50**: タブヘッダー（Overview/Commits/Pipelines/Changes）
- **行61-89**: Overviewタブ内容（ディスカッション、ウィジェット）
- **行91-102**: 各タブペイン

#### Step 4: マージ処理を理解する

マージのビジネスロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | merge_service.rb | `app/services/merge_requests/merge_service.rb` | マージ実行サービス |

**主要処理フロー**:
- `execute`メソッドでマージ処理を実行
- `hooks_validation_pass?`でフック検証
- 非同期マージは`MergeWorker`で実行

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

```
HTTP Request (GET /project/-/merge_requests/:id)
    │
    ├─ MergeRequestsController#show
    │      │
    │      ├─ before_action :merge_request (MRインスタンス取得)
    │      │
    │      └─ show_merge_request
    │             │
    │             ├─ close_merge_request_if_no_source_project
    │             │
    │             ├─ @merge_request.check_mergeability(async: true)
    │             │
    │             └─ respond_to
    │                    │
    │                    ├─ format.html → render_html_page
    │                    │                    │
    │                    │                    ├─ set_pipeline_variables
    │                    │                    └─ render → _page.html.haml
    │                    │
    │                    ├─ format.json → MergeRequestSerializer
    │                    │
    │                    ├─ format.patch → send_git_patch
    │                    │
    │                    └─ format.diff → send_git_diff
    │
    └─ Vue.jsコンポーネント (フロントエンド)
           │
           ├─ js-vue-mr-discussions (ディスカッション)
           ├─ js-merge-sticky-header (スティッキーヘッダー)
           └─ js-diffs-app (差分表示)
```

### データフロー図

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

MR ID ──────────────▶ MergeRequestsController ──────▶ MR詳細画面
                          │
                          ├─ merge_request取得
                          │      └─ Project#merge_requests.find
                          │
                          ├─ show_merge_request
                          │      ├─ mergeability check
                          │      └─ pipeline variables
                          │
                          └─ render_html_page
                                 ├─ @issuable_sidebar
                                 ├─ @current_user_data
                                 └─ @diffs_count
                                            │
                                            ▼
                               ──────────▶ HTML + Vue.js

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

マージボタン押下 ─────▶ MergeRequestsController#merge ──▶ マージ結果
                          │
                          ├─ merge_access_check
                          │
                          └─ merge!
                                 │
                                 ├─ MergeRequests::MergeService
                                 │      └─ Git merge操作
                                 │
                                 └─ 非同期: merge_async
                                            │
                                            ▼
                               ──────────▶ JSON { status: :success }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | コントローラー | リクエストハンドリング |
| show.html.haml | `app/views/projects/merge_requests/show.html.haml` | ビュー | メインビュー |
| _page.html.haml | `app/views/projects/merge_requests/_page.html.haml` | パーシャル | ページレイアウト |
| _mr_title.html.haml | `app/views/projects/merge_requests/_mr_title.html.haml` | パーシャル | タイトル表示 |
| _mr_box.html.haml | `app/views/projects/merge_requests/_mr_box.html.haml` | パーシャル | 基本情報 |
| _widget.html.haml | `app/views/projects/merge_requests/_widget.html.haml` | パーシャル | マージウィジェット |
| merge_request_serializer.rb | `app/serializers/merge_request_serializer.rb` | シリアライザー | JSON変換 |
| merge_service.rb | `app/services/merge_requests/merge_service.rb` | サービス | マージロジック |
| merge_request.rb | `app/models/merge_request.rb` | モデル | データモデル |
| merge_requests_helper.rb | `app/helpers/merge_requests_helper.rb` | ヘルパー | ビューヘルパー |
