# 機能設計書 62-パッケージレジストリ

## 概要

本ドキュメントは、GitLabにおけるパッケージレジストリ機能の設計仕様を記載する。複数の言語・パッケージマネージャに対応したパッケージの保存・管理・配布を行うプライベートパッケージリポジトリ機能を提供する。

### 本機能の処理概要

パッケージレジストリ機能は、npm、Maven、NuGet、PyPI、Conan、Composer、Generic、Golang、Debian、RubyGems、Helm、Terraform Module、RPM、MLモデル、Cargo等、複数のパッケージ形式をサポートするプライベートパッケージリポジトリである。

**業務上の目的・背景**：ソフトウェア開発において、再利用可能なコンポーネントやライブラリを管理・配布する仕組みは不可欠である。従来は各言語・プラットフォームごとに個別のパッケージマネージャやリポジトリを運用する必要があったが、本機能によりGitLab内で統合的にパッケージを管理できる。これにより、アクセス制御の一元化、CI/CDパイプラインとの緊密な連携、プロジェクト単位でのパッケージ管理が可能となり、開発・運用の効率化とセキュリティの向上を実現する。

**機能の利用シーン**：
- チーム・組織内で共有するプライベートライブラリの公開・配布
- CI/CDパイプラインでビルドした成果物のパッケージとしての保存
- 依存関係管理ツール（npm、pip、Maven等）からのパッケージ取得
- パッケージのバージョン管理と履歴追跡
- パッケージへのアクセス制御と監査

**主要な処理内容**：
1. パッケージの公開（Publish）- 各種パッケージマネージャからのパッケージアップロード
2. パッケージの取得（Pull/Download）- パッケージファイルのダウンロード
3. パッケージの検索（Search）- 名前、バージョン、タイプによるパッケージ検索
4. パッケージの削除（Delete）- パッケージの非同期削除
5. メタデータ管理 - 依存関係、タグ、パイプライン連携情報の管理

**関連システム・外部連携**：
- npm CLI（npmレジストリプロトコル）
- Maven（Mavenリポジトリプロトコル）
- NuGet CLI（NuGet V3 API）
- pip/twine（PyPI Simple API）
- Conan CLI（Conanリポジトリプロトコル）
- Helm CLI（Helmチャートリポジトリ）
- CI/CDパイプライン（ビルド成果物連携）

**権限による制御**：
- `read_package`権限：パッケージの閲覧・ダウンロード
- `write_package`権限：パッケージの公開
- `destroy_package`権限：パッケージの削除
- プロジェクト/グループレベルでの可視性設定

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 93 | パッケージ一覧 | 主機能 | パッケージレジストリの一覧表示 |
| 94 | インフラレジストリ一覧 | 主機能 | インフラストラクチャレジストリの一覧 |
| 95 | インフラレジストリ詳細 | 主機能 | インフラパッケージの詳細表示 |
| 115 | パッケージ設定 | 主機能 | パッケージ・レジストリ関連設定 |
| 156 | パッケージ一覧（グループ） | 主機能 | グループパッケージの一覧表示 |
| 157 | インフラレジストリ（グループ） | 主機能 | グループインフラレジストリの表示 |
| 160 | Dependency Proxy | 主機能 | Dependency Proxy設定の表示 |
| 175 | パッケージ設定（グループ） | 主機能 | グループパッケージ設定 |

## 機能種別

CRUD操作 / ファイルストレージ / データ連携 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String/Integer | Yes | プロジェクト/グループのID | 存在確認 |
| package_id | Integer | 詳細取得時Yes | パッケージID | 存在確認 |
| order_by | String | No | ソート項目（created_at, name, version, type） | enum値 |
| sort | String | No | ソート順（asc, desc） | enum値 |
| package_type | String | No | パッケージタイプフィルタ | enum値 |
| package_name | String | No | パッケージ名フィルタ | - |
| package_version | String | No | バージョンフィルタ | - |
| include_versionless | Boolean | No | バージョンなしパッケージを含むか | - |
| status | String | No | ステータスフィルタ | enum値 |

### 入力データソース

- 各種パッケージマネージャCLIからのHTTPリクエスト
- Web UI（パッケージ一覧画面）
- GitLab CI/CDジョブからのAPIリクエスト
- REST API / GraphQL API

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | パッケージID |
| name | String | パッケージ名 |
| version | String | バージョン |
| package_type | String | パッケージタイプ |
| status | String | ステータス（default, hidden, processing, error, pending_destruction, deprecated） |
| created_at | DateTime | 作成日時 |
| tags | Array | 関連タグ一覧 |
| pipelines | Array | 関連パイプライン情報 |
| package_files | Array | パッケージファイル一覧 |

### 出力先

- HTTPレスポンス（JSON）
- パッケージファイルのダウンロード（バイナリ）
- オブジェクトストレージ/ローカルファイルシステム

## 処理フロー

### 処理シーケンス

```
1. パッケージ一覧取得
   └─ 認証・認可チェック
   └─ PackagesFinderで検索条件に基づき取得
   └─ ソート・ページネーション適用
   └─ JSON形式でレスポンス

2. パッケージ詳細取得
   └─ 認証・認可チェック
   └─ PackageFinderで単一パッケージ取得
   └─ 関連データ（タグ、依存関係、パイプライン）をプリロード
   └─ JSON形式でレスポンス

3. パッケージ公開
   └─ 認証・認可チェック
   └─ パッケージタイプ別の検証
   └─ メタデータ抽出
   └─ パッケージレコード作成/更新
   └─ ファイルアップロード処理
   └─ イベント発行

4. パッケージ削除
   └─ 認証・認可チェック
   └─ 保護ルールチェック
   └─ pending_destructionステータスに変更
   └─ 非同期ワーカーでファイル削除
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D{権限チェック}
    D -->|権限なし| E[403 Forbidden]
    D -->|権限あり| F{操作種別}

    F -->|一覧取得| G[PackagesFinder実行]
    G --> H[ページネーション適用]
    H --> I[JSON返却]

    F -->|詳細取得| J[PackageFinder実行]
    J --> K{パッケージ存在?}
    K -->|No| L[404 Not Found]
    K -->|Yes| M[詳細情報返却]

    F -->|削除| N{保護ルールチェック}
    N -->|保護対象| O[403 Forbidden]
    N -->|OK| P[pending_destruction設定]
    P --> Q[非同期削除キュー]
    Q --> R[204 No Content]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | パッケージ名一意性 | プロジェクト内でパッケージ名+バージョン+タイプの組み合わせは一意 | パッケージ作成時（Conan除く） |
| BR-02 | 削除保護 | 保護ルールに該当するパッケージは削除不可 | パッケージ削除時 |
| BR-03 | ステータス遷移 | pending_destructionへの遷移後はロールバック不可 | パッケージ削除時 |
| BR-04 | 表示ステータス | displayable（default, error, deprecated）のみ一覧表示 | パッケージ一覧取得時 |
| BR-05 | インストール可能ステータス | installable（default, hidden, deprecated）のみダウンロード可能 | パッケージダウンロード時 |
| BR-06 | プロジェクト統計更新 | パッケージファイル追加/削除時にpackages_sizeを更新 | ファイル操作時 |

### 計算ロジック

パッケージサイズはパッケージファイルのサイズ合計から算出し、プロジェクト統計のpackages_sizeとして集計される。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| パッケージ作成 | packages_packages | INSERT | 新規パッケージレコードの作成 |
| パッケージファイル作成 | packages_package_files | INSERT | パッケージファイルレコードの作成 |
| パッケージ取得 | packages_packages, packages_package_files | SELECT | パッケージと関連データの取得 |
| パッケージ削除 | packages_packages | UPDATE | status=pending_destructionへ更新 |
| ファイル削除 | packages_package_files | UPDATE/DELETE | ファイルの論理/物理削除 |
| タグ操作 | packages_tags | INSERT/UPDATE/DELETE | タグの作成・更新・削除 |
| 依存関係登録 | packages_dependencies, packages_dependency_links | INSERT | 依存関係情報の登録 |
| ビルド情報登録 | packages_build_infos | INSERT | パイプライン連携情報の登録 |

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

#### packages_packages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | project_id | 対象プロジェクトID | 外部キー |
| INSERT | creator_id | current_user.id | 作成者 |
| INSERT | name | パッケージ名 | 必須 |
| INSERT | version | バージョン文字列 | 任意 |
| INSERT | package_type | パッケージタイプ（1-15） | enum |
| INSERT | status | 0（default） | enum |
| UPDATE | status | 4（pending_destruction） | 削除時 |
| UPDATE | status | 5（deprecated） | 非推奨化時 |

#### packages_package_files

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | package_id | 親パッケージID | 外部キー |
| INSERT | project_id | プロジェクトID | 冗長化のため |
| INSERT | file | アップロードファイル | CarrierWave |
| INSERT | file_name | ファイル名 | 必須 |
| INSERT | size | ファイルサイズ | バイト単位 |
| INSERT | file_sha256 | SHA256ハッシュ | PyPI等で必須 |
| INSERT | file_store | ストレージ種別 | local/remote |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証失敗 | 有効なアクセストークンを使用 |
| 403 | Forbidden | 権限不足、保護ルール違反 | 適切な権限を持つユーザーで実行 |
| 404 | Not Found | パッケージが存在しない | パッケージID/名を確認 |
| 400 | Bad Request | 入力値不正 | リクエストパラメータを修正 |
| 422 | Unprocessable Entity | バリデーションエラー | パッケージ仕様を確認 |

### リトライ仕様

パッケージファイルのアップロード失敗時、クライアント側でリトライを行う。サーバー側でのリトライ処理はなし。

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

- パッケージ作成はパッケージレコードとファイルレコードを同一トランザクションで処理
- 削除は論理削除（ステータス変更）後、非同期ワーカーで物理削除
- プロジェクト統計はコールバックで非同期更新

## パフォーマンス要件

- パッケージ一覧はページネーション（デフォルト20件）で取得
- パイプライン取得は最大20件/ページ（キーセットページネーション）
- 大容量ファイルはWorkhorseによるダイレクトアップロード対応

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

- プロジェクト/グループの可視性に基づくアクセス制御
- 保護パッケージルールによる削除制限
- CI/CDジョブトークンのスコープ制限
- パッケージファイルのハッシュ検証（SHA256）

## 備考

- パッケージタイプ別に専用のAPI・サービスが存在
- Terraform Moduleは通常のパッケージ一覧から除外（専用画面で表示）
- feature_category: `package_registry`

---

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

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

### 推奨読解順序

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

パッケージレジストリで使用される主要なデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | package.rb | `app/models/packages/package.rb` | パッケージの主要モデル。package_type enum、status enum、関連テーブルを確認 |
| 1-2 | package_file.rb | `app/models/packages/package_file.rb` | パッケージファイルモデル。ファイルアップロード、メタデータ管理を確認 |

**読解のコツ**:
- **19-35行目（package.rb）**: `package_type` enumで対応パッケージ形式を把握
- **37行目（package.rb）**: `status` enumでステータス遷移を理解
- **133-153行目（package.rb）**: STI（単一テーブル継承）の実装でパッケージタイプ別クラスへの分岐を確認
- **153行目（package_file.rb）**: `mount_file_store_uploader`でファイルアップロード実装を確認

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

API経由でのリクエスト処理の起点となるファイルを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | project_packages.rb (API) | `lib/api/project_packages.rb` | REST APIエンドポイント定義 |
| 2-2 | packages_controller.rb | `app/controllers/projects/packages/packages_controller.rb` | Web UIコントローラー |

**主要処理フロー**:
1. **8-10行目（API）**: `before`フックでauthorize_packages_access!
2. **59-66行目（API）**: GET /:id/packages - パッケージ一覧取得
3. **83-87行目（API）**: GET /:id/packages/:package_id - パッケージ詳細取得
4. **142-159行目（API）**: DELETE /:id/packages/:package_id - パッケージ削除

#### Step 3: Finder層を理解する

パッケージ検索のビジネスロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | packages_finder.rb | `app/finders/packages/packages_finder.rb` | パッケージ一覧検索のFinderクラス |
| 3-2 | package_finder.rb | `app/finders/packages/package_finder.rb` | 単一パッケージ検索のFinderクラス |

**主要処理フロー**:
- **packages_finder.rb 26-37行目**: `execute`メソッドで検索・フィルタ・ソートを適用
- **packages_finder.rb 57-61行目**: `base`メソッドでTerraform Moduleを除外

#### Step 4: サービス層を理解する

パッケージ操作のビジネスロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | mark_package_for_destruction_service.rb | `app/services/packages/mark_package_for_destruction_service.rb` | パッケージ削除処理 |
| 4-2 | create_package_service.rb | `app/services/packages/create_package_service.rb` | パッケージ作成処理 |

**主要処理フロー**:
- **mark_package_for_destruction_service.rb 7-21行目**: `execute`メソッドで削除処理（ステータス変更、メタデータ同期）

#### Step 5: アクセス制御を理解する

権限チェックの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | packages_access.rb | `app/controllers/concerns/packages_access.rb` | コントローラー向けアクセス制御 |

**主要処理フロー**:
- **13-15行目**: パッケージ機能の有効化チェック
- **17-19行目**: read_package権限チェック

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

```
Web UI / Package Manager CLI
    │
    ├─ GET /projects/:id/packages
    │      └─ API::ProjectPackages#index
    │             └─ PackagesFinder#execute
    │                    └─ Packages::Package.for_projects
    │
    ├─ GET /projects/:id/packages/:package_id
    │      └─ API::ProjectPackages#show
    │             └─ PackageFinder#execute
    │                    └─ Packages::Package.find_by
    │
    ├─ DELETE /projects/:id/packages/:package_id
    │      └─ API::ProjectPackages#delete
    │             └─ CheckRuleExistenceService#execute（保護ルールチェック）
    │             └─ MarkPackageForDestructionService#execute
    │                    └─ package.pending_destruction!
    │                    └─ MarkPackageFilesForDestructionWorker（非同期）
    │
    └─ POST /projects/:id/packages/{type}
           └─ 各パッケージタイプ別API
                  └─ CreatePackageService#execute
                         └─ Packages::Package.create
                         └─ Packages::PackageFile.create
```

### データフロー図

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

npm/Maven/NuGet等 ────▶ GitLab API ──────────────────▶ HTTP Response
CLIツール               (認証・認可)                    (JSON/パッケージファイル)
      │                      │
      │                      ▼
      │             パッケージタイプ別API
      │             (npm/maven/nuget/...)
      │                      │
      │                      ▼
      │             CreatePackageService
      │             (バリデーション・メタデータ抽出)
      │                      │
      │                      ▼
      │              ┌───────┴───────┐
      │              ▼               ▼
      │      packages_packages    packages_package_files
      │      (PostgreSQL)         (PostgreSQL)
      │                                 │
      └─────────────────────────────────┤
                                        ▼
                              Object Storage / Local
                              (パッケージファイル実体)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| package.rb | `app/models/packages/package.rb` | モデル | パッケージのActiveRecordモデル |
| package_file.rb | `app/models/packages/package_file.rb` | モデル | パッケージファイルのモデル |
| project_packages.rb (API) | `lib/api/project_packages.rb` | API | REST APIエンドポイント |
| group_packages.rb | `lib/api/group_packages.rb` | API | グループレベルAPIエンドポイント |
| packages_controller.rb | `app/controllers/projects/packages/packages_controller.rb` | コントローラー | Web UIコントローラー |
| packages_finder.rb | `app/finders/packages/packages_finder.rb` | Finder | パッケージ検索 |
| package_finder.rb | `app/finders/packages/package_finder.rb` | Finder | 単一パッケージ検索 |
| mark_package_for_destruction_service.rb | `app/services/packages/mark_package_for_destruction_service.rb` | サービス | パッケージ削除 |
| create_package_service.rb | `app/services/packages/create_package_service.rb` | サービス | パッケージ作成 |
| packages_access.rb | `app/controllers/concerns/packages_access.rb` | Concern | アクセス制御 |
| packages_helpers.rb | `lib/api/helpers/packages_helpers.rb` | ヘルパー | APIヘルパー |
| npm_project_packages.rb | `lib/api/npm_project_packages.rb` | API | npmパッケージAPI |
| maven_packages.rb | `lib/api/maven_packages.rb` | API | MavenパッケージAPI |
| nuget_project_packages.rb | `lib/api/nuget_project_packages.rb` | API | NuGetパッケージAPI |
| pypi_packages.rb | `lib/api/pypi_packages.rb` | API | PyPIパッケージAPI |
