# 機能設計書 5-プロジェクト移行

## 概要

本ドキュメントは、GitLabにおけるプロジェクト移行（Transfer）機能の詳細設計を記述する。この機能は、プロジェクトを現在の名前空間（ユーザー個人またはグループ）から別の名前空間に移動するための機能である。

### 本機能の処理概要

プロジェクト移行機能は、組織再編やプロジェクト整理のために、プロジェクトの所属先を変更するための包括的な機能を提供する。

**業務上の目的・背景**：組織変更、チーム再編、プロジェクト整理などの理由で、プロジェクトを別のグループや個人名前空間に移動する必要がある。この機能により、プロジェクトのデータを維持したまま、所属先を変更できる。

**機能の利用シーン**：
- 組織再編によりプロジェクトを別グループに移動する時
- 個人プロジェクトをグループに移管する時
- グループプロジェクトを個人名前空間に移動する時
- プロジェクト階層を整理する時

**主要な処理内容**：
1. 移行権限の確認（元・先の両方で権限必要）
2. 移行先に同名/同パスのプロジェクトがないことの確認
3. コンテナレジストリタグ存在時の移行可否判定
4. NPMパッケージスコープの検証
5. 名前空間とプロジェクトの関連付け変更
6. 可視性レベルの調整
7. 共有ランナー設定の調整
8. ラベル・マイルストーンの移行
9. アップロードファイルの移動
10. Container Registry パスの変更
11. インテグレーション設定の再適用
12. 権限の再計算

**関連システム・外部連携**：
- Container Registry（パス変更）
- Gitaly（リポジトリパス更新）
- システムフック（移行イベント通知）

**権限による制御**：
- 元プロジェクトでchange_namespace権限が必要
- 移行先名前空間でtransfer_projects権限が必要
- 管理者は全プロジェクトを移行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | プロジェクト編集 | 主画面 | 名前空間移動オプション |

## 機能種別

CRUD操作（Update）/ データ連携 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| new_namespace_id | Integer | Yes | 移行先名前空間ID | 存在する名前空間、権限あり |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

- データベース（projectsテーブル、routes等）
- ファイルシステム（アップロードファイル移動）
- Container Registry（パス変更）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受付（ProjectsController#transfer）
   └─ パラメータ確認と権限チェック

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

3. 事前チェック
   ├─ 移行先名前空間の存在確認
   ├─ 同一名前空間でないことの確認
   ├─ 元プロジェクトでの権限確認
   ├─ 移行先での権限確認
   └─ 重複プロジェクトチェック

4. Container Registry チェック
   ├─ CRタグ存在確認
   ├─ 同一ルート名前空間確認
   └─ ドライラン実行

5. NPMパッケージチェック
   └─ スコープ付きパッケージの検証

6. トランスファー処理（トランザクション内）
   ├─ キャッシュ期限切れ
   ├─ 名前空間・可視性更新
   ├─ 共有ランナー設定調整
   ├─ 移行通知送信
   ├─ ラベル・マイルストーン移行
   ├─ アップロード移動
   ├─ Container Registry パス更新
   ├─ インテグレーション再適用
   ├─ リポジトリ設定更新
   ├─ イシュー連絡先削除
   └─ システムフック実行

7. 後処理
   ├─ 有料機能の削除
   ├─ ペンディングビルド更新
   ├─ オーナーメンバーシップ確保
   ├─ 個人プロジェクトカウント更新
   └─ 権限再計算

8. レスポンス返却
   └─ 編集画面へリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[開始: transfer リクエスト] --> B{移行先指定?}
    B -->|No| C[エラー: 名前空間未指定]
    B -->|Yes| D{同一名前空間?}
    D -->|Yes| E[エラー: 同一名前空間]
    D -->|No| F{元権限あり?}
    F -->|No| G[エラー: 権限なし]
    F -->|Yes| H{先権限あり?}
    H -->|No| I[エラー: 移行先権限なし]
    H -->|Yes| J{重複チェック}
    J -->|重複| K[エラー: 重複]
    J -->|OK| L{CRタグあり?}
    L -->|Yes| M{CR API対応?}
    M -->|No| N[エラー: CR移行不可]
    M -->|Yes| O{同一ルート?}
    O -->|No| P[エラー: ルート変更不可]
    O -->|Yes| Q[ドライラン]
    Q -->|失敗| R[エラー: ドライラン失敗]
    L -->|No| S[トランスファー処理]
    Q -->|成功| S
    S --> T[後処理]
    T --> U[権限再計算]
    U --> V[成功]

    C --> W[終了]
    E --> W
    G --> W
    I --> W
    K --> W
    N --> W
    P --> W
    R --> W
    V --> W
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 双方権限必要 | 元・先両方で権限が必要 | 常時 |
| BR-002 | 重複禁止 | 移行先に同名/同パスプロジェクトがあると不可 | 常時 |
| BR-003 | CRルート制限 | CRタグあり時、異なるルート名前空間への移行は不可 | CRタグ存在時 |
| BR-004 | NPMスコープ制限 | スコープ付きNPMパッケージがあるとルート変更不可 | NPMパッケージ存在時 |
| BR-005 | 可視性調整 | 移行先の可視性に合わせて調整 | 可視性が異なる場合 |

### 計算ロジック

可視性レベル調整：
```ruby
# 移行先の可視性を超えない
project.visibility_level = to_namespace.visibility_level unless project.visibility_level_allowed_by_namespace?
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 名前空間変更 | projects | UPDATE | namespace_id更新 |
| ルート更新 | routes | UPDATE | パス更新 |
| リダイレクト追加 | redirect_routes | INSERT | 旧パスリダイレクト |
| ラベル移行 | labels | UPDATE | 重複時はマージ |
| マイルストーン移行 | milestones | UPDATE | 重複時はマージ |
| 連絡先削除 | issue_contacts | DELETE | CRMグループ変更時 |
| インテグレーション再作成 | integrations | DELETE/INSERT | デフォルト再適用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E001 | 権限エラー | 元プロジェクトでの権限なし | 権限を取得 |
| E002 | 権限エラー | 移行先での権限なし | 移行先の権限を取得 |
| E003 | 重複エラー | 同名/同パスプロジェクト存在 | 名前/パス変更後に移行 |
| E004 | CRエラー | CRタグありで異なるルートへの移行 | CRタグ削除後に移行 |
| E005 | NPMエラー | スコープ付きNPMパッケージでルート変更 | パッケージ削除後に移行 |

### リトライ仕様

- 移行処理失敗時はロールバック
- 一部処理（CR移行等）失敗時は手動リトライ必要

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

- トランスファー処理全体がトランザクション内
- Container Registry操作は個別
- 権限再計算は非同期

## パフォーマンス要件

- 通常の移行処理は数秒以内に完了
- 権限再計算は非同期で実行

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

- 双方での権限チェック必須
- 移行操作の監査ログ記録
- 移行通知メールの送信

## 備考

- 移行後は旧URLからの自動リダイレクトが設定される
- フォーク関係は維持される
- 権限は再計算されるため、一時的にアクセスできない可能性

---

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

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

### 推奨読解順序

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

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

**主要処理フロー**:
1. **137-149行目**: transferアクションの定義

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

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

**主要処理フロー**:
- **25-58行目**: executeメソッドのメイン処理
- **86-103行目**: transferメソッドでの詳細処理
- **137-183行目**: proceed_to_transferでの実際の移行処理
- **254-272行目**: refresh_permissionsでの権限再計算

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

```
ProjectsController#transfer
    │
    └─ Projects::TransferService#execute
           │
           ├─ 事前チェック
           │      ├─ @new_namespace.blank? チェック
           │      ├─ same namespace チェック
           │      ├─ allowed_transfer_project? チェック
           │      └─ allowed_to_transfer_to_namespace? チェック
           │
           └─ transfer
                  │
                  ├─ 重複チェック
                  │
                  ├─ verify_if_container_registry_tags_can_be_handled
                  │
                  ├─ project_has_namespaced_npm_packages? チェック
                  │
                  └─ proceed_to_transfer (トランザクション)
                         │
                         ├─ project.expire_caches_before_rename
                         ├─ update_namespace_and_visibility
                         ├─ project.reconcile_shared_runners_setting!
                         ├─ project.send_move_instructions
                         ├─ Labels::TransferService
                         ├─ Milestones::TransferService
                         ├─ move_project_uploads
                         ├─ transfer_project_path_in_registry
                         ├─ update_integrations
                         ├─ update_repository_configuration
                         ├─ remove_issue_contacts
                         └─ execute_system_hooks
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| projects_controller.rb | `app/controllers/projects_controller.rb` | ソース | コントローラー |
| transfer_service.rb | `app/services/projects/transfer_service.rb` | ソース | 移行ビジネスロジック |
| transfer_service.rb | `app/services/labels/transfer_service.rb` | ソース | ラベル移行 |
| transfer_service.rb | `app/services/milestones/transfer_service.rb` | ソース | マイルストーン移行 |
