# 画面設計書 148-マイルストーン一覧

## 概要

本ドキュメントは、GitLabにおけるグループマイルストーン一覧画面の設計仕様を定義するものである。グループに定義されたマイルストーンの一覧表示、検索、管理を行う画面を提供する。

### 本画面の処理概要

グループマイルストーン一覧画面は、グループに定義されたマイルストーンを一覧表示し、管理するための画面である。マイルストーンは課題やマージリクエストを期限ベースでグルーピングするために使用され、プロジェクト横断的な進捗管理が可能となる。

**業務上の目的・背景**：スプリント計画やリリース管理において、複数のプロジェクトにまたがる作業を一元的に追跡する必要がある。グループマイルストーンを使用することで、配下のプロジェクト全体の進捗を把握し、期限管理を効率化できる。

**画面へのアクセス方法**：以下のいずれかの方法でアクセス可能である。
- グループ詳細画面のサイドバーから「Plan > Milestones」を選択
- URL直接アクセス: `/groups/{group_path}/-/milestones`

**主要な操作・処理内容**：
1. グループマイルストーンの一覧表示（ページネーション付き）
2. マイルストーンの状態フィルタリング（Active/Closed/All）
3. マイルストーンのタイトル検索
4. マイルストーンのソート
5. マイルストーン新規作成画面への遷移

**画面遷移**：
- 遷移元：グループ詳細画面、グループサイドバー
- 遷移先：マイルストーン詳細画面、マイルストーン新規作成画面

**権限による表示制御**：
- Guest：マイルストーン一覧の閲覧
- Reporter以上：マイルストーン詳細の閲覧
- Maintainer以上：マイルストーン作成、編集、削除（admin_milestone権限）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 42 | マイルストーン管理 | 主機能 | グループマイルストーンの一覧表示 |

## 画面種別

一覧

## URL/ルーティング

- パス: `/groups/{group_path}/-/milestones`
- ルーティング: `groups/milestones#index`
- HTTPメソッド: GET
- 対応フォーマット: HTML, JSON

## 入出力項目

| 項目名 | 種別 | 必須 | データ型 | 説明 |
|--------|------|------|----------|------|
| page | クエリパラメータ | 任意 | Integer | ページ番号 |
| state | クエリパラメータ | 任意 | String | 状態フィルタ（active/closed/all） |
| search_title | クエリパラメータ | 任意 | String | タイトル検索クエリ |
| sort | クエリパラメータ | 任意 | String | ソート順（due_date_asc等） |

## 表示項目

| 項目名 | データ型 | 説明 | 表示条件 |
|--------|----------|------|----------|
| ページタイトル | h1（sr-only） | 「Milestones」 | 常時 |
| 状態フィルタタブ | Tab | Active/Closed/All | マイルストーン存在時 |
| 検索フォーム | TextInput | タイトル検索 | マイルストーン存在時 |
| ソートドロップダウン | Dropdown | ソート順選択 | マイルストーン存在時 |
| 新規作成ボタン | Button | マイルストーン作成へ遷移 | admin_milestone権限 |
| マイルストーンリスト | List | マイルストーン一覧 | マイルストーン存在時 |
| 削除モーダル | Modal | 削除確認 | 削除時 |
| 空状態 | EmptyState | 初期状態/結果0件 | マイルストーン0件時 |
| ページネーション | Pagination | ページ切替 | 複数ページ時 |

## イベント仕様

### 1-マイルストーン一覧表示（GET index）

1. `Milestone.states_count`で状態別カウント取得（15行目）
2. `milestones`メソッドで`MilestonesFinder`呼び出し（16行目）
3. 検索パラメータの適用（119-124行目）
4. デフォルトソートは`due_date_asc`（122行目）
5. ページネーション適用
6. 状態フィルタタブの表示判定（6行目）
7. マイルストーンリストのレンダリング

### 2-状態フィルタリング

1. stateパラメータの取得
2. `MilestonesFinder`に状態条件を渡す
3. Active（進行中）/Closed（完了）/Allで絞り込み

### 3-タイトル検索

1. search_titleパラメータの取得
2. `MilestonesFinder`に検索条件を渡す
3. タイトルでの部分一致検索
4. 検索結果をページネーション付きで表示

### 4-ソート

1. sortパラメータの取得（デフォルト: due_date_asc）
2. 利用可能なソート順：
   - due_date_asc: 期限日昇順
   - due_date_desc: 期限日降順
   - start_date_asc: 開始日昇順
   - start_date_desc: 開始日降順
   - name_asc: タイトル昇順
   - name_desc: タイトル降順

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 一覧表示 | milestones | SELECT | グループマイルストーン取得 |
| 一覧表示 | issues | SELECT | 課題カウント取得 |
| 一覧表示 | merge_requests | SELECT | MRカウント取得 |
| 状態カウント | milestones | SELECT | 状態別件数取得 |

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

#### milestones

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, title, description | group_id=グループID | グループマイルストーン |
| SELECT | start_date, due_date | - | 期間情報 |
| SELECT | state | フィルタ条件 | active/closed |
| SELECT | iid | - | 表示用識別子 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 情報 | No milestones to show | マイルストーン0件時 |
| MSG-002 | 情報 | Create a milestone to start tracking progress | 初期状態時 |

## 例外処理

| 例外条件 | 処理内容 | 遷移先 |
|----------|----------|--------|
| グループ不存在 | 404エラー | エラーページ |
| 閲覧権限なし | 404エラー | エラーページ |

## 備考

- マイルストーンは子孫グループとプロジェクトのマイルストーンも含めて表示可能
- state_machineで状態遷移を管理（active -> closed）
- デフォルトソートは期限日昇順（due_date_asc）
- JSON形式でのレスポンスにも対応（id, title, due_date, name）
- プロジェクトマイルストーンとグループマイルストーンで表示パーシャルが異なる

---

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

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

### 推奨読解順序

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

マイルストーンモデルとグループとの関連を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | milestone.rb | `app/models/milestone.rb` | マイルストーンモデル、state_machine |
| 1-2 | timebox.rb | `app/models/concerns/timebox.rb` | 共通の期間管理ロジック |

**読解のコツ**: `state_machine :state, initial: :active`（93行目）で状態遷移を確認。`belongs_to :group`と`belongs_to :project`で所属を確認。

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

コントローラーの`index`アクションがエントリーポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | milestones_controller.rb | `app/controllers/groups/milestones_controller.rb` | indexアクション |

**主要処理フロー**:
1. **12-22行目**: indexアクションの定義
2. **15行目**: `Milestone.states_count`で状態別カウント取得
3. **16行目**: `milestones`メソッドでMilestonesFinder呼び出し
4. **109-111行目**: `milestones`プライベートメソッド
5. **119-124行目**: `search_params`でフィルタ条件設定
6. **122行目**: デフォルトソート`due_date_asc`

#### Step 3: ファインダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | milestones_finder.rb | `app/finders/milestones_finder.rb` | マイルストーン検索ロジック |

#### Step 4: ビューレイヤーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.haml | `app/views/groups/milestones/index.html.haml` | メインテンプレート |
| 4-2 | _milestone.html.haml | `app/views/groups/milestones/_milestone.html.haml` | マイルストーン表示パーシャル |
| 4-3 | _milestones_filter.html.haml | `app/views/shared/_milestones_filter.html.haml` | 状態フィルタ |
| 4-4 | _search_form.html.haml | `app/views/shared/milestones/_search_form.html.haml` | 検索フォーム |

**主要処理フロー**:
- **6行目**: 状態カウントが存在するかチェック
- **8行目**: 状態フィルタタブのレンダリング
- **11-12行目**: 検索フォームとソートドロップダウン
- **13-15行目**: admin_milestone権限時に新規作成ボタン
- **22-29行目**: マイルストーンリストのループ表示
- **26-29行目**: プロジェクト/グループでパーシャル分岐
- **30行目**: ページネーション
- **32-35行目**: 空状態の表示

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

```
Groups::MilestonesController#index
    │
    ├─ HTML format
    │      │
    │      ├─ Milestone.states_count(group_projects, [group])
    │      │      └─ 状態別カウント取得
    │      │
    │      └─ milestones (private method)
    │             │
    │             └─ MilestonesFinder.new(search_params).execute
    │                    │
    │                    ├─ state filter
    │                    ├─ search_title filter
    │                    ├─ sort
    │                    └─ group_ids filter
    │
    └─ JSON format
           └─ milestones.to_json(only: [:id, :title, :due_date])
```

### データフロー図

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

Request params ──────────▶ MilestonesController#index ──▶ HTML Response
(state, search_title,             │                       (マイルストーン一覧)
 sort, page)                      │
                                  ▼
                          search_params
                                  │
                                  ├── state filter (active/closed/all)
                                  ├── search_title filter
                                  └── sort (due_date_asc default)
                                          │
                                          ▼
                                  MilestonesFinder
                                          │
                                          ├── group_ids filter
                                          │    (self_and_descendants)
                                          │
                                          └── project_ids filter
                                               (with_issues_or_mrs_available)
                                                  │
                                                  ▼
                                          milestones table (SELECT)
                                                  │
                                                  ▼
                                          Pagination
                                                  │
                                                  ▼
                                          milestone partial rendering
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| milestones_controller.rb | `app/controllers/groups/milestones_controller.rb` | コントローラー | indexアクション定義 |
| milestone.rb | `app/models/milestone.rb` | モデル | マイルストーンモデル |
| index.html.haml | `app/views/groups/milestones/index.html.haml` | ビュー | メインテンプレート |
| _milestone.html.haml | `app/views/groups/milestones/_milestone.html.haml` | ビュー | マイルストーンパーシャル |
| _milestones_filter.html.haml | `app/views/shared/_milestones_filter.html.haml` | ビュー | 状態フィルタ |
| _search_form.html.haml | `app/views/shared/milestones/_search_form.html.haml` | ビュー | 検索フォーム |
| _milestones_sort_dropdown.html.haml | `app/views/shared/_milestones_sort_dropdown.html.haml` | ビュー | ソートドロップダウン |
| milestones_finder.rb | `app/finders/milestones_finder.rb` | ファインダー | マイルストーン検索 |
| empty_states/milestones.html.haml | `app/views/shared/empty_states/_milestones.html.haml` | ビュー | 空状態表示 |
