# 帳票設計書 11-Project Export

## 概要

本ドキュメントは、GitLabにおけるProject Export機能の帳票設計書である。プロジェクト全体をアーカイブファイル（tar.gz形式）としてエクスポートする機能について、出力形式、データ構造、処理フローを定義する。

### 本帳票の処理概要

Project Export機能は、GitLabプロジェクトの完全なバックアップとして、リポジトリ、Wiki、Issue、Merge Request、設定情報などをtar.gz形式のアーカイブファイルとしてエクスポートする機能である。

**業務上の目的・背景**：プロジェクトの移行やバックアップを目的として、GitLabプロジェクトの完全なスナップショットを作成する必要がある。この機能により、異なるGitLabインスタンス間でのプロジェクト移行、災害復旧用バックアップの作成、プロジェクト構成のアーカイブ保存が可能となる。また、セルフマネージド環境からGitLab.comへの移行など、プラットフォーム間の移行シナリオにも対応する。

**帳票の利用シーン**：プロジェクト管理者がプロジェクトを別のGitLabインスタンスに移行する場合、組織の監査要件に基づくプロジェクトのアーカイブ保存、開発環境の複製やテスト環境の構築、セキュリティインシデント対応のための証跡保存などの場面で利用される。

**主要な出力内容**：
1. Gitリポジトリデータ（ソースコード、ブランチ、タグ、コミット履歴）
2. Wikiリポジトリデータ
3. Issue、Merge Request、マイルストーン、ラベルなどのプロジェクト管理データ
4. CI/CD設定（.gitlab-ci.yml）およびパイプライン設定
5. プロジェクト設定（アクセス権限、Webhook、インテグレーション設定）
6. LFSオブジェクト
7. アップロードファイル（添付ファイル）
8. スニペット
9. デザインリポジトリ

**帳票の出力タイミング**：プロジェクト設定画面の「Export project」ボタンをクリックした際に非同期で生成される。エクスポート完了後、メールで通知され、ダウンロードリンクが提供される。

**帳票の利用者**：プロジェクト管理者（Admin権限を持つユーザー）、システム管理者

## 帳票種別

アーカイブ出力（tar.gz形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | プロジェクト設定 - 一般設定 | `/:namespace/:project/-/edit` | Export project ボタン |
| - | プロジェクト詳細API | `GET /api/v4/projects/:id/export` | API呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | tar.gz（gzip圧縮されたtarアーカイブ） |
| 用紙サイズ | N/A（アーカイブファイル） |
| 向き | N/A |
| ファイル名 | `{project_name}_export.tar.gz` |
| 出力方法 | ダウンロード / メール通知後ダウンロード |
| 文字コード | UTF-8 |

### アーカイブ固有設定

| 項目 | 内容 |
|-----|------|
| 圧縮形式 | gzip |
| 暗号化 | なし（オブジェクトストレージ保存時はストレージ側で暗号化可能） |
| 分割出力 | なし |

## 帳票レイアウト

### レイアウト概要

tar.gzアーカイブ内のディレクトリ構造

```
project_export/
├── VERSION                    # エクスポートバージョン
├── project.json              # プロジェクトメタデータ（NDJSON形式）
├── tree/                     # プロジェクトツリーデータ
│   ├── project.ndjson       # プロジェクト情報
│   ├── issues.ndjson        # Issue一覧
│   ├── merge_requests.ndjson # MR一覧
│   └── ...                  # その他のリレーション
├── project.bundle           # Gitリポジトリバンドル
├── project.wiki.bundle      # Wikiリポジトリバンドル
├── project.design.bundle    # デザインリポジトリバンドル
├── uploads/                 # アップロードファイル
├── lfs-objects/            # LFSオブジェクト
└── snippets/               # スニペットリポジトリ
```

### ヘッダー部

N/A（アーカイブファイルのためヘッダー部なし）

### 明細部

#### VERSION ファイル

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | version | エクスポートバージョン番号 | Gitlab::ImportExport.version | 文字列 |

#### project.ndjson ファイル

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | id | プロジェクトID | projects.id | 数値 |
| 2 | name | プロジェクト名 | projects.name | 文字列 |
| 3 | path | プロジェクトパス | projects.path | 文字列 |
| 4 | description | 説明 | projects.description | 文字列 |
| 5 | created_at | 作成日時 | projects.created_at | ISO8601 |
| 6 | visibility_level | 公開レベル | projects.visibility_level | 数値 |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| プロジェクトID | エクスポート対象のプロジェクト | Yes |
| ユーザー権限 | admin_project権限またはテンプレートソース | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | N/A（関連データは各リレーションの作成順） | - |

### 改ページ条件

N/A（アーカイブファイル）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| projects | プロジェクト情報 | 主テーブル |
| issues | Issue情報 | project_id = projects.id |
| merge_requests | MR情報 | target_project_id = projects.id |
| milestones | マイルストーン | project_id = projects.id |
| labels | ラベル | project_id = projects.id |
| project_members | メンバー情報 | source_id = projects.id |
| protected_branches | 保護ブランチ | project_id = projects.id |
| ci_pipelines | パイプライン | project_id = projects.id |
| snippets | スニペット | project_id = projects.id |
| uploads | アップロード | model_id = projects.id |
| lfs_objects_projects | LFSオブジェクト | project_id = projects.id |

### テーブル別参照項目詳細

#### projects

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | project.id | 指定されたプロジェクトID | - |
| name | project.name | - | - |
| path | project.path | - | - |
| description | project.description | - | パラメータで上書き可能 |
| visibility_level | project.visibility_level | - | - |
| created_at | project.created_at | - | - |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| N/A | - | - | 計算項目なし |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Export要求] --> B[権限検証]
    B -->|権限あり| C[既存エクスポート削除]
    B -->|権限なし| Z[エラー: Permission denied]
    C --> D[各Exporterの実行]
    D --> E[VersionSaver]
    E --> F[AvatarSaver]
    F --> G[ProjectTreeSaver]
    G --> H[UploadsSaver]
    H --> I[RepoSaver]
    I --> J[WikiRepoSaver]
    J --> K[LfsSaver]
    K --> L[SnippetsRepoSaver]
    L --> M[DesignRepoSaver]
    M --> N[tar.gz圧縮]
    N --> O[ImportExportUploadに保存]
    O --> P[メール通知]
    P --> Q[終了]
    D -->|エラー| R[エラー通知]
    R --> Q
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 権限エラー | admin_project権限がない | You don't have permission to export this project | 管理者権限を取得する |
| ディスク容量不足 | 一時ディレクトリの容量不足 | Unable to save export file | ディスク容量を確保する |
| リポジトリエラー | Gitリポジトリへのアクセス失敗 | Repository export failed | リポジトリの状態を確認する |
| タイムアウト | 処理時間超過 | Export timed out | 小さなプロジェクトで再試行 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | プロジェクトサイズに依存（〜数GB） |
| 目標出力時間 | 中規模プロジェクトで10分以内 |
| 同時出力数上限 | Sidekiqワーカー数に依存 |

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

- エクスポートファイルにはプロジェクトの全データが含まれるため、admin_project権限の検証が必須
- エクスポートファイルはオブジェクトストレージに一時保存され、有効期限後に自動削除される
- 監査ログにエクスポート操作が記録される
- silent_admin_exports_enabled設定により管理者エクスポートの監査を制御可能

## 備考

- エクスポート処理は非同期（Sidekiqジョブ）で実行される
- 大規模プロジェクトの場合、並列エクスポート機能（ParallelExportService）が利用可能
- エクスポートファイルは一定期間（デフォルト7日間）後に自動削除される

---

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

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

### 推奨読解順序

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

エクスポートされるデータの構造と、保存先を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | import_export_upload.rb | `app/models/import_export_upload.rb` | エクスポートファイルの保存先モデル。export_file, import_fileのマウント設定を確認 |
| 1-2 | project_export_presenter.rb | `app/presenters/projects/import_export/project_export_presenter.rb` | エクスポート時のプロジェクトデータ整形。project_members、descriptionの上書き処理 |

**読解のコツ**: Railsのmount_uploaderを使用したファイルアップロード処理。CarrierWaveのコールバック処理に注意。

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

処理の起点となるサービスクラスを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | export_service.rb | `app/services/projects/import_export/export_service.rb` | メインのエクスポート処理。execute()メソッドがエントリーポイント |

**主要処理フロー**:
1. **15-17行目**: 権限チェック（admin_projectまたはtemplate_source）
2. **20-21行目**: save_all!でエクスポート実行、after_export_strategyで後処理
3. **26-30行目**: exportersメソッドで各Saverを定義
4. **56-71行目**: save_all!の実装。全Exporterを順次実行し、アーカイブを保存

#### Step 3: 各Saverの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tree_saver.rb | `lib/gitlab/import_export/project/tree_saver.rb` | プロジェクトツリーのJSON出力。stream_export()でNDJSON形式に出力 |
| 3-2 | saver.rb | `lib/gitlab/import_export/saver.rb` | tar.gz圧縮と保存処理。compress_and_save()とsave_upload()を確認 |

**主要処理フロー**:
- **TreeSaver 19-24行目**: saveメソッドでstream_export()を呼び出し
- **TreeSaver 48-59行目**: StreamingSerializerでNDJSON形式にシリアライズ
- **Saver 43-50行目**: tar_czfでgzip圧縮
- **Saver 61-71行目**: ImportExportUploadモデルへのファイル保存

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

```
Projects::ImportExport::ExportService#execute
    │
    ├─ save_all!
    │      ├─ save_exporters (各Saverを順次実行)
    │      │      ├─ Gitlab::ImportExport::VersionSaver#save
    │      │      ├─ Gitlab::ImportExport::AvatarSaver#save
    │      │      ├─ Gitlab::ImportExport::Project::TreeSaver#save
    │      │      │      └─ ImportExport::Json::StreamingSerializer#execute
    │      │      ├─ Gitlab::ImportExport::UploadsSaver#save
    │      │      ├─ Gitlab::ImportExport::RepoSaver#save
    │      │      ├─ Gitlab::ImportExport::WikiRepoSaver#save
    │      │      ├─ Gitlab::ImportExport::LfsSaver#save
    │      │      ├─ Gitlab::ImportExport::SnippetsRepoSaver#save
    │      │      └─ Gitlab::ImportExport::DesignRepoSaver#save
    │      │
    │      └─ save_export_archive
    │             └─ Gitlab::ImportExport::Saver#save
    │                    ├─ compress_and_save (tar.gz圧縮)
    │                    └─ save_upload (ImportExportUploadに保存)
    │
    └─ execute_after_export_action (後処理)
           └─ NotificationService#project_not_exported (エラー時)
```

### データフロー図

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

Project モデル ─────────▶ TreeSaver ─────────────────▶ tree/project.ndjson
                         (NDJSON変換)

Git Repository ─────────▶ RepoSaver ─────────────────▶ project.bundle
                         (git bundle)

Wiki Repository ────────▶ WikiRepoSaver ─────────────▶ project.wiki.bundle

Uploads ────────────────▶ UploadsSaver ──────────────▶ uploads/

LFS Objects ────────────▶ LfsSaver ──────────────────▶ lfs-objects/

全ファイル ─────────────▶ Saver ──────────────────────▶ {project}_export.tar.gz
                         (tar.gz圧縮)                    ↓
                                                     ImportExportUpload
                                                        ↓
                                                     オブジェクトストレージ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export_service.rb | `app/services/projects/import_export/export_service.rb` | ソース | メインエクスポートサービス |
| tree_saver.rb | `lib/gitlab/import_export/project/tree_saver.rb` | ソース | プロジェクトツリーのNDJSON出力 |
| saver.rb | `lib/gitlab/import_export/saver.rb` | ソース | tar.gz圧縮とアップロード |
| import_export_upload.rb | `app/models/import_export_upload.rb` | ソース | エクスポートファイル保存モデル |
| project_export_presenter.rb | `app/presenters/projects/import_export/project_export_presenter.rb` | ソース | プロジェクトデータのプレゼンター |
| version_saver.rb | `lib/gitlab/import_export/version_saver.rb` | ソース | バージョン情報の保存 |
| repo_saver.rb | `lib/gitlab/import_export/repo_saver.rb` | ソース | Gitリポジトリのバンドル化 |
| uploads_saver.rb | `lib/gitlab/import_export/uploads_saver.rb` | ソース | アップロードファイルのコピー |
| lfs_saver.rb | `lib/gitlab/import_export/lfs_saver.rb` | ソース | LFSオブジェクトのコピー |
| parallel_export_service.rb | `app/services/projects/import_export/parallel_export_service.rb` | ソース | 並列エクスポート処理 |
