# 機能設計書 36-GitLabバックエンド

## 概要

GitLab APIを使用したGitリポジトリ操作バックエンドについて記述する。REST APIに加えGraphQL APIオプションもサポートし、エントリの読み書き・メディア管理・エディトリアルワークフローをGitLab上で実行する。

### 本機能の処理概要

GitLabバックエンドは、Decap CMSのImplementationインターフェースを実装するクラスで、GitLabリポジトリをCMSのデータストアとして使用する。GitLab APIを通じてコンテンツファイルの読み書き、メディアファイルの管理、MRベースのエディトリアルワークフローを提供する。

**業務上の目的・背景**：GitLabはオンプレミスでも利用可能なGitプラットフォームであり、セルフホスティング環境でのCMS運用に適している。GitLabバックエンドにより、GitLabリポジトリ上のコンテンツを非技術者が管理できるようになる。

**機能の利用シーン**：config.ymlでbackend.name: 'gitlab'と設定されている場合に使用。カスタムGitLabインスタンス（api_root指定）にも対応。

**主要な処理内容**：
1. OAuth認証とトークンベース認証
2. エントリのフォルダ/ファイルベース読み込み（カーソルベースページネーション）
3. エントリの保存・削除
4. メディアファイルの一覧取得・アップロード・削除
5. エディトリアルワークフロー（MRベース）
6. GraphQL APIによる一括ファイル読み込み
7. デフォルトブランチの自動検出

**関連システム・外部連携**：GitLab REST API（gitlab.com/api/v4）、GitLab GraphQL API

**権限による制御**：リポジトリへの書き込み権限チェック（hasWriteAccess）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ログイン画面 | 主機能 | GitLab OAuth認証によるログイン |

## 機能種別

データ連携 / CRUD操作 / 外部API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| config.backend.repo | string | Yes | GitLabリポジトリ（namespace/project形式） | 未設定時はエラー |
| config.backend.branch | string | No | ブランチ名（デフォルト: 'master'） | なし |
| config.backend.api_root | string | No | API Root（デフォルト: 'https://gitlab.com/api/v4'） | なし |
| config.backend.squash_merges | boolean | No | スカッシュマージ使用 | なし |
| config.backend.use_graphql | boolean | No | GraphQL API使用 | なし |
| config.backend.graphql_api_root | string | No | GraphQL API Root（デフォルト: 'https://gitlab.com/api/graphql'） | なし |
| config.backend.cms_label_prefix | string | No | CMSラベルのプレフィックス | なし |
| config.backend.preview_context | string | No | デプロイプレビューのコンテキスト | なし |

### 入力データソース

- config.yml（バックエンド設定）
- GitLab API（リポジトリデータ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| entries | ImplementationEntry[] | エントリデータ |
| media | MediaFile[] | メディアファイル一覧 |
| user | User | 認証ユーザー情報（username→login変換） |

### 出力先

- Reduxストア経由でUI表示
- GitLab API（保存時）

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ 設定値の読み込み、asyncLock初期化
2. 認証
   ├─ トークン設定、APIインスタンス生成
   ├─ ユーザー情報取得（username→loginマッピング）
   ├─ 書き込み権限チェック
   └─ ブランチ未設定時はデフォルトブランチ名取得（getDefaultBranchName）
3. エントリ操作
   ├─ entriesByFolder: カーソル付きページネーション読み込み
   ├─ allEntriesByFolder: GraphQL対応の一括読み込み
   ├─ entriesByFiles: ファイル指定読み込み
   └─ persistEntry: ロック付き保存
4. メディア操作
   ├─ getMedia: 全ファイル一覧取得
   └─ persistMedia: SHA計算付きアップロード
5. ワークフロー操作
   └─ MRベースのステータス管理
```

### フローチャート

```mermaid
flowchart TD
    A[GitLab Backend初期化] --> B[authenticate]
    B --> C[API生成]
    C --> D[api.user]
    D --> E[api.hasWriteAccess]
    E --> F{ブランチ未設定?}
    F -->|Yes| G[getDefaultBranchName]
    F -->|No| H[ユーザー情報返却]
    G --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | パスフィルタリング | GitLabパスはルートフォルダを含むため、filterFileでフォルダパスとdepthを考慮したフィルタリング | entriesByFolder時 |
| BR-36-02 | ユーザー名マッピング | GitLabのusernameをloginフィールドにマッピング | authenticate返却時 |
| BR-36-03 | GraphQL一括読み込み | useGraphQL有効時はreadFilesGraphQLでファイルを一括取得 | allEntriesByFolder時 |
| BR-36-04 | ロック付き操作 | persist/update/delete/publishはrunWithLockで排他制御 | 書き込み操作時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| persistEntry | GitLabリポジトリ | CREATE/UPDATE | コミットAPIでファイルを保存 |
| deleteFiles | GitLabリポジトリ | DELETE | コミットAPIでファイル削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 設定エラー | repoが未設定 | "The GitLab backend needs a 'repo'" エラー |
| - | 認証エラー | 書き込み権限なし | "Your GitLab user account does not have access" エラー |
| - | リポジトリエラー | リポジトリが見つからない | 詳細なエラーメッセージ |

### リトライ仕様

特になし

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

asyncLock（runWithLock）によるCMSレベルの排他制御

## パフォーマンス要件

- MAX_CONCURRENT_DOWNLOADS = 10
- GraphQL使用時は一括ファイル取得でAPI呼び出し数を削減

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

- OAuthトークンによる認証
- カスタムGitLabインスタンスのAPI Rootとして任意のURLを指定可能

## 備考

- GitLabのallEntriesByFolderではlocalForageキャッシュとisShaExistsInBranchによる差分更新をサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | implementation.ts | `packages/decap-cms-backend-gitlab/src/implementation.ts` | GitLabクラスのプロパティ（48-68行目）: lock, api, options, repo, branch等の型定義 |

#### Step 2: エントリーポイント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | implementation.ts | `packages/decap-cms-backend-gitlab/src/implementation.ts` | コンストラクタ（70-99行目）: 設定読み込み。authenticate（126-169行目）: 認証とAPI初期化 |

**主要処理フロー**:
1. **70-99行目**: コンストラクタ。repo, branch, apiRoot, useGraphQL等の設定
2. **126-169行目**: authenticate。API生成、ユーザー情報取得、hasWriteAccess、デフォルトブランチ取得
3. **180-189行目**: filterFile。GitLabのパス仕様に合わせたフィルタリング
4. **191-210行目**: entriesByFolder。カーソル付きページネーション
5. **218-239行目**: allEntriesByFolder。GraphQL対応の一括読み込み
6. **293-300行目**: persistEntry。runWithLock付き保存

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

```
GitLab (implementation.ts)
    │
    ├─ authenticate(state)
    │      ├─ new API(config)
    │      ├─ api.user()
    │      ├─ api.hasWriteAccess()
    │      └─ getDefaultBranchName()
    │
    ├─ entriesByFolder(folder, extension, depth)
    │      ├─ api.listFiles(folder, depth > 1)
    │      ├─ filterFile()
    │      └─ entriesByFolder(listFiles, readFile, ...)
    │
    ├─ allEntriesByFolder(folder, extension, depth)
    │      └─ allEntriesByFolder({ ... customFetch: api.readFilesGraphQL })
    │
    └─ persistEntry(entry, options)
           └─ runWithLock(() => api.persistFiles(...))
```

### データフロー図

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

config.yml            ─▶ GitLab constructor           ─▶ GitLab instance
  backend:
    name: gitlab
    repo: namespace/project

OAuth Token           ─▶ authenticate()              ─▶ User { login: username }

folder, extension     ─▶ entriesByFolder()           ─▶ entries[] + cursor
                          ├─ api.listFiles()
                          ├─ filterFile()
                          └─ api.readFile()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| implementation.ts | `packages/decap-cms-backend-gitlab/src/implementation.ts` | ソース | GitLabバックエンドのImplementation実装 |
| API.ts | `packages/decap-cms-backend-gitlab/src/API.ts` | ソース | GitLab REST/GraphQL API操作 |
| queries.ts | `packages/decap-cms-backend-gitlab/src/queries.ts` | ソース | GraphQLクエリ定義 |
| AuthenticationPage.js | `packages/decap-cms-backend-gitlab/src/AuthenticationPage.js` | ソース | GitLab認証画面コンポーネント |
| index.ts | `packages/decap-cms-backend-gitlab/src/index.ts` | ソース | パッケージエントリーポイント |
