# 画面設計書 151-マイルストーン編集

## 概要

本ドキュメントは、GitLabのグループマイルストーン編集画面の設計仕様を定義するものです。

### 本画面の処理概要

この画面では、グループレベルで作成されたマイルストーンの編集を行います。マイルストーンはプロジェクト横断的なスケジュール管理に使用され、タイトル、説明、期間（開始日・終了日）の変更が可能です。

**業務上の目的・背景**：グループマイルストーンは、複数のプロジェクトにまたがる開発スケジュールを統一的に管理するために必要です。スプリントやリリースサイクルの計画変更に対応するため、マイルストーンの編集機能が求められます。アジャイル開発やスクラムにおけるイテレーション管理において重要な役割を果たします。

**画面へのアクセス方法**：グループのサイドバーから「課題」>「マイルストーン」を選択し、マイルストーン一覧画面からマイルストーン詳細画面を開き、「編集」ボタンをクリックすることでアクセスできます。直接URLからもアクセス可能です。

**主要な操作・処理内容**：
1. マイルストーンのタイトルを変更する
2. マイルストーンの説明をMarkdown形式で編集する
3. 開始日・終了日を設定・変更する
4. 変更内容を保存する
5. 編集をキャンセルして詳細画面に戻る

**画面遷移**：グループマイルストーン一覧画面またはマイルストーン詳細画面から遷移してきます。保存成功後はマイルストーン詳細画面にリダイレクトされます。キャンセル時もマイルストーン詳細画面に戻ります。

**権限による表示制御**：グループの「admin_milestone」権限を持つユーザーのみがこの画面にアクセスできます。権限がない場合は404エラーが表示されます。通常、グループのMaintainer以上のロールを持つユーザーが該当します。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 41 | マイルストーン管理 | 主機能 | グループマイルストーンの編集処理 |

## 画面種別

編集

## URL/ルーティング

- パス: `/groups/:group_id/-/milestones/:id/edit`
- HTTPメソッド: GET（表示）、PATCH/PUT（更新）
- コントローラー: `Groups::MilestonesController#edit`, `#update`

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 最大長 | 説明 |
|--------|--------|-----|------|--------|------|
| タイトル | title | テキスト | ○ | 255文字 | マイルストーンの名称 |
| 説明 | description | テキストエリア | - | - | Markdown形式で記述可能 |
| 開始日 | start_date | 日付 | - | - | マイルストーンの開始日 |
| 終了日 | due_date | 日付 | - | - | マイルストーンの終了日 |
| ロックバージョン | lock_version | 隠しフィールド | - | - | 楽観的ロック制御用 |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ページタイトル | 「Edit milestone」と表示 |
| パンくずリスト | グループ > Milestones > マイルストーン名 > Edit |
| フォーム | マイルストーン編集用のフォーム |
| エラーメッセージ | バリデーションエラー時に表示 |
| コンフリクト警告 | 同時編集によるコンフリクト発生時に表示 |

## イベント仕様

### 1-Save changes（保存ボタン）

保存ボタン押下時、以下の処理が実行されます。

1. フォームデータがサーバーに送信される
2. `Milestones::UpdateService`が呼び出される
3. スパムチェックが実行される（公開グループの場合）
4. マイルストーンが更新される
5. `Milestones::MilestoneUpdatedEvent`がパブリッシュされる
6. 成功時: マイルストーン詳細画面にリダイレクト
7. 失敗時: エラーメッセージを表示して編集画面を再表示

### 2-Cancel（キャンセルボタン）

キャンセルボタン押下時、マイルストーン詳細画面にリダイレクトされます。変更内容は破棄されます。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | milestones | UPDATE | マイルストーン情報の更新 |

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

#### milestones

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | title | フォーム入力値 | 必須項目 |
| UPDATE | description | フォーム入力値 | 任意項目 |
| UPDATE | start_date | フォーム入力値 | 任意項目 |
| UPDATE | due_date | フォーム入力値 | 任意項目 |
| UPDATE | updated_at | 現在時刻 | 自動設定 |
| UPDATE | lock_version | インクリメント | 楽観的ロック |

## メッセージ仕様

| メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|-------------|--------------|---------------|---------|
| M001 | エラー | "Title can't be blank" | タイトルが空の場合 |
| M002 | エラー | "Title already being used for another group or project milestone." | タイトル重複時 |
| M003 | 警告 | "Someone edited this milestone at the same time you did. Please refresh your browser and make sure your changes will not unintentionally remove theirs." | 楽観的ロック競合時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| マイルストーンが見つからない | 404エラーページを表示 |
| 権限不足 | 404エラーページを表示（セキュリティ上、権限エラーは404として扱う） |
| 楽観的ロック競合（ActiveRecord::StaleObjectError） | コンフリクト警告を表示し、編集画面を再表示 |
| バリデーションエラー | エラーメッセージを表示して編集画面を再表示 |

## 備考

- 説明フィールドはMarkdownエディタで、プレビュー機能やクイックアクション入力補完が利用可能
- グループマイルストーンのタイトルは、グループ配下のすべてのプロジェクトおよびグループ階層内で一意である必要がある
- 楽観的ロック（lock_version）により同時編集の競合を検出

---

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

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

### 推奨読解順序

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

まず、マイルストーンのデータモデルと関連するエンティティを理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | milestone.rb | `app/models/milestone.rb` | マイルストーンモデルの定義、バリデーション、スコープを理解する |

**読解のコツ**: Milestoneモデルは`Timebox`モジュールをincludeしており、開始日・終了日の共通ロジックがある点に注意。`state_machine`による状態管理（active/closed）も重要。

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

コントローラーでのリクエスト処理フローを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | milestones_controller.rb | `app/controllers/groups/milestones_controller.rb` | edit/updateアクションの実装を理解する |

**主要処理フロー**:
1. **行40**: `edit`アクションでビューをレンダリング
2. **行42-80**: `update`アクションでマイルストーン更新処理
3. **行93-95**: `authorize_admin_milestones!`で権限チェック
4. **行113-117**: `milestone`メソッドでマイルストーンを取得

#### Step 3: ビジネスロジック層を理解する

サービスクラスでの更新処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_service.rb | `app/services/milestones/update_service.rb` | マイルストーン更新のビジネスロジックを理解する |

**主要処理フロー**:
- **行5-19**: `execute`メソッドで状態変更とアトリビュート更新を実行
- **行24-26**: `before_update`でスパムチェックを実行
- **行28-37**: `publish_event`でイベントを発行

#### Step 4: ビューテンプレートを理解する

フォームのレンダリング構造を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | edit.html.haml | `app/views/groups/milestones/edit.html.haml` | 編集画面のテンプレート構造を理解する |
| 4-2 | _form.html.haml | `app/views/groups/milestones/_form.html.haml` | フォームの詳細実装を理解する |

**主要処理フロー**:
- **行6-7**: ページヘッダーとフォームのレンダリング
- **フォーム行1-37**: フォームフィールドの定義とMarkdownエディタの設定

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

```
Groups::MilestonesController#edit / #update
    │
    ├─ before_action :milestone (行6)
    │      └─ group.milestones.find_by_iid (行114)
    │
    ├─ before_action :authorize_admin_milestones! (行7)
    │      └─ can?(current_user, :admin_milestone, group) (行94)
    │
    └─ update アクション (行42-80)
           │
           ├─ Milestones::UpdateService.new(...).execute (行43)
           │      ├─ Milestones::ReopenService / CloseService (行9-13)
           │      ├─ milestone.assign_attributes (行15)
           │      ├─ before_update (行16) → check_for_spam
           │      └─ publish_event (行17) → Gitlab::EventStore.publish
           │
           └─ redirect_to / render (行47-51, 56-59)
```

### データフロー図

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

フォームデータ          Groups::MilestonesController
(title, description,         │
 start_date, due_date,       │
 lock_version)               ▼
        ───────────▶  Milestones::UpdateService
                             │
                             ├──▶ 状態変更（activate/close）
                             │
                             ├──▶ スパムチェック
                             │
                             ├──▶ milestone.save
                             │        │
                             │        ▼
                             │    milestonesテーブル
                             │
                             └──▶ MilestoneUpdatedEvent
                                      │
                                      ▼
                              Gitlab::EventStore ───▶ 詳細画面へリダイレクト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| milestones_controller.rb | `app/controllers/groups/milestones_controller.rb` | コントローラー | リクエスト処理・権限チェック |
| update_service.rb | `app/services/milestones/update_service.rb` | サービス | 更新ビジネスロジック |
| milestone.rb | `app/models/milestone.rb` | モデル | データ定義・バリデーション |
| edit.html.haml | `app/views/groups/milestones/edit.html.haml` | ビュー | 編集画面テンプレート |
| _form.html.haml | `app/views/groups/milestones/_form.html.haml` | 部分ビュー | フォームテンプレート |
| group.rb | `config/routes/group.rb` | ルーティング | URLルーティング定義（行109-116） |
