# 機能設計書 38-Git Gatewayバックエンド

## 概要

Netlify Git Gatewayを経由したGitHub/GitLab/Bitbucketリポジトリ操作バックエンドについて記述する。Netlify Identityとの統合およびPKCE認証もサポートし、Netlify Large Mediaにも対応する。

### 本機能の処理概要

Git Gatewayバックエンドは、Netlifyが提供するGit GatewayサービスをプロキシとしてGitHub/GitLab/Bitbucketリポジトリを操作するバックエンドである。ユーザーはGitプロバイダのアカウントを持つ必要がなく、Netlify Identity（メール/パスワード認証）またはPKCE OAuthで認証できる。内部的にはGitHub/GitLab/Bitbucketの各バックエンドに処理を委譲する。

**業務上の目的・背景**：Netlifyでホスティングされている静的サイトのCMS管理において、コンテンツ編集者がGitHub等のアカウントを持たなくてもCMSを利用できるようにする。Netlify Identityによるユーザー管理とロールベースのアクセス制御を提供する。

**機能の利用シーン**：config.ymlでbackend.name: 'git-gateway'と設定されている場合に使用。Netlifyでデプロイされたサイトでの利用が主なユースケース。

**主要な処理内容**：
1. Netlify Identity認証またはPKCE OAuth認証
2. Git Gatewayの設定取得（GitHub/GitLab/Bitbucket判定）
3. JWTトークンのロールベースアクセス制御
4. 内部バックエンド（GitHub/GitLab/Bitbucket）の動的初期化と委譲
5. Netlify Large Media対応（.lfsconfig/.gitattributes解析）
6. デプロイプレビュー（Netlify API経由のフォールバック）
7. Git Gatewayステータス監視

**関連システム・外部連携**：Netlify Identity API、Netlify Git Gateway API、Netlify Large Media API、Netlify Deploy API

**権限による制御**：JWTのapp_metadata.rolesとacceptRoles設定によるロールベースアクセス制御。hasWriteAccessによる書き込み権限確認。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ログイン画面 | 主機能 | Netlify Identity経由またはPKCE OAuthでのログイン |

## 機能種別

データ連携 / プロキシ / 認証管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| config.backend.identity_url | string | No | Identity API URL（デフォルト: '/.netlify/identity'） | なし |
| config.backend.gateway_url | string | No | Gateway API URL（デフォルト: '/.netlify/git'） | なし |
| config.backend.large_media_url | string | No | Large Media URL（デフォルト: '/.netlify/large-media'） | なし |
| config.backend.auth_type | string | No | 認証タイプ（'pkce'またはNetlify Identity） | なし |
| config.backend.branch | string | No | ブランチ名（デフォルト: 'master'） | なし |
| config.backend.squash_merges | boolean | No | スカッシュマージ使用 | なし |
| config.backend.status_endpoint | string | No | ステータスエンドポイント | なし |
| config.backend.use_large_media_transforms_in_media_library | boolean | No | Large Media変換有効化（デフォルト: true） | なし |

### 入力データソース

- config.yml（バックエンド設定）
- Netlify Identity API（ユーザー情報）
- Netlify Git Gateway API（リポジトリ設定）
- localStorage（netlifySiteURL）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| user | User | 認証ユーザー情報（name、email/login、avatar_url） |
| entries | ImplementationEntry[] | 内部バックエンド経由のエントリデータ |
| media | MediaFile[] | メディアファイル（Large Media含む） |

### 出力先

- 内部バックエンド（GitHub/GitLab/Bitbucket）経由でGitリポジトリ

## 処理フロー

### 処理シーケンス

```
1. 初期化
   ├─ エンドポイントURL解決（ローカル開発時のnetlifySiteURL考慮）
   ├─ gateway URLからバックエンドタイプ検出（github/gitlab/bitbucket）
   └─ 認証タイプ判定（pkce or netlify）
2. 認証
   ├─ Netlify Identity: JWTトークン取得
   │   └─ user.jwt()メソッド経由
   ├─ PKCE OAuth: トークン文字列取得
   ├─ バックエンドタイプ未確定の場合
   │   └─ gatewayUrl/settings取得でgithub_enabled/gitlab_enabled/bitbucket_enabled判定
   ├─ ロールチェック（acceptRoles && JWTのapp_metadata.roles）
   ├─ 内部バックエンドのAPI・Backendインスタンス生成
   │   ├─ GitHub: GitHubAPI + GitHubBackend
   │   ├─ GitLab: GitLabAPI + GitLabBackend
   │   └─ Bitbucket: BitBucketAPI + BitbucketBackend
   └─ hasWriteAccess確認
3. 操作（すべて内部バックエンドに委譲）
   ├─ entriesByFolder/entriesByFiles/getEntry
   ├─ getMedia/getMediaDisplayURL/getMediaFile
   │   └─ Large Media対応: isLargeMediaFile判定
   ├─ persistEntry（Large Mediaフィルタリング付き）
   ├─ persistMedia（Large Mediaポインターファイル対応）
   └─ ワークフロー操作
4. デプロイプレビュー
   ├─ 内部バックエンドのgetDeployPreview
   └─ フォールバック: Netlify API直接アクセス（公開ログのみ）
```

### フローチャート

```mermaid
flowchart TD
    A[Git Gateway初期化] --> B{auth_type?}
    B -->|pkce| C[PKCEAuthenticationPage]
    B -->|netlify| D[NetlifyAuthenticationPage]
    C --> E[authenticate]
    D --> E
    E --> F{backendType確定?}
    F -->|No| G[Gateway /settings取得]
    G --> H{enabled判定}
    H -->|github| I[GitHubAPI + GitHubBackend]
    H -->|gitlab| J[GitLabAPI + GitLabBackend]
    H -->|bitbucket| K[BitBucketAPI + BitbucketBackend]
    F -->|Yes| L{backendType}
    L -->|github| I
    L -->|gitlab| J
    L -->|bitbucket| K
    I --> M[hasWriteAccess]
    J --> M
    K --> M
    M --> N[User返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | ロールベースアクセス制御 | acceptRolesが設定されている場合、JWTのapp_metadata.rolesとの交差を確認 | acceptRolesが設定されている場合 |
| BR-38-02 | バックエンドタイプ自動検出 | gateway URLの末尾から、または/settingsのレスポンスからbackendTypeを判定 | backendTypeが未確定時 |
| BR-38-03 | ローカル開発対応 | localhost/127.0.0.1/0.0.0.0の場合、netlifySiteURLを使用してエンドポイントを構築 | ローカルホスト時 |
| BR-38-04 | Large Media判定 | .lfsconfig + .gitattributesを解析し、Netlify Large Media対応を判定 | メディア操作時 |
| BR-38-05 | Large Media変換 | transformImages有効時、プレビューにnf_resize: 'fit', w: 560, h: 320を適用 | メディアライブラリ表示時 |
| BR-38-06 | デプロイプレビューフォールバック | 内部バックエンドのプレビューがnullの場合、Netlify API直接アクセスで取得 | getDeployPreview時 |
| BR-38-07 | Identity初期化タイムアウト | Netlify Identity Widgetの初期化を2.5秒タイムアウトで待機 | 初期化時 |

### 計算ロジック

特になし

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

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

内部バックエンド（GitHub/GitLab/Bitbucket）に委譲。各バックエンドの設計書を参照。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | APIError | Git Gateway settingsが有効なJSONを返さない | "Your Git Gateway backend is not returning valid settings" |
| - | APIError | Git Gatewayからのエラーレスポンス | "Git Gateway Error: {message}" |
| - | 権限エラー | ロールチェック失敗 | "You don't have sufficient permissions to access Decap CMS" |
| AccessTokenError | トークンエラー | JWT取得失敗 | "Failed getting access token: {error}" |

### リトライ仕様

特になし（内部バックエンドのリトライ機構に依存）

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

内部バックエンドの排他制御に委譲

## パフォーマンス要件

- Netlify Identity Widget初期化のタイムアウト: 2.5秒
- Large Media: 画像変換パラメータ（560x320 fit）

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

- JWTトークンにロール情報を含む（app_metadata.roles）
- GoTrueライブラリによるIdentity管理
- Large Media用の.lfsconfig解析でNetlifyドメイン確認

## 備考

- Git Gatewayは他のバックエンド（GitHub/GitLab/Bitbucket）のファサードとして機能
- window.netlifyIdentityが存在する場合はIdentity Widgetを使用
- Netlify API経由のデプロイプレビューは公開ログのみ対応（プライベートログは未対応）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | implementation.ts | `packages/decap-cms-backend-git-gateway/src/implementation.ts` | GitGatewayクラスのプロパティ（137-161行目）: config, api, backendType, authType, backend, authClient等。GitGatewayUser型（125-129行目）: jwt関数とメタデータ |

#### Step 2: 初期化と認証フロー

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | implementation.ts | `packages/decap-cms-backend-git-gateway/src/implementation.ts` | コンストラクタ（162-201行目）: エンドポイントURL構築、backendType検出、authType判定 |
| 2-2 | implementation.ts | `packages/decap-cms-backend-git-gateway/src/implementation.ts` | authenticate（279-387行目）: JWT/OAuthトークン取得、settings取得、ロールチェック、内部バックエンド生成 |

**主要処理フロー**:
1. **162-201行目**: コンストラクタ。getEndpointでURL構築、backendTypeの正規表現マッチ
2. **279-294行目**: authenticate。Netlify JWT / OAuthトークン取得
3. **296-336行目**: backendType未確定時のsettings取得とバックエンドタイプ判定
4. **338-344行目**: ロールチェック（JWTデコード + intersectionによる交差判定）
5. **363-376行目**: 内部バックエンドのAPI・Backendインスタンス生成（GitHub/GitLab/Bitbucket分岐）

#### Step 3: Large Media対応

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | implementation.ts | `packages/decap-cms-backend-git-gateway/src/implementation.ts` | _getLargeMediaClient（466-506行目）: .lfsconfig + .gitattributes解析 |
| 3-2 | netlify-lfs-client.ts | `packages/decap-cms-backend-git-gateway/src/netlify-lfs-client.ts` | Netlify Large Mediaクライアント |

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

```
GitGateway (implementation.ts)
    │
    ├─ authenticate(credentials)
    │      ├─ tokenPromise (JWT / OAuth)
    │      ├─ gatewayUrl/settings [backendType判定]
    │      ├─ jwtDecode → ロールチェック
    │      └─ 内部バックエンド生成
    │            ├─ [github] GitHubAPI + GitHubBackend
    │            ├─ [gitlab] GitLabAPI + GitLabBackend
    │            └─ [bitbucket] BitBucketAPI + BitbucketBackend
    │
    ├─ entriesByFolder/entriesByFiles/getEntry
    │      └─ backend.entriesByFolder/entriesByFiles/getEntry (委譲)
    │
    ├─ getMediaDisplayURL(displayURL)
    │      ├─ isLargeMediaFile(path)
    │      │      └─ getLargeMediaClient().matchPath(path)
    │      ├─ [LargeMedia] getLargeMediaDisplayURL()
    │      └─ [通常] backend.getMediaDisplayURL()
    │
    ├─ persistEntry(entry, options)
    │      ├─ getLargeMediaClient()
    │      │      └─ getLargeMediaFilteredMediaFiles()
    │      └─ backend.persistEntry()
    │
    └─ getDeployPreview(collection, slug)
           ├─ backend.getDeployPreview()
           └─ [フォールバック] Netlify API直接アクセス
```

### データフロー図

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

Netlify Identity      ─▶ authenticate()              ─▶ User { name, email }
  JWT/OAuth               ├─ settings取得
                          ├─ ロールチェック
                          └─ 内部バックエンド生成

メディアパス           ─▶ isLargeMediaFile()          ─▶ boolean
                          ├─ .lfsconfig解析
                          └─ .gitattributesパターンマッチ

エントリ保存           ─▶ persistEntry()              ─▶ Git commit
                          ├─ Large Media フィルタリング
                          └─ backend.persistEntry()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| implementation.ts | `packages/decap-cms-backend-git-gateway/src/implementation.ts` | ソース | Git GatewayバックエンドのImplementation実装 |
| GitHubAPI.ts | `packages/decap-cms-backend-git-gateway/src/GitHubAPI.ts` | ソース | Git Gateway経由のGitHub API |
| GitLabAPI.ts | `packages/decap-cms-backend-git-gateway/src/GitLabAPI.ts` | ソース | Git Gateway経由のGitLab API |
| netlify-lfs-client.ts | `packages/decap-cms-backend-git-gateway/src/netlify-lfs-client.ts` | ソース | Netlify Large Mediaクライアント |
| index.ts | `packages/decap-cms-backend-git-gateway/src/index.ts` | ソース | パッケージエントリーポイント |
