# 機能設計書 3-プロジェクト削除

## 概要

本ドキュメントは、GitLabにおけるプロジェクト削除機能の詳細設計を記述する。この機能は、プロジェクトとそれに関連するすべてのデータ（リポジトリ、イシュー、マージリクエスト、CI/CDパイプライン、コンテナレジストリ等）を削除するための機能である。

### 本機能の処理概要

プロジェクト削除機能は、プロジェクトのライフサイクル終了時に、関連するすべてのリソースを適切にクリーンアップするための包括的な機能を提供する。

**業務上の目的・背景**：不要になったプロジェクトを削除し、ストレージリソースを解放する必要がある。また、セキュリティやコンプライアンスの観点から、不要なデータを適切に削除することが求められる。削除は重大な操作であるため、猶予期間を設けた「ソフト削除」と即座に完全削除する「ハード削除」の2段階が用意されている。

**機能の利用シーン**：
- プロジェクトが不要になり、完全に削除したい時
- 組織再編によりプロジェクトを整理する時
- テスト用プロジェクトをクリーンアップする時
- コンプライアンス要件によりデータ削除が必要な時

**主要な処理内容**：
1. 削除権限の確認（Owner権限が必要）
2. 削除マーク付与（ソフト削除、猶予期間あり）
3. 猶予期間経過後または即時削除要求時の完全削除
4. リポジトリストレージ移動中でないことの確認
5. CIパイプラインの中止
6. フォーク関係の解除
7. コンテナレジストリタグの削除
8. 関連リソース（スニペット、イベント、Webhook等）の削除
9. Gitリポジトリ（メイン、Wiki、デザイン）の削除
10. プロジェクトボットユーザーの削除
11. システムフック実行

**関連システム・外部連携**：
- Gitaly（リポジトリ削除）
- Container Registry（イメージ削除）
- Sidekiq（非同期削除処理）
- システムフック（削除イベント通知）

**権限による制御**：
- プロジェクト削除にはOwner権限が必要
- 即時削除（猶予期間スキップ）はインスタンス設定で許可されたユーザーのみ
- 管理者は全プロジェクトを削除可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | プロジェクト編集 | 主画面 | プロジェクト削除オプションの表示 |

## 機能種別

CRUD操作（Delete）/ バッチ処理 / データ連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| permanently_delete | Boolean | No | 即時完全削除フラグ | 管理者設定で許可時のみ有効 |

### 入力データソース

- 画面入力（Web UI - Settings > General > Advanced）
- API リクエスト（REST API / GraphQL）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Boolean | 処理結果（true: 成功、false: 失敗） |
| message | String | 処理結果メッセージ |

### 出力先

- データベース（各種テーブルからのレコード削除）
- Gitリポジトリ（Gitalyサーバー上のリポジトリ削除）
- Container Registry（イメージ削除）
- ファイルシステム（アップロードファイル削除）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受付（ProjectsController#destroy）
   └─ パラメータ確認とパーミッションチェック

2. 即時削除判定
   ├─ permanently_delete=true かつ 管理者許可あり → 即時削除
   └─ それ以外 → ソフト削除（MarkForDeletionService）

3. ソフト削除の場合（MarkForDeletionService）
   ├─ pending_delete フラグ設定
   └─ 削除予定日の記録（猶予期間後）

4. 完全削除の場合（DestroyService#execute）
   ├─ 削除進行中マーク設定
   ├─ リポジトリストレージ移動チェック
   ├─ キャッシュフラッシュ
   ├─ CIパイプライン中止
   ├─ フォーク関係解除
   └─ attempt_destroy 実行

5. attempt_destroy 処理
   ├─ コンテナレジストリタグ削除
   ├─ プールリポジトリからの離脱
   └─ destroy_project_related_records

6. destroy_project_related_records
   ├─ スニペット削除
   ├─ リポジトリ削除（メイン、Wiki、デザイン）
   ├─ イベント削除
   ├─ Webhook削除
   ├─ プロジェクトボット削除
   ├─ CIレコード削除（パイプライン、アーティファクト等）
   ├─ デプロイメント削除
   ├─ マージリクエストDiff削除
   └─ project.destroy!

7. 完了処理
   ├─ システムフック実行
   ├─ 削除イベント発行
   └─ 個人プロジェクトカウント更新
```

### フローチャート

```mermaid
flowchart TD
    A[開始: destroy リクエスト] --> B{権限確認}
    B -->|No| C[権限エラー]
    B -->|Yes| D{即時削除?}
    D -->|No| E[MarkForDeletionService]
    E --> F[pending_delete設定]
    F --> G[削除予定通知]
    D -->|Yes| H{管理者許可あり?}
    H -->|No| I[権限エラー]
    H -->|Yes| J[DestroyService#async_execute]
    J --> K[ProjectDestroyWorker]
    K --> L[DestroyService#execute]
    L --> M{ストレージ移動中?}
    M -->|Yes| N[エラー: 移動中]
    M -->|No| O[キャッシュフラッシュ]
    O --> P[CIパイプライン中止]
    P --> Q[フォーク関係解除]
    Q --> R{CRタグ削除成功?}
    R -->|No| S[エラー: CR削除失敗]
    R -->|Yes| T[関連レコード削除]
    T --> U[リポジトリ削除]
    U --> V[project.destroy!]
    V --> W[システムフック実行]
    W --> X[イベント発行]
    X --> Y[成功]

    C --> Z[終了]
    G --> Z
    I --> Z
    N --> Z
    S --> Z
    Y --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 削除権限 | プロジェクト削除にはOwner権限が必要 | 常時 |
| BR-002 | ストレージ移動制限 | リポジトリストレージ移動中は削除不可 | ストレージ移動スケジュール存在時 |
| BR-003 | スニペット移動制限 | スニペットのストレージ移動中は削除不可 | スニペット移動スケジュール存在時 |
| BR-004 | ソフト削除猶予期間 | 通常削除は猶予期間後に完全削除 | インスタンス設定による |
| BR-005 | 即時削除制限 | 即時削除は管理者設定で許可されたユーザーのみ | permanently_delete=true時 |

### 計算ロジック

削除予定日：
```ruby
# 猶予期間はインスタンス設定による（デフォルト7日など）
deletion_scheduled_date = Date.today + deletion_adjourned_period
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロジェクト削除 | projects | DELETE | プロジェクトレコード削除 |
| CI関連削除 | ci_pipelines, ci_builds等 | DELETE | CI/CDデータ削除 |
| MR関連削除 | merge_requests, merge_request_diffs等 | DELETE | MRデータ削除 |
| イシュー関連削除 | issues, notes等 | DELETE | イシューデータ削除 |
| イベント削除 | events | DELETE | イベントログ削除 |
| Webhook削除 | web_hooks | DELETE | Webhook設定削除 |
| メンバー削除 | members | DELETE | メンバーシップ削除 |
| デプロイメント削除 | deployments | DELETE | デプロイ履歴削除 |
| 環境削除 | environments | DELETE | 環境定義削除 |

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

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | pending_delete | true | ソフト削除時 |
| UPDATE | marked_for_deletion_at | 現在日時 | ソフト削除時 |
| DELETE | - | WHERE id = project_id | 完全削除時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E001 | 権限エラー | 削除権限なし | Owner権限を取得 |
| E002 | ストレージ移動エラー | リポジトリストレージ移動中 | 移動完了後に再実行 |
| E003 | スニペット移動エラー | スニペットストレージ移動中 | 移動完了後に再実行 |
| E004 | CRタグ削除エラー | コンテナレジストリタグ削除失敗 | 手動でタグ削除後に再実行 |
| E005 | リポジトリ削除エラー | Gitリポジトリ削除失敗 | 管理者に連絡 |
| E006 | スニペット削除エラー | スニペット削除失敗 | 管理者に連絡 |
| E007 | Webhook削除エラー | Webhook削除失敗 | 管理者に連絡 |

### リトライ仕様

- 削除処理失敗時はpending_deleteフラグを維持し、delete_errorにメッセージを記録
- Sidekiq Workerによる自動リトライあり
- エラー後は可視性レベルを名前空間に合わせて調整（制限が厳しくなった場合）

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

- プロジェクト削除全体がトランザクション内で実行
- 外部リソース（Gitaly、Container Registry）は個別に処理
- 失敗時はロールバックとエラー記録

## パフォーマンス要件

- 削除処理は非同期（Sidekiq Worker）で実行
- 大規模プロジェクトの削除は数分〜数十分かかる可能性
- CI/CDレコードはバッチ削除（100件単位）

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

- Owner権限チェック必須
- 即時削除の管理者許可確認
- 削除操作の監査ログ記録
- コンテナレジストリ保護ルールの確認

## 備考

- 削除されたプロジェクトは復元不可（完全削除後）
- ソフト削除中のプロジェクトは復元可能（RestoreService）
- フォーク元プロジェクト削除時はフォーク関係が解除される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | projects_controller.rb | `app/controllers/projects_controller.rb` | destroyアクションの実装 |

**主要処理フロー**:
1. **201-221行目**: destroyアクションの定義
2. **202行目**: 権限チェック（can?(:remove_project, @project)）
3. **204-210行目**: 即時削除判定と処理分岐
4. **212行目**: MarkForDeletionServiceの呼び出し

#### Step 2: ソフト削除ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mark_for_deletion_service.rb | `app/services/projects/mark_for_deletion_service.rb` | ソフト削除の実装 |

#### Step 3: 完全削除ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | destroy_service.rb | `app/services/projects/destroy_service.rb` | 完全削除の中心ロジック |

**主要処理フロー**:
- **11-16行目**: async_execute（非同期実行）
- **18-68行目**: executeメソッドのメイン処理
- **95-103行目**: validate_active_repositories_move!
- **179-186行目**: attempt_destroy
- **192-220行目**: destroy_project_related_records
- **400-411行目**: remove_registry_tags

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

```
ProjectsController#destroy
    │
    ├─ [即時削除パス]
    │      │
    │      └─ Projects::DestroyService#async_execute
    │             │
    │             └─ ProjectDestroyWorker.perform_async
    │                    │
    │                    └─ Projects::DestroyService#execute
    │
    └─ [ソフト削除パス]
           │
           └─ Projects::MarkForDeletionService#execute
                  │
                  └─ project.update(pending_delete: true, ...)

Projects::DestroyService#execute
    │
    ├─ mark_deletion_in_progress
    │
    ├─ validate_active_repositories_move!
    │
    ├─ flush_caches
    │
    ├─ Ci::AbortPipelinesService
    │
    ├─ Projects::UnlinkForkService
    │
    └─ attempt_destroy
           │
           ├─ remove_registry_tags
           │      └─ ContainerRepository::DestroyService
           │
           ├─ project.leave_pool_repository
           │
           └─ destroy_project_related_records
                  │
                  ├─ trash_relation_repositories!
                  │      └─ Snippets::BulkDestroyService
                  │
                  ├─ trash_project_repositories!
                  │      └─ Repositories::DestroyService (×3: main, wiki, design)
                  │
                  ├─ destroy_events!
                  │      └─ Events::DestroyService
                  │
                  ├─ destroy_web_hooks!
                  │      └─ WebHooks::DestroyService
                  │
                  ├─ destroy_project_bots!
                  │      └─ Users::DestroyService
                  │
                  ├─ destroy_ci_records!
                  │      └─ Ci::DestroyPipelineService
                  │
                  ├─ destroy_deployments!
                  │
                  ├─ destroy_mr_diff_relations!
                  │
                  └─ project.destroy!
```

### データフロー図

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

削除リクエスト        ProjectsController#destroy
  │                          │
  ▼                          ▼
              ┌───────────────────────────────┐
              │ 権限チェック                   │
              │ ・Owner権限確認                │
              │ ・即時削除許可確認             │
              └─────────────┬─────────────────┘
                            │
              ┌─────────────┴─────────────────┐
              │                               │
              ▼                               ▼
    ┌─────────────────┐             ┌─────────────────┐
    │ ソフト削除       │             │ 即時削除         │
    │ (pending_delete)│             │ (DestroyService)│
    └────────┬────────┘             └────────┬────────┘
             │                               │
             ▼                               ▼
    削除予定日設定              ┌───────────────────────────┐
             │                  │ 非同期削除処理             │
             │                  │ (ProjectDestroyWorker)    │
             │                  └─────────────┬─────────────┘
             │                                │
             │                                ▼
             │                  ┌───────────────────────────┐
             │                  │ リソース削除               │
             │                  │ ・リポジトリ                │───▶ Gitaly
             │                  │ ・CRイメージ               │───▶ Container Registry
             │                  │ ・DBレコード               │───▶ Database
             │                  │ ・アップロード             │───▶ Storage
             │                  └─────────────┬─────────────┘
             │                                │
             │                                ▼
             │                  ┌───────────────────────────┐
             │                  │ 完了処理                   │
             │                  │ ・システムフック           │───▶ 外部システム
             │                  │ ・イベント発行             │
             │                  └───────────────────────────┘
             │
             ▼
    猶予期間後に完全削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| projects_controller.rb | `app/controllers/projects_controller.rb` | ソース | コントローラー |
| destroy_service.rb | `app/services/projects/destroy_service.rb` | ソース | 完全削除ロジック |
| mark_for_deletion_service.rb | `app/services/projects/mark_for_deletion_service.rb` | ソース | ソフト削除ロジック |
| restore_service.rb | `app/services/projects/restore_service.rb` | ソース | 削除取り消しロジック |
| project_destroy_worker.rb | `app/workers/project_destroy_worker.rb` | ソース | 非同期削除Worker |
| unlink_fork_service.rb | `app/services/projects/unlink_fork_service.rb` | ソース | フォーク関係解除 |
| destroy_pipeline_service.rb | `app/services/ci/destroy_pipeline_service.rb` | ソース | パイプライン削除 |
| bulk_destroy_service.rb | `app/services/snippets/bulk_destroy_service.rb` | ソース | スニペット一括削除 |
