# 機能設計書 37-Bitbucketバックエンド

## 概要

Bitbucket APIを使用したGitリポジトリ操作バックエンドについて記述する。Git LFSにも対応し、エントリの読み書き・メディア管理・エディトリアルワークフローをBitbucket上で実行する。

### 本機能の処理概要

BitbucketバックエンドはDecap CMSのImplementationインターフェースを実装するクラスで、Bitbucketリポジトリをデータストアとして使用する。Bitbucket APIを通じてコンテンツ操作を行い、Git LFS（Large File Storage）による大きなメディアファイルの管理もサポートする。

**業務上の目的・背景**：Atlassian Bitbucketを利用するチーム向けのCMSバックエンド。Bitbucketのエコシステム（Jira連携等）を活用しながら、コンテンツ管理を行える。

**機能の利用シーン**：config.ymlでbackend.name: 'bitbucket'と設定されている場合に使用。Atlassian Suite（Bitbucket + Jira + Confluence）を利用する組織での静的サイト管理に適している。

**主要な処理内容**：
1. OAuth認証（Implicit/PKCEフロー）とトークンリフレッシュ
2. エントリのフォルダ/ファイルベース読み込み
3. エントリの保存・削除（Git LFSフィルタリング付き）
4. メディアファイルの一覧取得・アップロード・削除（LFS対応）
5. エディトリアルワークフロー（PRベース）
6. Bitbucket APIステータス監視
7. アクセストークンの自動リフレッシュ

**関連システム・外部連携**：Bitbucket REST API（api.bitbucket.org/2.0）、Bitbucket Status API、Git LFS

**権限による制御**：リポジトリへの書き込み権限チェック。トークンリフレッシュ時の認証タイプ検証（implicitの場合はリフレッシュ不可）。

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| config.backend.repo | string | Yes | Bitbucketリポジトリ（workspace/repo形式） | 未設定時はエラー |
| config.backend.branch | string | No | ブランチ名（デフォルト: 'master'） | なし |
| config.backend.api_root | string | No | API Root（デフォルト: 'https://api.bitbucket.org/2.0'） | なし |
| config.backend.large_media_url | string | No | Git LFS URL | なし |
| config.backend.squash_merges | boolean | No | スカッシュマージ使用 | なし |
| config.backend.cms_label_prefix | string | No | CMSラベルのプレフィックス | なし |
| config.backend.auth_type | string | No | 認証タイプ（'implicit'等） | なし |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ 設定値の読み込み、asyncLock初期化、LFS URL設定
2. 認証
   ├─ トークン設定
   ├─ ブランチ未設定時はmainbranch.name取得
   ├─ refresh_token保存
   ├─ APIインスタンス生成
   ├─ 書き込み権限チェック
   └─ ユーザー情報返却（display_name→name, username→login, avatar_url変換）
3. トークンリフレッシュ
   ├─ auth_type='implicit'の場合はAccessTokenErrorスロー
   ├─ NetlifyAuthenticatorでrefreshを実行
   └─ 新トークンの保存とupdateUserCredentials呼び出し
4. API リクエスト
   ├─ Bearer トークンヘッダー付加
   ├─ 401レスポンス時にトークンリフレッシュして再リクエスト
   └─ レスポンス返却
5. エントリ操作
   ├─ entriesByFolder: defaultBranchCommitSha取得 → ファイル一覧 → エントリ読み込み
   └─ persistEntry: LargeMediaClient → フィルタリング → ロック付き保存
6. メディア操作
   ├─ persistMedia: LFS対応のpointer file生成
   └─ getLargeMediaClient: .gitattributesからパターン取得
```

### フローチャート

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

    H[APIリクエスト] --> I{401エラー?}
    I -->|Yes| J{access token expired?}
    J -->|Yes| K[getRefreshedAccessToken]
    K --> L[新トークンで再リクエスト]
    I -->|No| M[レスポンス返却]
    J -->|No| M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | Implicit認証制約 | auth_type='implicit'の場合、トークンリフレッシュは不可 | getRefreshedAccessToken時 |
| BR-37-02 | 自動トークンリフレッシュ | 401レスポンスかつaccess token expiredの場合、自動的にトークンをリフレッシュして再リクエスト | apiRequestFunction内 |
| BR-37-03 | Git LFSフィルタリング | .gitattributesのパターンに一致するファイルはLFS経由で処理 | persistEntry/persistMedia時 |
| BR-37-04 | ロック付き操作 | persist/update/delete/publishはrunWithLockで排他制御 | 書き込み操作時 |
| BR-37-05 | デフォルトブランチ | ブランチ未設定時はBitbucket APIからmainbranch.nameを取得 | authenticate時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| persistEntry | Bitbucketリポジトリ | CREATE/UPDATE | APIでファイルをコミット（LFSフィルタリング付き） |
| deleteFiles | Bitbucketリポジトリ | DELETE | コミットメッセージ付きでファイル削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 設定エラー | repoが未設定 | "The BitBucket backend needs a 'repo'" エラー |
| - | 認証エラー | 書き込み権限なし | "Your BitBucket user account does not have access" エラー |
| AccessTokenError | トークンエラー | implicit認証でリフレッシュ試行 | "Can't refresh access token when using implicit auth" |
| 401 | アクセストークン期限切れ | APIリクエストで401 + "access token expired" | 自動リフレッシュ＋再リクエスト |

### リトライ仕様

- アクセストークン期限切れ時に自動リフレッシュ＋再リクエスト

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

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

## パフォーマンス要件

- MAX_CONCURRENT_DOWNLOADS = 10
- allEntriesByFolderでlocalForageキャッシュと差分更新をサポート

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

- Bearer トークンによる認証
- リフレッシュトークンの安全な管理
- Git LFS URLの設定

## 備考

- Bitbucket Status APIで'API', 'Authentication and user management', 'Git LFS'の運用状態を監視
- LargeMediaClientは.gitattributesのパターンに基づいてLFS対象ファイルを判定

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | BitbucketBackendクラスのプロパティ（66-93行目）: lock, api, updateUserCredentials, refreshToken, authType等 |

#### Step 2: 認証とトークン管理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | authenticate（195-256行目）: トークン設定、ブランチ解決、API生成、ユーザー情報変換 |
| 2-2 | implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | getRefreshedAccessToken（258-288行目）: implicit認証チェック、NetlifyAuthenticator.refresh |
| 2-3 | implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | apiRequestFunction（303-324行目）: 401自動リフレッシュ |

**主要処理フロー**:
1. **195-256行目**: authenticate。ブランチ自動取得、API生成、display_name→name変換
2. **258-288行目**: getRefreshedAccessToken。implicit制約チェック、リフレッシュ実行
3. **303-324行目**: apiRequestFunction。401時のトークンリフレッシュ自動再試行

#### Step 3: Git LFS対応

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | getLargeMediaClient（407-430行目）: .gitattributesパターン取得、GitLfsClient生成 |
| 3-2 | git-lfs-client.ts | `packages/decap-cms-backend-bitbucket/src/git-lfs-client.ts` | Git LFSクライアント実装 |

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

```
BitbucketBackend (implementation.ts)
    │
    ├─ authenticate(state)
    │      ├─ Bitbucket API: mainbranch.name取得
    │      ├─ new API(config)
    │      ├─ api.hasWriteAccess()
    │      └─ api.user()
    │
    ├─ apiRequestFunction(req)
    │      ├─ Bearer {token} ヘッダー付加
    │      └─ [401] getRefreshedAccessToken() → 再リクエスト
    │
    ├─ persistEntry(entry, options)
    │      ├─ getLargeMediaClient()
    │      │      └─ .gitattributes → GitLfsClient
    │      ├─ getLargeMediaFilteredMediaFiles(client, assets)
    │      └─ runWithLock(() => api.persistFiles(...))
    │
    └─ persistMedia(mediaFile, options)
           ├─ getLargeMediaClient()
           ├─ client.matchPath(fixedPath)
           └─ getPointerFileForMediaFileObj(client, fileObj, path)
```

### データフロー図

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

config.yml            ─▶ Bitbucket constructor        ─▶ Bitbucket instance
  backend:                                                ├─ api
    name: bitbucket                                       ├─ largeMediaURL
    repo: workspace/repo                                  └─ authType

OAuth Token           ─▶ authenticate()              ─▶ User { name, login,
  + refresh_token         ├─ API生成                       avatar_url, token,
                          └─ ユーザー情報変換                 refresh_token }

API Request           ─▶ apiRequestFunction()        ─▶ Response
  (任意のリクエスト)        └─ [401] auto-refresh          └─ [リフレッシュ後の再応答]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| implementation.ts | `packages/decap-cms-backend-bitbucket/src/implementation.ts` | ソース | BitbucketバックエンドのImplementation実装 |
| API.ts | `packages/decap-cms-backend-bitbucket/src/API.ts` | ソース | Bitbucket REST API操作 |
| git-lfs-client.ts | `packages/decap-cms-backend-bitbucket/src/git-lfs-client.ts` | ソース | Git LFSクライアント |
| AuthenticationPage.js | `packages/decap-cms-backend-bitbucket/src/AuthenticationPage.js` | ソース | Bitbucket認証画面コンポーネント |
| index.ts | `packages/decap-cms-backend-bitbucket/src/index.ts` | ソース | パッケージエントリーポイント |
