# 画面設計書 61-MR一覧

## 概要

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

### 本画面の処理概要

本画面は、プロジェクト内のマージリクエスト（MR）を一覧形式で表示し、効率的な管理・操作を可能にする画面である。コードレビューワークフローの中心的な役割を担い、開発チームがコード変更の状態を把握し、レビュー・マージ作業を円滑に進めるための基盤を提供する。

**業務上の目的・背景**：ソフトウェア開発において、コード変更のレビューとマージは品質管理の重要なプロセスである。複数の開発者が並行して作業するプロジェクトでは、マージリクエストを効率的に管理し、適切な優先順位でレビューを行う必要がある。本画面は、すべてのマージリクエストを一元的に確認でき、フィルタリングやソートによって必要な情報を迅速に取得できる環境を提供する。

**画面へのアクセス方法**：プロジェクトページの左側ナビゲーションメニューから「Code」>「Merge requests」を選択するか、プロジェクトのURL末尾に`/-/merge_requests`を追加してアクセスする。

**主要な操作・処理内容**：
1. マージリクエストの一覧表示（オープン/マージ済み/クローズの状態別）
2. ラベル、マイルストーン、作成者、アサイニーによるフィルタリング
3. 作成日時、更新日時、マイルストーン期限などによるソート
4. 一括操作（ラベル付与、アサイン、クローズなど）
5. 新規マージリクエストの作成画面への遷移
6. 個別マージリクエスト詳細画面への遷移
7. CSV形式でのエクスポート
8. RSSフィードでの購読

**画面遷移**：
- 遷移元：プロジェクトトップページ、ダッシュボード、ナビゲーションメニュー
- 遷移先：MR新規作成画面、MR詳細画面、ユーザープロフィール画面、ラベル一覧

**権限による表示制御**：
- 閲覧権限（Reporter以上）：マージリクエストの一覧表示、フィルタリング
- 一括更新権限（Developer以上）：ラベル一括付与、一括アサイン
- 管理者権限（Maintainer以上）：一括クローズ、設定変更

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | マージリクエスト作成 | 主機能 | マージリクエストの一覧表示 |
| 40 | ラベル管理 | 補助機能 | ラベルによるフィルタリング |

## 画面種別

一覧

## URL/ルーティング

| メソッド | URL | アクション | 説明 |
|----------|-----|-----------|------|
| GET | `/:namespace_id/:project_id/-/merge_requests` | index | MR一覧画面表示 |
| GET | `/:namespace_id/:project_id/-/merge_requests.atom` | index | RSSフィード |
| GET | `/:namespace_id/:project_id/-/merge_requests.json` | index | JSON形式データ取得 |
| POST | `/:namespace_id/:project_id/-/merge_requests/bulk_update` | bulk_update | 一括更新 |
| POST | `/:namespace_id/:project_id/-/merge_requests/export_csv` | export_csv | CSVエクスポート |

## 入出力項目

### フィルタリング項目

| 項目名 | データ型 | 必須 | 説明 |
|--------|---------|------|------|
| scope | string | - | スコープ（all/created_by_me/assigned_to_me） |
| state | string | - | 状態（opened/merged/closed/all） |
| assignee_id | integer | - | アサイニーのユーザーID |
| author_id | integer | - | 作成者のユーザーID |
| reviewer_id | integer | - | レビュアーのユーザーID |
| label_name | string[] | - | ラベル名（複数指定可） |
| milestone_title | string | - | マイルストーン名 |
| search | string | - | 検索キーワード |
| source_branch | string | - | ソースブランチ名 |
| target_branch | string | - | ターゲットブランチ名 |
| wip | string | - | WIP/Draftフィルタ（yes/no） |
| sort | string | - | ソート条件 |

### ソート条件

| 値 | 説明 |
|----|------|
| created_desc | 作成日時（降順） |
| created_asc | 作成日時（昇順） |
| updated_desc | 更新日時（降順） |
| updated_asc | 更新日時（昇順） |
| milestone_due_desc | マイルストーン期限（降順） |
| milestone_due_asc | マイルストーン期限（昇順） |
| merged_at_desc | マージ日時（降順） |
| merged_at_asc | マージ日時（昇順） |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| MR番号 | integer | マージリクエストのIID |
| タイトル | string | マージリクエストのタイトル |
| 状態 | string | open/merged/closed |
| 作成者 | object | 作成者のユーザー情報 |
| アサイニー | object[] | アサインされたユーザー一覧 |
| レビュアー | object[] | レビュアー一覧 |
| ラベル | object[] | 付与されたラベル一覧 |
| マイルストーン | object | 関連マイルストーン |
| パイプライン状態 | string | 最新パイプラインの状態 |
| コメント数 | integer | コメント総数 |
| ソースブランチ | string | マージ元ブランチ |
| ターゲットブランチ | string | マージ先ブランチ |
| 作成日時 | datetime | 作成日時 |
| 更新日時 | datetime | 最終更新日時 |
| マージ日時 | datetime | マージされた日時 |
| Draft状態 | boolean | Draft（WIP）かどうか |
| 承認状態 | object | 承認の状態と必要承認数 |

## イベント仕様

### 1-フィルター適用

フィルター条件を変更した際、URLパラメータを更新し、サーバーに対してJSONリクエストを送信して一覧を再取得する。フロントエンドはVue.jsコンポーネントで実装されており、リアクティブに表示を更新する。

### 2-ソート変更

ソート条件を変更すると、sort パラメータが更新され、一覧が再取得される。ユーザー設定に保存され、次回アクセス時も同じソート条件が適用される。

### 3-一括操作

チェックボックスで複数のMRを選択し、サイドバーから一括操作を実行する。
- ラベルの一括付与/削除
- マイルストーンの一括設定
- アサイニーの一括設定
- 一括クローズ

### 4-新規MR作成ボタン押下

「New merge request」ボタンをクリックすると、MR新規作成画面（`project_new_merge_request_path`）に遷移する。

### 5-MR行クリック

MR一覧の行をクリックすると、該当MRの詳細画面（`project_merge_request_path`）に遷移する。

### 6-CSVエクスポート

エクスポートボタンをクリックすると、現在のフィルター条件に基づいたCSVファイルがバックグラウンドで生成され、ユーザーのメールアドレスに送信される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 一覧表示 | merge_requests | SELECT | MR一覧の取得 |
| 一覧表示 | labels | SELECT | ラベル情報の取得 |
| 一覧表示 | milestones | SELECT | マイルストーン情報の取得 |
| 一覧表示 | ci_pipelines | SELECT | パイプライン状態の取得 |
| 一括ラベル付与 | label_links | INSERT | ラベルリンクの作成 |
| 一括アサイン | merge_request_assignees | INSERT/DELETE | アサイン情報の更新 |
| 一括クローズ | merge_requests | UPDATE | state_idの更新 |

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

#### merge_requests（一括クローズ時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | state_id | 2 (closed) | 状態をクローズに変更 |
| UPDATE | updated_at | 現在時刻 | 自動更新 |

#### label_links（一括ラベル付与時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | target_id | MRのID | |
| INSERT | target_type | 'MergeRequest' | |
| INSERT | label_id | 選択されたラベルID | |
| INSERT | created_at | 現在時刻 | |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| 情報 | Your CSV export has started. It will be emailed to {email} when complete. | CSVエクスポート開始時 |
| 警告 | No merge requests found | 検索結果が0件の場合 |
| エラー | Failed to load merge requests | API取得失敗時 |
| 情報 | {n} merge requests selected | 一括選択時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| プロジェクトが見つからない | 404エラーページを表示 |
| 閲覧権限がない | 403エラーページを表示 |
| APIタイムアウト | エラーメッセージを表示し、リトライを促す |
| 検索レート制限超過 | 429エラーを返し、待機を促す |

## 備考

- 一覧表示はVue.jsによるSPAコンポーネント（`js-merge-request-list-root`）で実装
- ポーリング間隔は10秒（10,000ミリ秒）
- ページネーションは20件/ページがデフォルト
- RSSフィードはAtom形式で提供

---

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

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

### 推奨読解順序

#### 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のレスポンス形式を理解 |

**読解のコツ**: ActiveRecordモデルのスコープ、関連（has_many, belongs_to）、enum定義に注目する。

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

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

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

**主要処理フロー**:
1. **行97-104**: `index`アクション - @issuablesから@merge_requestsを設定、HTML/Atom形式で応答
2. **行18**: `skip_before_action :merge_request` - indexアクションではMRインスタンスを事前取得しない
3. **行32**: `before_action :set_issuables_index` - IssuableCollectionsモジュールで一覧を取得

#### Step 3: Finder層を理解する

データ取得のロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | merge_requests_finder.rb | `app/finders/merge_requests_finder.rb` | フィルタリングロジック |
| 3-2 | issuable_finder.rb | `app/finders/issuable_finder.rb` | 共通フィルターロジック |

**主要処理フロー**:
- `execute`メソッドでフィルター条件を順次適用
- スコープ、状態、ラベル、マイルストーンなどでWHERE句を構築

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.haml | `app/views/projects/merge_requests/index.html.haml` | Vueマウントポイントの設定 |
| 4-2 | merge_requests_helper.rb | `app/helpers/merge_requests_helper.rb` | `project_merge_requests_list_data`メソッド（行266-281） |

**主要処理フロー**:
- **行15**: `js-merge-request-list-root`要素でVueコンポーネントをマウント
- **行16-17**: 一括更新権限がある場合、サイドバーを表示

#### Step 5: フロントエンド（Vue.js）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | merge_requests_list_app.vue | `app/assets/javascripts/merge_requests/list/components/merge_requests_list_app.vue` | メインコンポーネント |

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

```
HTTP Request (GET /project/-/merge_requests)
    │
    ├─ MergeRequestsController#index
    │      │
    │      ├─ before_action :set_issuables_index
    │      │      └─ IssuableCollections#set_issuables_index
    │      │             └─ MergeRequestsFinder#execute
    │      │                    ├─ filter_items (スコープ適用)
    │      │                    ├─ filter_by_state
    │      │                    ├─ filter_by_labels
    │      │                    └─ filter_by_milestone
    │      │
    │      └─ respond_to do |format|
    │             ├─ format.html → render index.html.haml
    │             │                    └─ Vue.js マウント
    │             └─ format.json → JSON API レスポンス
    │
    └─ MergeRequestSerializer#represent (JSON時)
```

### データフロー図

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

URLパラメータ ──────▶ MergeRequestsFinder ──────▶ MRコレクション
(フィルター条件)           │
                          ├─ scope filter
                          ├─ state filter
                          ├─ label filter
                          └─ sort
                                     │
                                     ▼
                          MergeRequestSerializer
                                     │
                                     ▼
Vue.js Component ◀────────────── JSON/HTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | コントローラー | リクエストハンドリング |
| merge_requests_helper.rb | `app/helpers/merge_requests_helper.rb` | ヘルパー | ビューヘルパーメソッド |
| index.html.haml | `app/views/projects/merge_requests/index.html.haml` | ビュー | HTMLテンプレート |
| merge_request.rb | `app/models/merge_request.rb` | モデル | データモデル定義 |
| merge_requests_finder.rb | `app/finders/merge_requests_finder.rb` | Finder | データ取得ロジック |
| merge_request_serializer.rb | `app/serializers/merge_request_serializer.rb` | シリアライザー | JSON変換 |
| merge_requests.rb | `config/routes/merge_requests.rb` | ルーティング | URL定義 |
| bulk_update_sidebar.haml | `app/views/projects/merge_requests/_bulk_update_sidebar.html.haml` | パーシャル | 一括更新サイドバー |
