# 機能設計書 64-Helmチャート管理

## 概要

本ドキュメントは、GitLabにおけるHelmチャート管理機能の設計仕様を記載する。KubernetesのパッケージマネージャであるHelmで使用するチャートの保存・管理・配布を行うHelmリポジトリ機能を提供する。

### 本機能の処理概要

Helmチャート管理機能は、Kubernetes用のパッケージ形式であるHelmチャートをGitLabプロジェクト内でホスティングするための機能である。Helm Repository APIに準拠し、標準的なHelm CLIからのチャート取得・公開をサポートする。

**業務上の目的・背景**：Kubernetesアプリケーションの配布において、Helmチャートは事実上の標準パッケージ形式となっている。従来はArtifact Hub、ChartMuseum、S3などの外部サービスを利用する必要があったが、本機能によりGitLab内でソースコード、CI/CD、コンテナイメージ、そしてHelmチャートを統合管理できる。これにより、アクセス制御の一元化、バージョン管理、CI/CDパイプラインとのシームレスな連携が可能となる。

**機能の利用シーン**：
- CI/CDパイプラインでパッケージングしたHelmチャートの公開
- Helm CLIからのチャート検索・インストール
- マイクロサービスアプリケーションのKubernetesデプロイ
- チャートのバージョン管理とチャネル（stable、edge等）による分類

**主要な処理内容**：
1. チャートインデックス（index.yaml）の取得
2. チャートファイル（.tgz）のダウンロード
3. チャートファイルのアップロード・公開
4. チャートメタデータの抽出・管理
5. メタデータキャッシュの生成・同期

**関連システム・外部連携**：
- Helm CLI（helm repo add、helm install）
- CI/CDパイプライン（helm package、アップロード）
- Kubernetesクラスター（チャートデプロイ）
- GitLab Workhorse（ファイルアップロード）

**権限による制御**：
- `read_package`権限：チャートの閲覧・ダウンロード
- `write_package`権限：チャートの公開
- パッケージ保護ルールによるpush制限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | パッケージ一覧 | 参照画面 | Helmパッケージはパッケージレジストリの一部として表示 |

## 機能種別

CRUD操作 / ファイルストレージ / データ連携 / メタデータ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer/String | Yes | プロジェクトIDまたはフルパス | 存在確認 |
| channel | String | Yes | Helmチャネル（stable、edge等） | 正規表現バリデーション、最大255文字 |
| file_name | String | ダウンロード時Yes | チャートファイル名 | - |
| chart | File | アップロード時Yes | チャートファイル（.tgz） | helm_max_file_sizeチェック |

### 入力データソース

- Helm CLI（helm repo add、helm pull、helm push）
- CI/CDジョブからのcurlリクエスト
- GitLab Workhorse経由のファイルアップロード

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| index.yaml | YAML | チャートインデックス（Helm Repository API形式） |
| chart.tgz | Binary | チャートアーカイブファイル |

### 出力先

- HTTPレスポンス（YAML/バイナリ）
- オブジェクトストレージ/ローカルファイルシステム

## 処理フロー

### 処理シーケンス

```
1. チャートインデックス取得（GET :channel/index.yaml）
   └─ 認証・認可チェック
   └─ メタデータキャッシュ確認
      └─ キャッシュあり：キャッシュファイルを返却
      └─ キャッシュなし：
         └─ PackagesFinderでパッケージ一覧取得
         └─ GenerateMetadataServiceでインデックス生成
         └─ キャッシュ同期をトリガー
         └─ インデックスを返却

2. チャートダウンロード（GET :channel/charts/:file_name.tgz）
   └─ 認証・認可チェック
   └─ PackageFilesFinder でファイル検索
   └─ パッケージファイル返却

3. チャートアップロード（POST api/:channel/charts）
   └─ Workhorse認可チェック
   └─ ファイルサイズチェック
   └─ 一時パッケージ作成
   └─ パッケージファイル保存
   └─ ExtractionWorker（非同期）
      └─ メタデータ抽出
      └─ パッケージ名・バージョン設定
      └─ ファイルリネーム
      └─ メタデータキャッシュ更新
```

### フローチャート

```mermaid
flowchart TD
    A[Helm CLI] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D{操作種別}

    D -->|index.yaml取得| E{キャッシュ存在?}
    E -->|Yes| F[キャッシュ返却]
    E -->|No| G[パッケージ一覧取得]
    G --> H[メタデータ生成]
    H --> I[キャッシュ同期]
    I --> J[index.yaml返却]

    D -->|チャートダウンロード| K[ファイル検索]
    K --> L{ファイル存在?}
    L -->|No| M[404 Not Found]
    L -->|Yes| N[ファイル返却]

    D -->|チャートアップロード| O{サイズチェック}
    O -->|超過| P[400 Bad Request]
    O -->|OK| Q[一時パッケージ作成]
    Q --> R[ファイル保存]
    R --> S[ExtractionWorker]
    S --> T{保護ルールチェック}
    T -->|保護対象| U[ProtectedPackageError]
    T -->|OK| V[メタデータ抽出]
    V --> W[パッケージ更新]
    W --> X[キャッシュ更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | チャネル形式 | チャネル名は正規表現に従う（英数字、ハイフン、アンダースコア） | チャネル指定時 |
| BR-02 | パッケージ保護 | 保護ルールに該当するチャートはpush禁止 | チャートアップロード時 |
| BR-03 | 排他制御 | ファイル処理は排他ロック（1時間タイムアウト） | ProcessFileService |
| BR-04 | パッケージ上限 | インデックスに含むパッケージ数は設定に従う | インデックス生成時 |
| BR-05 | ファイルサイズ上限 | helm_max_file_sizeを超えるファイルは拒否 | アップロード時 |
| BR-06 | 一時パッケージ | アップロード時はまず一時パッケージとして保存 | アップロード時 |
| BR-07 | メタデータキャッシュ | index.yamlはキャッシュされ、変更時に更新 | インデックス取得時 |

### 計算ロジック

- ファイル名: `{chart_name}-{chart_version}.tgz`
- リースキー: `packages:helm:process_file_service:package_file:{id}`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| パッケージ作成 | packages_packages | INSERT | 一時パッケージの作成 |
| パッケージ更新 | packages_packages | UPDATE | 名前・バージョン・ステータスの更新 |
| パッケージファイル作成 | packages_package_files | INSERT | チャートファイルの保存 |
| メタデータ作成 | packages_helm_file_metadata | INSERT | チャートメタデータの保存 |
| キャッシュ作成/更新 | packages_helm_metadata_caches | INSERT/UPDATE | インデックスキャッシュの保存 |

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

#### packages_packages（Helmパッケージ）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | TEMPORARY_PACKAGE_NAME | 一時パッケージとして作成 |
| INSERT | package_type | 11（helm） | Helmタイプ |
| INSERT | status | 2（processing） | 処理中 |
| UPDATE | name | Chart.yamlのname | メタデータから抽出 |
| UPDATE | version | Chart.yamlのversion | メタデータから抽出 |
| UPDATE | status | 0（default） | 処理完了 |

#### packages_helm_file_metadata

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | package_file_id | パッケージファイルID | 主キー |
| INSERT | project_id | プロジェクトID | 冗長化のため |
| INSERT | channel | リクエストのchannel | 最大255文字 |
| INSERT | metadata | Chart.yamlの内容 | JSON形式 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証失敗 | 有効なトークンを使用 |
| 403 | Forbidden | 権限不足、保護ルール違反 | 権限確認、保護ルール確認 |
| 404 | Not Found | チャートが存在しない | チャネル・ファイル名を確認 |
| 400 | Bad Request | ファイルサイズ超過 | ファイルサイズを削減 |

### リトライ仕様

排他ロック取得失敗時、ExclusiveLeaseGuardにより自動リトライ。タイムアウト1時間。

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

- チャート処理（名前変更、メタデータ設定、一時パッケージ削除）はトランザクション内で実行
- メタデータキャッシュ更新は非同期ワーカーで実行

## パフォーマンス要件

- インデックスはメタデータキャッシュを活用して高速化
- パッケージ上限はhelm_max_packages_countで制限
- ファイルアップロードはWorkhorse経由でストリーミング処理

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

- パーソナルアクセストークン、デプロイトークン、ジョブトークンによる認証
- プロジェクトの可視性に基づくアクセス制御
- パッケージ保護ルールによるpush制限
- ファイルサイズ制限によるDoS対策

## 備考

- Helm Repository API準拠
- パッケージレジストリの一部として実装（package_type=helm）
- feature_category: `package_registry`

---

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

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

### 推奨読解順序

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

Helmチャート管理で使用される主要なデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | package.rb | `app/models/packages/helm/package.rb` | HelmパッケージのSTIモデル。名前・バージョン形式のバリデーション |
| 1-2 | file_metadatum.rb | `app/models/packages/helm/file_metadatum.rb` | チャートメタデータ（channel、metadata JSON）を管理 |
| 1-3 | metadata_cache.rb | `app/models/packages/helm/metadata_cache.rb` | index.yamlのキャッシュを管理 |

**読解のコツ**:
- **package.rb 8-9行目**: 名前・バージョンの正規表現バリデーションを確認
- **file_metadatum.rb 14-20行目**: channel、metadataのバリデーションを確認
- **file_metadatum.rb 22行目**: `select_distinct_channel_and_project`スコープで対象チャネル一覧取得

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | helm_packages.rb | `lib/api/helm_packages.rb` | Helm Repository APIエンドポイント定義 |

**主要処理フロー**:
1. **66-89行目**: GET `:channel/index.yaml` - チャートインデックス取得
2. **105-116行目**: GET `:channel/charts/:file_name.tgz` - チャートダウンロード
3. **131-137行目**: POST `api/:channel/charts/authorize` - アップロード認可
4. **153-180行目**: POST `api/:channel/charts` - チャートアップロード

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

ビジネスロジックを実装するサービスクラスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | process_file_service.rb | `app/services/packages/helm/process_file_service.rb` | チャート処理の中心ロジック |
| 3-2 | extract_file_metadata_service.rb | `app/services/packages/helm/extract_file_metadata_service.rb` | Chart.yamlからのメタデータ抽出 |
| 3-3 | generate_metadata_service.rb | `app/services/packages/helm/generate_metadata_service.rb` | index.yaml生成 |

**主要処理フロー**:
- **process_file_service.rb 19-35行目**: `execute`メソッドで排他制御付きパッケージ処理
- **process_file_service.rb 41-52行目**: `package_protected?`で保護ルールチェック
- **process_file_service.rb 54-59行目**: パッケージ名・バージョン設定
- **process_file_service.rb 62-74行目**: ファイルリネームとメタデータ設定

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

チャート検索のロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | packages_finder.rb | `app/finders/packages/helm/packages_finder.rb` | チャネル別パッケージ検索 |

**主要処理フロー**:
- **14-26行目**: `execute`メソッドでチャネル別パッケージ一覧取得
- **30-33行目**: `max_packages_count`でパッケージ上限設定取得

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

```
Helm CLI
    │
    ├─ GET /projects/:id/packages/helm/:channel/index.yaml
    │      └─ API::HelmPackages#index
    │             ├─ MetadataCache取得（キャッシュヒット時）
    │             │      └─ present_carrierwave_file!
    │             └─ キャッシュミス時
    │                    └─ PackagesFinder#execute
    │                    └─ GenerateMetadataService#execute
    │                    └─ BulkSyncHelmMetadataCacheService#execute
    │
    ├─ GET /projects/:id/packages/helm/:channel/charts/:file_name.tgz
    │      └─ API::HelmPackages#chart
    │             └─ PackageFilesFinder#most_recent!
    │                    └─ present_package_file!
    │
    └─ POST /projects/:id/packages/helm/api/:channel/charts
           └─ API::HelmPackages#upload
                  └─ CreateTemporaryPackageService#execute
                  └─ CreatePackageFileService#execute
                  └─ ExtractionWorker（非同期）
                         └─ ProcessFileService#execute
                                ├─ CheckRuleExistenceService（保護ルールチェック）
                                ├─ ExtractFileMetadataService#execute
                                ├─ パッケージ更新
                                └─ CreateMetadataCacheWorker（非同期）
```

### データフロー図

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

Helm CLI ───────────▶ GitLab API ──────────────────▶ HTTP Response
(helm pull/push)        (認証・認可)                    (YAML/Binary)
                              │
                              ▼
                    ┌─────────┴─────────┐
                    ▼                   ▼
            index.yaml取得        チャートアップロード
                    │                   │
                    ▼                   ▼
           MetadataCache確認    CreateTemporaryPackageService
                    │                   │
        ┌───────────┴───────────┐       ▼
        ▼                       ▼  ExtractionWorker
   キャッシュ返却         GenerateMetadataService
                                │       │
                                ▼       ▼
                    packages_helm_metadata_caches
                    (PostgreSQL)
                                        │
                                        ▼
                              Object Storage / Local
                              (チャートファイル実体)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| helm_packages.rb | `lib/api/helm_packages.rb` | API | Helm Repository APIエンドポイント |
| package.rb | `app/models/packages/helm/package.rb` | モデル | HelmパッケージのSTIモデル |
| file_metadatum.rb | `app/models/packages/helm/file_metadatum.rb` | モデル | チャートメタデータ |
| metadata_cache.rb | `app/models/packages/helm/metadata_cache.rb` | モデル | インデックスキャッシュ |
| process_file_service.rb | `app/services/packages/helm/process_file_service.rb` | サービス | チャート処理 |
| extract_file_metadata_service.rb | `app/services/packages/helm/extract_file_metadata_service.rb` | サービス | メタデータ抽出 |
| generate_metadata_service.rb | `app/services/packages/helm/generate_metadata_service.rb` | サービス | index.yaml生成 |
| create_metadata_cache_service.rb | `app/services/packages/helm/create_metadata_cache_service.rb` | サービス | キャッシュ作成 |
| bulk_sync_helm_metadata_cache_service.rb | `app/services/packages/helm/bulk_sync_helm_metadata_cache_service.rb` | サービス | キャッシュ一括同期 |
| packages_finder.rb | `app/finders/packages/helm/packages_finder.rb` | Finder | パッケージ検索 |
| extraction_worker.rb | `app/workers/packages/helm/extraction_worker.rb` | ワーカー | 非同期メタデータ抽出 |
| create_metadata_cache_worker.rb | `app/workers/packages/helm/create_metadata_cache_worker.rb` | ワーカー | 非同期キャッシュ作成 |
