# 機能設計書 4-プロジェクトアーカイブ

## 概要

本ドキュメントは、GitLabにおけるプロジェクトアーカイブ機能の詳細設計を記述する。この機能は、プロジェクトを読み取り専用状態に設定し、新たな変更を防止するための機能である。アンアーカイブにより元の状態に戻すことも可能。

### 本機能の処理概要

プロジェクトアーカイブ機能は、プロジェクトを保存・保管状態にするための機能を提供する。アーカイブされたプロジェクトは閲覧可能だが、変更は不可となる。

**業務上の目的・背景**：完了したプロジェクトや一時的に凍結するプロジェクトについて、誤った変更を防止しつつ履歴を保持する必要がある。削除ではなく、参照可能な状態で保存したい場合に使用する。また、ストレージ使用量の削減や、プロジェクト一覧の整理にも役立つ。

**機能の利用シーン**：
- プロジェクトが完了し、今後の変更が不要な時
- 一時的にプロジェクトの変更を凍結したい時
- 古いプロジェクトを整理しつつ、履歴は残したい時
- リソース使用量を最適化したい時

**主要な処理内容**：
1. アーカイブ権限の確認
2. 既にアーカイブ済みでないことの確認
3. 先祖がアーカイブ済みでないことの確認
4. 削除予定でないことの確認
5. archivedフラグの設定
6. フォーク関係の解除
7. システムフック実行
8. アーカイブイベントの発行

**関連システム・外部連携**：
- システムフック（アーカイブイベント通知）
- フォークネットワーク（フォーク関係解除）

**権限による制御**：
- プロジェクトアーカイブにはarchive_project権限（通常Owner以上）が必要
- 管理者は全プロジェクトをアーカイブ可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | プロジェクト編集 | 主画面 | アーカイブ・アンアーカイブ処理 |
| 24 | プロジェクト詳細 | 結果表示画面 | アーカイブ状態の表示 |

## 機能種別

CRUD操作（Update）/ 状態管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | アーカイブ/アンアーカイブはパラメータ不要 | - |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | ServiceResponse | 処理結果オブジェクト |
| result.success? | Boolean | 成功/失敗 |
| result.message | String | エラーメッセージ（失敗時） |

### 出力先

- データベース（projectsテーブル）
- 画面リダイレクト（プロジェクトページ）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受付（ProjectsController#archive）
   └─ 認証・権限確認

2. サービス呼び出し（Projects::ArchiveService#execute）
   └─ ビジネスロジック実行

3. 事前チェック
   ├─ アーカイブ権限確認
   ├─ 既にアーカイブ済みでないか確認
   ├─ 先祖がアーカイブ済みでないか確認
   └─ 削除予定でないか確認

4. アーカイブ処理（トランザクション内）
   ├─ 状態遷移（archive）
   └─ archivedフラグ更新

5. 後処理（after_archive）
   ├─ システムフック実行
   ├─ アーカイブイベント発行
   └─ フォーク関係解除

6. レスポンス返却
   └─ プロジェクトページへリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[開始: archive リクエスト] --> B{権限確認}
    B -->|No| C[NotAuthorizedError]
    B -->|Yes| D{既にアーカイブ済み?}
    D -->|Yes| E[AlreadyArchivedError]
    D -->|No| F{先祖がアーカイブ済み?}
    F -->|Yes| G[AncestorAlreadyArchivedError]
    F -->|No| H{削除予定?}
    H -->|Yes| I[ScheduledDeletionError]
    H -->|No| J[トランザクション開始]
    J --> K[archive状態遷移]
    K --> L[archived = true]
    L --> M{更新成功?}
    M -->|No| N[ArchivingFailedError]
    M -->|Yes| O[システムフック実行]
    O --> P[イベント発行]
    P --> Q[フォーク関係解除]
    Q --> R[成功レスポンス]

    C --> S[終了]
    E --> S
    G --> S
    I --> S
    N --> S
    R --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | アーカイブ権限 | archive_project権限が必要 | 常時 |
| BR-002 | 重複アーカイブ防止 | 既にアーカイブ済みのプロジェクトはアーカイブ不可 | self_archived?がtrue時 |
| BR-003 | 先祖アーカイブ制限 | 親グループがアーカイブ済みの場合はアーカイブ不可 | ancestors_archived?がtrue時 |
| BR-004 | 削除予定制限 | 削除予定のプロジェクトはアーカイブ不可 | scheduled_for_deletion_in_hierarchy_chain?がtrue時 |
| BR-005 | フォーク解除 | アーカイブ時にフォーク関係が解除される | アーカイブ成功時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| アーカイブ | projects | UPDATE | archivedフラグ更新 |
| フォーク解除 | fork_network_members | DELETE | フォーク関係解除 |

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

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | archived | true | アーカイブ時 |
| UPDATE | archived | false | アンアーカイブ時 |
| UPDATE | updated_at | 現在時刻 | 更新日時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NotAuthorizedError | 権限エラー | アーカイブ権限なし | Owner権限を取得 |
| AlreadyArchivedError | 状態エラー | 既にアーカイブ済み | 操作不要または先にアンアーカイブ |
| AncestorAlreadyArchivedError | 階層エラー | 先祖がアーカイブ済み | 先祖のアンアーカイブが必要 |
| ScheduledDeletionError | 状態エラー | 削除予定 | 削除予定を解除 |
| ArchivingFailedError | 処理エラー | アーカイブ処理失敗 | 再試行または管理者に連絡 |

### リトライ仕様

- 通常のアーカイブ処理でリトライは不要
- フォーク解除失敗時も主処理は成功として扱われる

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

- アーカイブ処理はトランザクション内で実行
- 状態遷移とフラグ更新が一括コミット
- 後処理（システムフック、フォーク解除）はトランザクション外

## パフォーマンス要件

- アーカイブ処理は1秒以内に完了
- フォーク解除は同期処理

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

- archive_project権限チェック必須
- 監査ログへの記録

## 備考

- アーカイブされたプロジェクトはUI上で「Archived」ラベルが表示される
- アーカイブ中のプロジェクトではCI/CDパイプラインは実行されない
- アンアーカイブは同様のプロセスで逆の処理を行う

---

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

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

### 推奨読解順序

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

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

**主要処理フロー**:
1. **248-254行目**: archiveアクションの定義
2. **256-262行目**: unarchiveアクションの定義

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | archive_service.rb | `app/services/projects/archive_service.rb` | アーカイブの中心ロジック |

**主要処理フロー**:
- **7-21行目**: エラーレスポンス定義
- **23-37行目**: executeメソッドのメイン処理
- **42-45行目**: archive_projectでのトランザクション処理
- **48-53行目**: after_archiveでの後処理

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

```
ProjectsController#archive
    │
    └─ Projects::ArchiveService#execute
           │
           ├─ can?(:archive_project, project) チェック
           │
           ├─ project.self_archived? チェック
           │
           ├─ project.ancestors_archived? チェック
           │
           ├─ project.scheduled_for_deletion_in_hierarchy_chain? チェック
           │
           ├─ archive_project (トランザクション)
           │      │
           │      ├─ project.archive(transition_user:)
           │      │
           │      └─ project.update(archived: true)
           │
           └─ after_archive
                  │
                  ├─ system_hook_service.execute_hooks_for(:update)
                  │
                  ├─ publish_events
                  │
                  └─ UnlinkForkService.new.execute
```

### データフロー図

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

アーカイブリクエスト  ProjectsController#archive
         │                          │
         ▼                          ▼
              ┌───────────────────────────────┐
              │ 権限・状態チェック              │
              │ ・archive_project権限          │
              │ ・既にアーカイブ済み?           │
              │ ・先祖がアーカイブ済み?         │
              │ ・削除予定?                    │
              └─────────────┬─────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐      ┌─────────────────┐
              │ トランザクション処理            │ ───▶ │ projectsテーブル │
              │ ・状態遷移                     │      │ archived = true │
              │ ・archivedフラグ更新           │      └─────────────────┘
              └─────────────┬─────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐
              │ 後処理                         │
              │ ・システムフック実行            │───▶ 外部システム通知
              │ ・イベント発行                 │
              │ ・フォーク関係解除             │───▶ fork_network_members削除
              └───────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| projects_controller.rb | `app/controllers/projects_controller.rb` | ソース | コントローラー |
| archive_service.rb | `app/services/projects/archive_service.rb` | ソース | アーカイブロジック |
| unarchive_service.rb | `app/services/projects/unarchive_service.rb` | ソース | アンアーカイブロジック |
| archive_events.rb | `app/services/projects/archive_events.rb` | ソース | イベント発行concern |
| unlink_fork_service.rb | `app/services/projects/unlink_fork_service.rb` | ソース | フォーク解除ロジック |
