# 機能設計書 7-プロジェクトフォーク

## 概要

本ドキュメントは、GitLabにおけるプロジェクトフォーク機能の詳細設計を記述する。この機能は、既存のプロジェクトをコピーして新しいプロジェクトを作成し、フォークネットワークで元プロジェクトとの関係を維持する機能である。

### 本機能の処理概要

プロジェクトフォーク機能は、オープンソース開発やコードレビューにおいて、他者のプロジェクトをコピーして独自の変更を加えるための基盤を提供する。

**業務上の目的・背景**：オープンソースプロジェクトへの貢献、実験的な機能開発、プロジェクトのカスタマイズなどのために、元のプロジェクトを変更せずにコピーを作成する必要がある。フォーク機能により、開発者は自分の名前空間でコードを自由に変更し、マージリクエストを通じて元プロジェクトに貢献できる。

**機能の利用シーン**：
- オープンソースプロジェクトへの貢献準備時
- 既存プロジェクトをベースに新規開発を行う時
- プロジェクトの実験的な変更を行う時
- 組織内でテンプレートプロジェクトを複製する時

**主要な処理内容**：
1. フォーク先名前空間の選択と検証
2. フォーク権限の確認
3. 新規プロジェクトの作成（CreateServiceを利用）
4. フォークネットワークへの登録
5. プロジェクト機能設定の引き継ぎ
6. リポジトリのコピー（非同期インポート）
7. フォークカウントの更新

**関連システム・外部連携**：
- Gitaly（リポジトリ複製）
- Object Storage（オブジェクトプール）

**権限による制御**：
- 元プロジェクトでfork_project権限が必要
- フォーク先名前空間でプロジェクト作成権限が必要
- 管理者は全プロジェクトをフォーク可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | フォーク一覧 | 主画面 | フォーク一覧表示 |
| 8 | フォーク作成 | 主画面 | フォーク先選択・作成 |

## 機能種別

CRUD操作（Create）/ データ連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| namespace_key | Integer | Yes | フォーク先名前空間ID | 存在確認、権限確認 |
| path | String | No | プロジェクトパス | 一意性確認 |
| name | String | No | プロジェクト名 | - |
| description | String | No | 説明 | - |
| visibility | String | No | 可視性レベル | public/internal/private |
| branches | String | No | 特定ブランチのみフォーク | ブランチ存在確認 |

### 入力データソース

- 画面入力（Web UI - Fork画面）
- API リクエスト（REST API / GraphQL）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| project | Project | 作成されたプロジェクト |
| message | String | エラーメッセージ（失敗時） |

### 出力先

- データベース（projects, fork_network_members等）
- ファイルシステム（リポジトリ）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受付（ForksController#create）
   └─ パラメータ確認

2. 既存フォーク確認
   └─ 同一パスのフォーク済みプロジェクトがあるか確認

3. 権限チェック
   ├─ フォーク元プロジェクトでの権限確認
   └─ フォーク先名前空間での権限確認

4. フォーク処理（ForkService#execute）
   ├─ 既存プロジェクトへのリンク
   │    └─ link_existing_project
   └─ 新規プロジェクト作成
        └─ fork_new_project

5. 新規プロジェクト作成詳細
   ├─ CreateServiceによるプロジェクト作成
   ├─ フォークネットワーク設定
   ├─ プロジェクト機能設定の継承
   └─ 可視性レベルの調整

6. 後処理
   ├─ フォークカウント更新
   └─ 監査イベント記録

7. レスポンス
   ├─ インポート中 → インポートページへリダイレクト
   └─ 完了 → プロジェクトページへリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[開始: fork リクエスト] --> B{既にフォーク済み?}
    B -->|Yes| C[既存プロジェクトを返却]
    B -->|No| D{フォーク権限あり?}
    D -->|No| E[エラー: 権限なし]
    D -->|Yes| F{フォーク先権限あり?}
    F -->|No| G[エラー: フォーク先権限なし]
    F -->|Yes| H[ForkService#execute]
    H --> I{既存プロジェクトリンク?}
    I -->|Yes| J[link_existing_project]
    I -->|No| K[fork_new_project]
    J --> L{リンク成功?}
    L -->|No| M[エラー返却]
    L -->|Yes| N[後処理]
    K --> O[CreateService呼び出し]
    O --> P{作成成功?}
    P -->|No| M
    P -->|Yes| Q[機能設定継承]
    Q --> N
    N --> R[フォークカウント更新]
    R --> S{インポート中?}
    S -->|Yes| T[インポートページへ]
    S -->|No| U[プロジェクトページへ]

    E --> V[終了]
    G --> V
    M --> V
    T --> V
    U --> V
    C --> V
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 権限必須 | フォーク元・先両方で権限が必要 | 常時 |
| BR-002 | 可視性制限 | フォーク先の可視性を超えない | 常時 |
| BR-003 | 自己フォーク禁止 | 同一プロジェクトへのリンク不可 | link_existing_project時 |
| BR-004 | 組織一致 | フォーク元と同一組織に属する必要 | link_existing_project時 |
| BR-005 | 重複フォーク禁止 | 既にフォーク済みのプロジェクトはリンク不可 | link_existing_project時 |

### 計算ロジック

可視性レベル調整：
```ruby
# 元プロジェクトとフォーク先名前空間の可視性の小さい方
target_level = [@project.visibility_level, target_namespace.visibility_level].min

# さらにパラメータ指定があればその制限も適用
target_level = [target_level, params[:visibility]].min if params[:visibility]

# 許可された最も近いレベルに調整
Gitlab::VisibilityLevel.closest_allowed_level(target_level)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロジェクト作成 | projects | INSERT | フォークプロジェクト作成 |
| フォークネットワーク | fork_networks | INSERT | 新規ネットワーク作成（ルートの場合） |
| フォークメンバー | fork_network_members | INSERT | フォーク関係登録 |
| メンバー追加 | members | INSERT | オーナー追加 |
| プロジェクト機能 | project_features | INSERT/UPDATE | 機能設定継承 |

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

#### fork_network_members

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | fork_network_id | fork_network.id | ネットワークID |
| INSERT | project_id | new_project.id | フォークプロジェクトID |
| INSERT | forked_from_project_id | source_project.id | フォーク元ID |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E001 | 権限エラー | フォーク権限なし | 権限を取得 |
| E002 | 権限エラー | フォーク先権限なし | フォーク先を変更 |
| E003 | 重複エラー | 既にフォーク済み | 既存フォークを使用 |
| E004 | 自己フォーク | 自己へのリンク | 別プロジェクトを選択 |
| E005 | 組織不一致 | 組織が異なる | 同一組織のプロジェクトを選択 |

### リトライ仕様

- プロジェクト作成失敗時はロールバック
- リポジトリインポートは非同期で再試行可能

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

- プロジェクト作成とフォークネットワーク登録は同一トランザクション内
- リポジトリ複製は非同期インポートとして別途実行

## パフォーマンス要件

- フォーク作成自体は数秒以内に完了
- リポジトリ複製はサイズに応じて非同期実行
- 低緊急度（urgency: :low）として設定（index）

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

- フォーク元・先両方での権限チェック必須
- 可視性レベルの適切な調整
- 監査ログへの記録（EE）

## 備考

- フォーク後はマージリクエストを通じて元プロジェクトに貢献可能
- オブジェクトプールを利用してストレージ効率化
- 特定ブランチのみのフォークも可能

---

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

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

### 推奨読解順序

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

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

**主要処理フロー**:
1. **68-88行目**: createアクションの定義
2. **108-112行目**: fork_serviceの初期化
3. **130-132行目**: authorize_fork_namespace!の権限チェック

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

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

**主要処理フロー**:
- **5-11行目**: executeメソッドのエントリーポイント
- **36-56行目**: link_existing_projectで既存プロジェクトへのリンク
- **58-70行目**: fork_new_projectで新規プロジェクト作成
- **72-112行目**: new_fork_paramsでフォークパラメータ構築
- **169-174行目**: target_visibility_levelで可視性調整

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

```
Projects::ForksController#create
    │
    ├─ fork_namespace.projects.find_by(path:) [既存フォーク確認]
    │
    └─ Projects::ForkService#execute
           │
           ├─ [fork_to_project指定時]
           │      └─ link_existing_project
           │             ├─ forked? チェック
           │             ├─ self_fork チェック
           │             ├─ organization_id チェック
           │             ├─ build_fork_network_member
           │             └─ link_fork_network
           │
           └─ [新規フォーク時]
                  └─ fork_new_project
                         │
                         ├─ new_fork_params構築
                         │      ├─ forked_from_project設定
                         │      ├─ visibility_level調整
                         │      ├─ namespace_id設定
                         │      └─ relations_block設定
                         │
                         ├─ CreateService#execute
                         │
                         └─ project_feature.update!
                                └─ 機能設定継承
```

### データフロー図

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

フォークボタン          ForksController#create
クリック                      │
         │                   │
         ▼                   ▼
              ┌───────────────────────────────┐
              │ 既存フォーク確認               │
              │ namespace.projects.find_by    │
              └─────────────┬─────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐
              │ ForkService#execute           │
              │                               │
              │ 新規 → fork_new_project       │
              │ 既存 → link_existing_project  │
              └─────────────┬─────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐      ┌─────────────────────┐
              │ CreateService#execute         │ ───▶ │ projects            │
              │ (新規フォーク時)              │      │ fork_network_members│
              └─────────────┬─────────────────┘      └─────────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐
              │ after_fork                    │
              │ ├─ refresh_forks_count        │
              │ └─ stream_audit_event         │
              └─────────────┬─────────────────┘
                            │
                            ▼
              ┌───────────────────────────────┐
              │ リダイレクト                   │
              │ インポート中 → import_path    │
              │ 完了 → project_path           │
              └───────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| forks_controller.rb | `app/controllers/projects/forks_controller.rb` | ソース | コントローラー |
| fork_service.rb | `app/services/projects/fork_service.rb` | ソース | フォークビジネスロジック |
| create_service.rb | `app/services/projects/create_service.rb` | ソース | プロジェクト作成 |
| fork_network.rb | `app/models/fork_network.rb` | ソース | フォークネットワークモデル |
| fork_network_member.rb | `app/models/fork_network_member.rb` | ソース | フォーク関係モデル |
| fork_targets_finder.rb | `app/finders/fork_targets_finder.rb` | ソース | フォーク先候補検索 |
