# 機能設計書 11-グループ削除

## 概要

本ドキュメントは、GitLabにおけるグループ削除機能の設計仕様を定義する。グループおよびその配下のすべてのプロジェクト、サブグループを削除する機能について、処理フロー、入出力仕様、ビジネスルールを記載する。

### 本機能の処理概要

グループ削除機能は、GitLabのグループ管理において、不要となったグループを完全に削除するための機能である。グループを削除すると、そのグループに含まれるすべてのプロジェクト、サブグループ、メンバーシップ、ラベル、マイルストーン等の関連データも連鎖的に削除される。

**業務上の目的・背景**：組織変更やプロジェクト終了時に、不要となったグループを整理し、システムリソースの効率的な利用とセキュリティ管理を実現する。また、データガバナンスの観点から、不要なデータを適切に廃棄することが求められる。

**機能の利用シーン**：
- 組織改編により不要となったチームのグループを削除する場合
- プロジェクト終了後にグループごと整理する場合
- テスト目的で作成したグループを削除する場合

**主要な処理内容**：
1. 削除権限の確認（グループオーナーまたは管理者権限）
2. グループの削除スケジュール設定（ソフトデリート）
3. 猶予期間経過後の完全削除（ハードデリート）
4. 配下のプロジェクト、サブグループの再帰的削除
5. 関連するMattermostチーム、メンバー権限の削除
6. 削除イベントの発行と監査ログの記録

**関連システム・外部連携**：
- Mattermostチームとの連携（チーム削除）
- 通知サービスとの連携（削除スケジュール通知）
- バックグラウンドジョブシステム（Sidekiq）との連携

**権限による制御**：
- グループオーナー権限が必要
- 管理者はグループの即時削除が可能（allow_immediate_namespaces_deletion_for_user設定による）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 143 | グループ編集 | 主画面 | グループ削除オプションの操作 |
| 235 | グループ編集（管理者） | 参照画面 | 管理者によるグループ削除 |

## 機能種別

CRUD操作（Delete）/ バックグラウンド処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | 削除対象グループのID | 存在するグループであること |
| permanently_remove | Boolean | No | 即時削除フラグ（管理者のみ） | trueの場合、即時削除を試行 |

### 入力データソース

- 画面入力：削除確認ダイアログからのユーザー操作
- URLパラメータ：グループID

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| message | String | 削除結果メッセージ |
| status | Symbol | 処理結果（:success / :error） |

### 出力先

- 画面表示：削除完了/エラーメッセージ
- 監査ログ：削除操作の記録
- イベントストア：GroupDeletedEventの発行

## 処理フロー

### 処理シーケンス

```
1. 削除リクエスト受付
   └─ GroupsController#destroyが呼び出される

2. 権限チェック
   └─ authorize_remove_group!により削除権限を確認

3. 削除方式の判定
   └─ 即時削除 or 削除スケジュール設定

4. 削除スケジュール設定（通常フロー）
   └─ Groups::MarkForDeletionService#execute
      └─ グループ名・パスに削除サフィックスを付与
      └─ deletion_scheduleレコードの作成
      └─ 通知メールの送信

5. 即時削除（管理者フロー）
   └─ Groups::DestroyService#async_execute
      └─ GroupDestroyWorkerをエンキュー

6. バックグラウンド削除処理
   └─ Groups::DestroyService#execute
      └─ 配下プロジェクトの削除
      └─ サブグループの再帰的削除
      └─ Mattermostチームの削除
      └─ グループレコードの削除
      └─ GroupDeletedEventの発行
```

### フローチャート

```mermaid
flowchart TD
    A[削除リクエスト] --> B{権限チェック}
    B -->|権限なし| C[アクセス拒否]
    B -->|権限あり| D{即時削除要求?}
    D -->|Yes| E{管理者権限?}
    E -->|Yes| F[即時削除実行]
    E -->|No| C
    D -->|No| G[削除スケジュール設定]
    G --> H[通知メール送信]
    H --> I[猶予期間待機]
    I --> J[バックグラウンド削除]
    F --> J
    J --> K[プロジェクト削除]
    K --> L[サブグループ削除]
    L --> M[関連データ削除]
    M --> N[グループ削除完了]
    N --> O[イベント発行]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 削除権限 | グループオーナーまたは管理者のみ削除可能 | 常時 |
| BR-02 | 削除猶予期間 | 削除スケジュール設定後、一定期間の猶予期間が設けられる | 通常削除時 |
| BR-03 | 即時削除制限 | 即時削除は管理者のみ、かつ設定で許可されている場合のみ | 即時削除要求時 |
| BR-04 | カスケード削除 | グループ削除時、配下のプロジェクト・サブグループも削除 | 常時 |
| BR-05 | コンテナレジストリ制限 | コンテナイメージを含むグループは名前変更不可 | 削除スケジュール設定時 |

### 計算ロジック

該当なし

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 削除スケジュール | group_deletion_schedules | INSERT | 削除スケジュール作成 |
| グループ状態更新 | namespaces | UPDATE | deleted_at, path等の更新 |
| グループ削除 | namespaces | DELETE | グループレコード削除 |
| プロジェクト削除 | projects | DELETE | 配下プロジェクト削除 |
| メンバー削除 | members | DELETE | グループメンバー削除 |

### テーブル別操作詳細

#### namespaces

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | path | 元のpath + 削除サフィックス | 削除スケジュール時 |
| UPDATE | name | 元のname + 削除サフィックス | 削除スケジュール時 |
| UPDATE | deleted_at | 現在時刻 | 削除開始時 |
| DELETE | id | 対象グループID | 完全削除時 |

#### group_deletion_schedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | group_id | 対象グループID | - |
| INSERT | marked_for_deletion_on | 現在日時 | - |
| INSERT | deleting_user_id | 操作ユーザーID | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | 削除権限がない場合 | アクセス拒否画面を表示 |
| - | ブロックエラー | ユーザーがブロックされている場合 | エラーメッセージを表示 |
| - | 削除失敗 | プロジェクト削除に失敗した場合 | 削除を再スケジュール |

### リトライ仕様

- バックグラウンド削除中にエラーが発生した場合、削除は再スケジュールされる
- `reschedule_deletion`メソッドにより、deleted_atがnilに戻され、再度削除ワーカーが実行される

## トランザクション仕様

- 削除スケジュール設定はトランザクション内で実行
- グループ削除処理全体はトランザクション内で実行され、失敗時はロールバック
- プロジェクト削除は個別にトランザクション管理

## パフォーマンス要件

- 大量のプロジェクト・サブグループを含むグループの削除は非同期で実行
- 削除処理はSidekiqワーカーにより順次処理

## セキュリティ考慮事項

- 削除権限の厳格なチェック（authorize_remove_group!）
- ブロックされたユーザーによる削除を防止
- 削除操作の監査ログ記録
- GroupDeletedEventによる削除の追跡

## 備考

- 削除されたグループは猶予期間内であれば復元可能（RestoreService）
- 管理者設定により即時削除の可否を制御可能

---

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

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

### 推奨読解順序

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

グループと削除スケジュールの関連を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | group.rb | `app/models/group.rb` | Groupモデルの基本構造、deletion_scheduleとの関連 |
| 1-2 | group_deletion_schedule.rb | `app/models/group_deletion_schedule.rb` | 削除スケジュールのデータ構造 |

**読解のコツ**: Groupモデルは非常に大きいため、まずは`has_one :deletion_schedule`の関連と`deleting_user`, `marked_for_deletion_on`のデリゲートに注目する。

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

コントローラーの削除処理エントリーポイントを確認する。

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

**主要処理フロー**:
1. **180-188行目**: 即時削除の判定と権限チェック
2. **190行目**: MarkForDeletionServiceの呼び出し
3. **399-413行目**: destroy_immediatelyメソッドによる即時削除

#### Step 3: 削除スケジュールサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mark_for_deletion_service.rb | `app/services/groups/mark_for_deletion_service.rb` | 削除スケジュール設定のロジック |

**主要処理フロー**:
- **22-43行目**: execute_deletionメソッドでトランザクション内での削除スケジュール作成
- **45-56行目**: グループ名・パスの変更処理
- **69-77行目**: 削除スケジュールの保存

#### Step 4: 完全削除サービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | destroy_service.rb | `app/services/groups/destroy_service.rb` | 実際の削除処理ロジック |

**主要処理フロー**:
- **7-11行目**: async_executeで非同期削除のエンキュー
- **15-66行目**: executeメソッドで同期削除処理
- **19-24行目**: プロジェクトの反復削除
- **29-32行目**: サブグループの再帰的削除
- **137-145行目**: GroupDeletedEventの発行

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

```
GroupsController#destroy
    │
    ├─ authorize_remove_group! (権限チェック)
    │
    ├─ [通常フロー] Groups::MarkForDeletionService#execute
    │      ├─ rename_group_for_deletion! (グループ名変更)
    │      ├─ save_deletion_schedule! (スケジュール保存)
    │      └─ NotificationService#group_scheduled_for_deletion
    │
    └─ [即時削除] Groups::DestroyService#async_execute
           └─ GroupDestroyWorker#perform
                  └─ Groups::DestroyService#execute
                         ├─ Projects::DestroyService#execute (各プロジェクト)
                         ├─ Groups::DestroyService#execute (各サブグループ、再帰)
                         ├─ Mattermost::Team#destroy
                         ├─ group.destroy
                         └─ Gitlab::EventStore.publish(GroupDeletedEvent)
```

### データフロー図

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

グループID ───▶ GroupsController ───▶ 削除結果メッセージ
                     │
                     ▼
              MarkForDeletionService
                     │
                     ▼
              group_deletion_schedules ───▶ 削除スケジュール
                     │
                     ▼ (猶予期間後)
              GroupDestroyWorker
                     │
                     ▼
              DestroyService ───▶ 監査ログ
                     │
                     ▼
              namespaces (DELETE) ───▶ GroupDeletedEvent
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| groups_controller.rb | `app/controllers/groups_controller.rb` | コントローラー | リクエスト処理のエントリーポイント |
| mark_for_deletion_service.rb | `app/services/groups/mark_for_deletion_service.rb` | サービス | 削除スケジュール設定 |
| destroy_service.rb | `app/services/groups/destroy_service.rb` | サービス | 実際の削除処理 |
| restore_service.rb | `app/services/groups/restore_service.rb` | サービス | 削除取り消し処理 |
| group.rb | `app/models/group.rb` | モデル | グループエンティティ |
| group_deletion_schedule.rb | `app/models/group_deletion_schedule.rb` | モデル | 削除スケジュールエンティティ |
| group_destroy_worker.rb | `app/workers/group_destroy_worker.rb` | ワーカー | 非同期削除ジョブ |
