# 画面設計書 300-GitLabプロジェクトインポート

## 概要

本ドキュメントは、GitLabにおけるGitLabエクスポートファイルからプロジェクトをインポートする画面の設計を記載したものである。

### 本画面の処理概要

GitLabの別インスタンスからエクスポートしたプロジェクトファイル（.gz形式）をアップロードしてインポートする画面である。プロジェクトのリポジトリ、Issue、マージリクエスト、Wiki、メンバー、設定などを含む完全なプロジェクトデータを移行できる。

**業務上の目的・背景**：異なるGitLabインスタンス間でプロジェクトを移行する際に使用する。オンプレミスからSaaSへの移行、SaaSからオンプレミスへの移行、または別組織のGitLabインスタンスへのプロジェクト移動が可能。テンプレートプロジェクトからの新規プロジェクト作成にも内部的に使用される。

**画面へのアクセス方法**：
1. サイドバーまたはヘッダーから「プロジェクト新規作成」を選択
2. 「Import project」タブを選択
3. 「GitLab export」を選択して本画面にアクセス

**主要な操作・処理内容**：
1. プロジェクト名の入力
2. インポート先ネームスペース（グループ）の選択
3. プロジェクトスラグの入力（自動生成）
4. GitLabエクスポートファイル（.gz）のアップロード
5. 「Import project」ボタンでインポート実行

**画面遷移**：
- 遷移元：プロジェクト新規作成画面（インポート選択）
- 遷移先：インポートされたプロジェクト詳細画面

**権限による表示制御**：
- 選択したネームスペースへのプロジェクトインポート権限（`import_projects`）が必要
- GitLabプロジェクトインポート機能が有効である必要がある（`gitlab_project_import_enabled?`）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 108 | プロジェクトエクスポート | 主機能 | GitLabエクスポートファイルのインポート処理 |

## 画面種別

登録

## URL/ルーティング

```
GET /import/gitlab_project/new
POST /import/gitlab_project
POST /import/gitlab_project/authorize
```

ルーティング定義: `config/routes/import.rb`
```ruby
resource :gitlab_project, only: [:create, :new] do
  post :create
  post :authorize
end
```

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| プロジェクト名 | name | 文字列 | 必須 | GitLabでのプロジェクト名 |
| プロジェクトスラグ | path | 文字列 | 必須 | GitLabでのプロジェクトパス（URLに使用） |
| ネームスペースID | namespace_id | 整数 | 必須 | インポート先ネームスペース |
| ファイル | file | ファイル | 必須 | GitLabエクスポートファイル（.gz形式） |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ページタイトル | 「GitLab Import」 |
| フォームタイトル | 「Import an exported GitLab project」 |
| 説明文 | プロジェクトのエクスポートとアップロードの手順説明 |
| ファイルアップロード | ドラッグ＆ドロップまたはクリックでファイル選択 |
| 選択済みファイル表示 | ファイル名とサイズを表示 |

## イベント仕様

### 1-プロジェクト名入力時のスラグ自動生成

プロジェクト名を入力すると、自動的にプロジェクトスラグが生成される：

```javascript
// app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue (行92-97)
watch: {
  // eslint-disable-next-line func-names
  'form.fields.name.value': function (newVal) {
    this.form.fields.path.value = kebabCase(newVal);
  },
},
```

### 2-ファイルアップロード

ドロップゾーンまたはファイル選択ダイアログでファイルを選択：

```javascript
// app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue (行99-110)
setFile() {
  this.file = this.$refs.fileUpload.files['0'];

  const fileUrlReader = new FileReader();

  fileUrlReader.readAsDataURL(this.file);

  fileUrlReader.onload = (e) => {
    this.filePreviewURL = e.target?.result;
  };
  this.dropzoneState = true;
},
```

### 3-フォーム送信

「Import project」ボタンを押下すると以下の処理が実行される：

```javascript
// app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue (行120-134)
onSubmit() {
  if (!this.form.state) {
    this.form.showValidation = true;
  }

  if (this.file === null) {
    this.dropzoneState = false;
  }

  if (!this.form.state || !this.dropzoneState) {
    return;
  }

  this.$refs.form.submit();
}
```

### 4-サーバー側処理

```ruby
# app/controllers/import/gitlab_projects_controller.rb (行17-44)
def create
  unless file_is_valid?(project_params[:file])
    return redirect_back_or_default(
      options: {
        alert: _("You need to upload a GitLab project export archive (ending in .gz).")
      }
    )
  end

  @project = ::Projects::GitlabProjectsImportService.new(
    current_user,
    project_params,
    import_type: 'gitlab_project'
  ).execute

  if @project.saved?
    redirect_to(
      project_path(@project),
      notice: safe_format(_("Project '%{project_name}' is being imported."), project_name: @project.name)
    )
  else
    redirect_back_or_default(
      options: {
        alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}"
      }
    )
  end
end
```

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Import project | projects | INSERT | 新規プロジェクトを作成 |
| Import project | project_import_data | INSERT | インポートデータを保存 |
| Import project | import_states | INSERT | インポート状態を記録 |
| Import project | namespaces | SELECT | インポート先ネームスペースを取得 |

### テーブル別更新項目詳細

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | 入力されたプロジェクト名 | プロジェクト名 |
| INSERT | path | 入力されたスラグ | URLパス |
| INSERT | namespace_id | 選択されたネームスペースID | インポート先ネームスペース |
| INSERT | import_type | 'gitlab_project' | インポート種別 |
| INSERT | creator_id | current_user.id | 作成者 |
| INSERT | organization_id | namespace.organization_id | 組織ID（サービスで設定） |

#### project_import_data

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | project_id | 作成されたプロジェクトID | 関連プロジェクト |
| INSERT | data | override_params等 | インポート関連データ |

## メッセージ仕様

| メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|-------------|---------------|---------------|---------|
| MSG001 | 成功 | Project '{project_name}' is being imported. | インポート開始成功時 |
| MSG002 | エラー | You need to upload a GitLab project export archive (ending in .gz). | ファイル形式不正時 |
| MSG003 | エラー | Project could not be imported: {errors} | プロジェクト作成エラー時 |
| MSG004 | バリデーション | Please enter a valid project name. | プロジェクト名未入力時 |
| MSG005 | バリデーション | Please enter a valid project slug. | スラグ未入力時 |
| MSG006 | バリデーション | Please upload a valid GitLab project export file. | ファイル未選択時 |

## 例外処理

| 例外パターン | 処理内容 |
|-------------|---------|
| ファイル形式不正（非.gz） | エラーメッセージを表示して再入力を促す |
| ファイル未選択 | バリデーションエラーを表示 |
| プロジェクト名不正 | バリデーションエラーを表示 |
| ネームスペース権限不足 | 404エラーを表示 |
| GitLabインポート機能無効 | 404エラーを表示 |
| ファイルサイズ超過 | 最大インポートサイズに基づくエラー |

## 備考

- Feature Flag `new_project_creation_form`が有効な場合、Vue.jsコンポーネントで表示される
- Feature Flagが無効な場合、従来のHAMLフォームが表示される
- 許可されるファイル形式: application/gzip（.gz）
- 最大ファイルサイズ: `Gitlab::CurrentSettings.max_import_size`で設定
- プロジェクト名からスラグへの変換にはkebabCase関数を使用
- Workhorse認証（`WorkhorseAuthorization`モジュール）によるファイルアップロード処理
- テンプレートプロジェクトからの作成にも同じサービスが使用される

---

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

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

### 推奨読解順序

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

フォームデータ構造とバリデーションルールを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | import_from_gitlab_export_app.vue | `app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue` | data()でのフォーム初期化（行70-86）、feedbackMap（行13-26） |
| 1-2 | gitlab_projects_controller.rb | `app/controllers/import/gitlab_projects_controller.rb` | project_params（行52-56） |

**読解のコツ**: フォームはname, path, namespace_id, fileの4項目。nameからpathへの自動変換（kebabCase）に注目。

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

ビューの初期化とVueコンポーネントのマウントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | new.html.haml | `app/views/import/gitlab_projects/new.html.haml` | Feature Flagによる分岐、data属性の設定 |
| 2-2 | gitlab_projects_controller.rb | `app/controllers/import/gitlab_projects_controller.rb` | newアクション（行10-15） |

**主要処理フロー**:
1. `new_project_creation_form`フラグで分岐
2. 有効時: Vueコンポーネント（`#js-import-gitlab-project-root`）
3. 無効時: 従来のHAMLフォーム

#### Step 3: フォームコンポーネントを理解する

Vueコンポーネントの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | import_from_gitlab_export_app.vue | `app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue` | テンプレート構造、onSubmitメソッド |

**主要処理フロー**:
- **行92-97**: プロジェクト名変更時のスラグ自動生成
- **行99-110**: `setFile`メソッド - ファイルアップロード処理
- **行120-134**: `onSubmit`メソッド - フォーム送信とバリデーション

#### Step 4: サービスレイヤーを理解する

インポート処理の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | gitlab_projects_import_service.rb | `app/services/projects/gitlab_projects_import_service.rb` | executeメソッド、prepare_import_params |

**主要処理フロー**:
- **行22-28**: `execute`メソッド - テンプレート準備とプロジェクト作成
- **行70-84**: `prepare_import_params`メソッド - インポートパラメータの準備

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

```
GET /import/gitlab_project/new
    │
    └─ Import::GitlabProjectsController#new
           │
           ├─ namespace権限チェック (import_projects)
           │      └─ 権限なし: render_404
           │
           └─ app/views/import/gitlab_projects/new.html.haml
                  │
                  ├─ Feature enabled: new_project_creation_form
                  │      └─ #js-import-gitlab-project-root
                  │             └─ import_from_gitlab_export_app.vue
                  │
                  └─ Feature disabled
                         └─ 従来のHAMLフォーム

POST /import/gitlab_project
    │
    └─ Import::GitlabProjectsController#create
           │
           ├─ file_is_valid? チェック
           │      └─ 無効: redirect_back_or_default (エラー)
           │
           └─ Projects::GitlabProjectsImportService#execute
                  │
                  ├─ prepare_template_environment
                  │
                  ├─ prepare_import_params
                  │
                  └─ Projects::CreateService#execute
                         │
                         └─ Project作成 + インポート処理開始
```

### データフロー図

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

フォームデータ       ───▶  Import::GitlabProjectsController  ───▶  Project (作成)
(name, path,              #create                                    │
namespace_id, file)                                                  ▼
        │                                                       プロジェクト画面へ
        ▼                                                        リダイレクト
file_is_valid?       ───▶  ファイル形式チェック (.gz)
        │
        ▼
GitlabProjectsImportService ───▶ Projects::CreateService
        │                              │
        ├─ import_type設定             ├─ Project INSERT
        │                              │
        └─ organization_id設定         └─ インポートジョブキュー登録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| new.html.haml | `app/views/import/gitlab_projects/new.html.haml` | テンプレート | 初期画面表示 |
| import_from_gitlab_export_app.vue | `app/assets/javascripts/import/gitlab_project/import_from_gitlab_export_app.vue` | Vueコンポーネント | フォームUI（新UI） |
| gitlab_projects_controller.rb | `app/controllers/import/gitlab_projects_controller.rb` | コントローラー | リクエスト処理 |
| gitlab_projects_import_service.rb | `app/services/projects/gitlab_projects_import_service.rb` | サービス | インポート処理 |
| _new_project_form.html.haml | `app/views/import/shared/_new_project_form.html.haml` | パーシャル | 共通フォーム（旧UI） |
| import.rb | `config/routes/import.rb` | ルーティング | URLルーティング定義 |
| project_name_rules.js | `app/assets/javascripts/projects/project_name_rules.js` | JavaScript | プロジェクト名バリデーションルール |
| project_destination_select.vue | `app/assets/javascripts/projects/new_v2/components/project_destination_select.vue` | Vueコンポーネント | ネームスペース選択 |
