# 機能設計書 13-Local API

## 概要

本ドキュメントは、Payload CMSにおけるLocal API機能の設計を定義する。サーバーサイドから直接Payloadを操作するためのプログラマティックなインターフェースを提供し、フック、カスタムエンドポイント、バックグラウンドジョブなどでのデータ操作を実現する。

### 本機能の処理概要

Local APIは、HTTPリクエストを介さずにPayload CMSのデータ操作を行うためのNode.js関数群である。REST APIやGraphQL APIと同じビジネスロジック（Operations層）を共有しながら、サーバーサイドコードから直接呼び出すことができる。

**業務上の目的・背景**：Webアプリケーションのサーバーサイドでは、HTTPオーバーヘッドなしにデータ操作を行いたいケースが多い。特にカスタムフック内での関連データ操作、バックグラウンドジョブでのバッチ処理、サーバーサイドレンダリング時のデータ取得などで、Local APIは効率的なデータアクセス手段を提供する。また、`overrideAccess`オプションにより、アクセス制御をバイパスした管理者権限での操作が可能。

**機能の利用シーン**：
- カスタムフック内での関連ドキュメント操作
- サーバーサイドレンダリング（SSR）でのデータ取得
- カスタムAPIエンドポイントでのデータ操作
- バックグラウンドジョブ、CRONタスクでのバッチ処理
- シード処理、マイグレーションスクリプト
- 外部システムからのWebhook処理

**主要な処理内容**：
1. コレクション操作：create、find、findByID、update、delete、count、duplicate
2. グローバル操作：findOne、update
3. バージョン操作：findVersions、findVersionByID、restoreVersion
4. リクエストコンテキスト生成：createLocalReqによるPayloadRequest生成
5. トランザクション管理：既存トランザクションの引き継ぎ

**関連システム・外部連携**：
- Operations層（REST API、GraphQL APIと共通）
- データベースアダプター
- フック機能（beforeChange、afterRead等）
- トランザクション管理

**権限による制御**：
- `overrideAccess`オプション（デフォルト: true）でアクセス制御をバイパス
- `overrideAccess: false`指定時は`user`オプションでユーザーを指定可能
- フィールドレベルのアクセス制御も適用可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （該当なし） | - | サーバーサイド専用APIのため画面連携なし |

## 機能種別

CRUD操作 / サーバーサイドAPI

## 入力仕様

### 入力パラメータ

#### 共通パラメータ（全操作）

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| collection | CollectionSlug | Yes | 操作対象のコレクションslug | - |
| overrideAccess | boolean | No | アクセス制御をバイパスするか | true |
| context | RequestContext | No | フックに渡すコンテキストオブジェクト | {} |
| req | Partial<PayloadRequest> | No | 既存のリクエストオブジェクト（トランザクション引継用） | - |
| user | Document | No | アクセス制御に使用するユーザー | - |
| locale | TypedLocale | No | ロケール指定 | defaultLocale |
| fallbackLocale | TypedLocale / false | No | フォールバックロケール | - |
| depth | number | No | リレーション展開深度 | - |
| populate | PopulateType | No | 展開するリレーション指定 | - |
| select | SelectType | No | 取得するフィールド選択 | - |
| showHiddenFields | boolean | No | 隠しフィールドを表示 | false |

#### create（作成）固有パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| data | RequiredDataFromCollectionSlug | Yes | 作成するドキュメントデータ | - |
| draft | boolean | No | ドラフトとして作成 | false |
| file | File | No | アップロードファイル | - |
| filePath | string | No | ファイルパス | - |
| disableTransaction | boolean | No | トランザクション無効化 | false |
| disableVerificationEmail | boolean | No | 認証メール無効化 | false |
| duplicateFromID | string/number | No | 複製元ドキュメントID | - |
| overwriteExistingFiles | boolean | No | 既存ファイル上書き | false |
| publishAllLocales | boolean | No | 全ロケール公開 | - |

#### find（一覧取得）固有パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| where | Where | No | フィルタ条件 | - |
| sort | Sort | No | ソート条件 | - |
| limit | number | No | 取得件数上限 | 10 |
| page | number | No | ページ番号 | 1 |
| pagination | boolean | No | ページネーション有効化 | true |
| draft | boolean | No | ドラフトを含める | false |
| trash | boolean | No | ゴミ箱を含める | false |
| joins | JoinQuery | No | JOIN設定 | - |
| includeLockStatus | boolean | No | ロック状態を含める | - |
| disableErrors | boolean | No | エラーを無効化 | false |

#### findByID（ID指定取得）固有パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| id | string/number | Yes | ドキュメントID | - |
| data | object | No | DBクエリをスキップしてデータを直接渡す | - |
| disableErrors | boolean | No | エラーを無効化（見つからない場合null返却） | false |
| flattenLocales | boolean | No | ロケールをフラット化 | - |
| draft | boolean | No | ドラフトを含める | false |
| trash | boolean | No | ゴミ箱のドキュメントを含める | false |

#### update（更新）固有パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| id | string/number | Conditional | 更新対象のドキュメントID（単一更新時） | - |
| where | Where | Conditional | フィルタ条件（一括更新時） | - |
| data | DeepPartial | Yes | 更新データ | - |
| autosave | boolean | No | 自動保存モード | false |
| draft | boolean | No | ドラフトとして保存 | - |
| overrideLock | boolean | No | ロックを無視 | true |
| unpublishAllLocales | boolean | No | 全ロケール非公開 | - |

### 入力データソース

- Node.js関数呼び出し（プログラマティック）
- PayloadRequest経由のトランザクションコンテキスト

## 出力仕様

### 出力データ

#### 単一ドキュメント取得・作成・更新時

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (ドキュメント) | TransformCollectionWithSelect | ドキュメントオブジェクト |

#### 一覧取得時（PaginatedDocs）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| docs | array | ドキュメント配列 |
| totalDocs | number | 総ドキュメント数 |
| limit | number | 取得件数上限 |
| totalPages | number | 総ページ数 |
| page | number | 現在のページ番号 |
| pagingCounter | number | ページングカウンター |
| hasPrevPage | boolean | 前ページ存在フラグ |
| hasNextPage | boolean | 次ページ存在フラグ |
| prevPage | number/null | 前ページ番号 |
| nextPage | number/null | 次ページ番号 |

#### 一括更新・削除時（BulkOperationResult）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| docs | array | 処理されたドキュメント配列 |
| errors | array | エラー配列 |

### 出力先

- 関数戻り値（Promise）
- 例外（APIError等）

## 処理フロー

### 処理シーケンス

```
1. Local API関数呼び出し
   └─ payload.create/find/update/delete等

2. オプション解析
   └─ collection, overrideAccess, context等を抽出

3. コレクション存在確認
   └─ payload.collections[collectionSlug]の存在チェック

4. createLocalReqでリクエスト生成
   └─ PayloadRequestオブジェクトを構築
   └─ locale、fallbackLocale、user、context等を設定
   └─ 既存のreqからtransactionIDを引き継ぎ

5. ファイル処理（アップロード時）
   └─ fileまたはfilePathからFileオブジェクトを取得

6. Operations層呼び出し
   └─ createOperation/findOperation等を呼び出し
   └─ REST API、GraphQL APIと同じビジネスロジックを実行

7. 結果返却
   └─ ドキュメントまたはPaginatedDocsを返却
```

### フローチャート

```mermaid
flowchart TD
    A[Local API関数呼び出し] --> B[オプション解析]
    B --> C{コレクション存在?}
    C -->|No| D[APIError送出]
    C -->|Yes| E[createLocalReq実行]
    E --> F{ファイルあり?}
    F -->|Yes| G[ファイル処理]
    F -->|No| H[Operations層呼び出し]
    G --> H
    H --> I[結果返却]
    D --> J[例外終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトアクセスバイパス | overrideAccessのデフォルトはtrue | 全操作 |
| BR-02 | payloadAPI識別子 | req.payloadAPIは'local'に設定 | 全操作 |
| BR-03 | トランザクション引継ぎ | reqを渡すとtransactionIDが引き継がれる | req指定時 |
| BR-04 | データディープコピー | createでdataをディープコピーしてフックの変更から保護 | create操作 |
| BR-05 | ロケールデフォルト | locale未指定時はdefaultLocaleを使用 | localization有効時 |
| BR-06 | ファイルパス解決 | filePathからFileオブジェクトを自動生成 | filePath指定時 |
| BR-07 | ID指定/WHERE指定分岐 | updateでid指定時はupdateByID、where指定時はupdateを実行 | update操作 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createLocal | {collection} | INSERT | createOperationを呼び出し |
| findLocal | {collection} | SELECT | findOperationを呼び出し |
| findByIDLocal | {collection} | SELECT | findByIDOperationを呼び出し |
| updateLocal (id) | {collection} | UPDATE | updateByIDOperationを呼び出し |
| updateLocal (where) | {collection} | UPDATE | updateOperationを呼び出し（一括） |
| deleteLocal (id) | {collection} | DELETE | deleteByIDOperationを呼び出し |
| deleteLocal (where) | {collection} | DELETE | deleteOperationを呼び出し（一括） |
| countLocal | {collection} | SELECT | countOperationを呼び出し |
| duplicateLocal | {collection} | INSERT | duplicateOperationを呼び出し |

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

Operations層に委譲するため、詳細はREST API機能設計書を参照。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| APIError | コレクション不存在 | 指定したcollectionSlugが存在しない | コレクションslugを確認 |
| NotFound | ドキュメント不存在 | findByIDで指定IDが存在しない（disableErrors=false時） | IDを確認またはdisableErrors=trueを指定 |
| Forbidden | 権限エラー | overrideAccess=falseでアクセス権限なし | 権限を確認またはoverrideAccess=trueを指定 |
| ValidationError | バリデーションエラー | 必須フィールド未入力等 | データを確認 |

### リトライ仕様

Local APIにはビルトインのリトライ機能はない。呼び出し元でのリトライ実装が必要。

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

- `req`パラメータを渡すことで、既存トランザクションを引き継ぎ可能
- `disableTransaction: true`でトランザクションを無効化可能
- フック内でLocal APIを呼び出す場合、`req`を渡すことで同一トランザクション内で実行

```typescript
// フック内でのトランザクション引き継ぎ例
const beforeChangeHook = async ({ req, data }) => {
  await payload.update({
    collection: 'related-collection',
    id: data.relatedId,
    data: { status: 'updated' },
    req, // トランザクションを引き継ぎ
  })
  return data
}
```

## パフォーマンス要件

- HTTPオーバーヘッドがないため、REST API/GraphQL APIより低レイテンシ
- `select`パラメータによる不要フィールド除外でメモリ使用量削減
- `pagination: false`で全件取得時は`limit`を併用してメモリ使用量を制御

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

- `overrideAccess: true`（デフォルト）は管理者権限相当のため、信頼できるサーバーサイドコードでのみ使用
- フロントエンド向けデータ取得時は`overrideAccess: false`を指定
- `user`パラメータで適切なユーザーを指定してアクセス制御を適用

## 備考

- Local APIは`payload`インスタンスのメソッドとして提供される
- `payload.create`、`payload.find`等のエイリアスでも呼び出し可能
- TypeScript型推論により、コレクション固有の型が適用される

---

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

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

### 推奨読解順序

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

まず、Local APIで使用されるオプション型とPayloadRequestの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | create.ts | `packages/payload/src/collections/operations/local/create.ts` | BaseOptions、Options型の定義（32-184行目） |
| 1-2 | find.ts | `packages/payload/src/collections/operations/local/find.ts` | BaseFindOptions型の定義（32-181行目） |
| 1-3 | createLocalReq.ts | `packages/payload/src/utilities/createLocalReq.ts` | CreateLocalReqOptions型（88-96行目） |

**読解のコツ**: Options型はジェネリクスを多用しており、`TSlug`でコレクションslug、`TSelect`でフィールド選択を型安全に扱う。`DraftFlagFromCollectionSlug`等の条件型でドラフト機能の有無に応じた型制御を行う。

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

Local API関数のエントリーポイントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | create.ts | `packages/payload/src/collections/operations/local/create.ts` | createLocal関数（186-239行目） |
| 2-2 | find.ts | `packages/payload/src/collections/operations/local/find.ts` | findLocal関数（190-254行目） |
| 2-3 | findByID.ts | `packages/payload/src/collections/operations/local/findByID.ts` | findByIDLocal関数（127-179行目） |
| 2-4 | update.ts | `packages/payload/src/collections/operations/local/update.ts` | updateLocal関数（197-294行目） |

**主要処理フロー**（create.ts createLocal）:
- **193-209行目**: オプションのデストラクチャリング、`overrideAccess`デフォルト値設定
- **211行目**: `payload.collections[collectionSlug]`でコレクション取得
- **213-217行目**: コレクション不存在時はAPIError送出
- **219行目**: `createLocalReq`でPayloadRequestを生成
- **221行目**: `file`または`filePath`からFileオブジェクトを取得
- **223-238行目**: `createOperation`を呼び出し（データはディープコピー）

#### Step 3: リクエスト生成処理を理解する

createLocalReq関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | createLocalReq.ts | `packages/payload/src/utilities/createLocalReq.ts` | createLocalReq関数（100-163行目） |

**主要処理フロー**（createLocalReq.ts）:
- **112-129行目**: ローカリゼーション設定時のlocale/fallbackLocale処理
- **131-133行目**: i18nの取得（req.i18nまたは新規生成）
- **135-137行目**: headersがない場合は新規Headers()を生成
- **139-140行目**: context設定、`payloadAPI`を'local'に設定
- **141-144行目**: payload、i18n、t、userを設定
- **148-150行目**: user.collectionが未設定の場合はadmin.userを設定
- **152-154行目**: payloadDataLoader、routeParams、queryを設定
- **156-158行目**: depthパラメータをreq.queryに反映
- **160行目**: `attachFakeURLProperties`でURL関連プロパティを設定

#### Step 4: Operations層との接続を理解する

Local APIからOperations層への呼び出しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | create.ts (operations) | `packages/payload/src/collections/operations/create.ts` | createOperation関数 |
| 4-2 | find.ts (operations) | `packages/payload/src/collections/operations/find.ts` | findOperation関数 |

**主要処理フロー**（update.ts updateLocal）:
- **286-291行目**: `options.id`の有無で`updateByIDOperation`または`updateOperation`を分岐呼び出し

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

```
payload.create() / payload.find() / payload.update() / payload.delete()
    │
    └─ collections/operations/local/create.ts (createLocal)
           │
           ├─ payload.collections[collectionSlug] (コレクション取得)
           │
           ├─ createLocalReq() (リクエスト生成)
           │      ├─ locale/fallbackLocale設定
           │      ├─ payloadAPI = 'local'
           │      ├─ user設定
           │      ├─ context設定
           │      └─ attachFakeURLProperties()
           │
           ├─ getFileByPath() (ファイル取得、必要時)
           │
           └─ createOperation() (Operations層)
                  ├─ initTransaction()
                  ├─ buildBeforeOperation()
                  ├─ executeAccess()
                  ├─ beforeValidate()
                  ├─ beforeChange()
                  ├─ payload.db.create()
                  ├─ afterRead()
                  ├─ afterChange()
                  ├─ buildAfterOperation()
                  └─ commitTransaction()
```

### データフロー図

```
[入力]                      [Local API]                    [出力]

Options Object ───▶ createLocal/findLocal/etc. ───▶ Document/PaginatedDocs
  ├─ collection                   │
  ├─ data                         │
  ├─ overrideAccess               ▼
  ├─ context            createLocalReq()
  ├─ req                          │
  ├─ user                         │ PayloadRequest生成
  ├─ locale                       │   ├─ payloadAPI: 'local'
  └─ ...                          │   ├─ locale/fallbackLocale
                                  │   └─ user/context
                                  │
                                  ▼
                          Operations Layer
                                  │
                                  ├─ Hooks (beforeChange, afterRead, etc.)
                                  ├─ Access Control (if overrideAccess=false)
                                  └─ Database Adapter
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| create.ts | `packages/payload/src/collections/operations/local/create.ts` | ソース | createLocal関数 |
| find.ts | `packages/payload/src/collections/operations/local/find.ts` | ソース | findLocal関数 |
| findByID.ts | `packages/payload/src/collections/operations/local/findByID.ts` | ソース | findByIDLocal関数 |
| update.ts | `packages/payload/src/collections/operations/local/update.ts` | ソース | updateLocal関数 |
| delete.ts | `packages/payload/src/collections/operations/local/delete.ts` | ソース | deleteLocal関数 |
| count.ts | `packages/payload/src/collections/operations/local/count.ts` | ソース | countLocal関数 |
| duplicate.ts | `packages/payload/src/collections/operations/local/duplicate.ts` | ソース | duplicateLocal関数 |
| findVersions.ts | `packages/payload/src/collections/operations/local/findVersions.ts` | ソース | findVersionsLocal関数 |
| findVersionByID.ts | `packages/payload/src/collections/operations/local/findVersionByID.ts` | ソース | findVersionByIDLocal関数 |
| restoreVersion.ts | `packages/payload/src/collections/operations/local/restoreVersion.ts` | ソース | restoreVersionLocal関数 |
| findOne.ts | `packages/payload/src/globals/operations/local/findOne.ts` | ソース | グローバルfindOneLocal関数 |
| update.ts (globals) | `packages/payload/src/globals/operations/local/update.ts` | ソース | グローバルupdateLocal関数 |
| createLocalReq.ts | `packages/payload/src/utilities/createLocalReq.ts` | ソース | PayloadRequest生成ユーティリティ |
| getFileByPath.ts | `packages/payload/src/uploads/getFileByPath.ts` | ソース | ファイルパスからFile取得 |
| create.ts (operations) | `packages/payload/src/collections/operations/create.ts` | ソース | createOperation（ビジネスロジック） |
| find.ts (operations) | `packages/payload/src/collections/operations/find.ts` | ソース | findOperation（ビジネスロジック） |
