# 機能設計書 63-アクセス制御

## 概要

本ドキュメントは、Payload CMSのアクセス制御機能（フィールド・ドキュメントレベルのアクセス制御）について、その設計仕様を詳細に記載したものである。

### 本機能の処理概要

アクセス制御機能は、ユーザーの権限に基づいてコレクション、グローバル、およびフィールドへのアクセスを制御する機能である。

**業務上の目的・背景**：エンタープライズ向けCMSでは、複数のユーザーロールが存在し、それぞれに異なる権限が必要となる。編集者は記事を作成・編集できるが公開はできない、管理者はすべての操作が可能、といった細かな権限制御が求められる。また、ドキュメントの所有者のみが編集できる、特定の部門のユーザーのみがアクセスできるといった、データに基づく動的な権限制御も必要となる。本機能は、これらの要件を満たすための柔軟なアクセス制御メカニズムを提供する。

**機能の利用シーン**：
- コレクションの読み取り・作成・更新・削除操作の権限チェック
- グローバルデータへのアクセス制御
- フィールドレベルでの読み取り・更新権限の制御
- 静的ファイル（アップロード）へのアクセス制御
- 管理画面でのナビゲーション表示制御

**主要な処理内容**：
1. executeAccess関数による権限チェックの実行
2. Access関数の呼び出しと結果の評価
3. Where条件の返却によるドキュメントフィルタリング
4. Forbiddenエラーのスロー（アクセス拒否時）

**関連システム・外部連携**：
- コレクション・グローバルのすべてのCRUD操作
- フィールドシステム（afterReadフック内でのアクセス制御）
- REST API・GraphQL APIのエンドポイント

**権限による制御**：アクセス制御自体が権限制御の中核機能。ユーザー情報（`req.user`）を基に、各操作の許可・拒否を決定する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | 権限エラー画面 | 主画面 | アクセス権限チェック結果の表示 |
| 8 | ダッシュボード画面 | 補助画面 | 表示可能なエンティティの権限チェック |
| 9 | 一覧画面 | 補助画面 | コレクション・ドキュメントレベルの権限チェック |
| 10 | ドキュメント編集画面 | 補助画面 | フィールドレベルの読み書き権限チェック |

## 機能種別

認可処理 / セキュリティ制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| req | PayloadRequest | Yes | リクエストオブジェクト | - |
| access | Access | Yes | アクセス制御関数 | - |
| id | number \| string | No | ドキュメントID | - |
| data | any | No | 操作対象データ | - |
| disableErrors | boolean | No | エラー無効化フラグ | - |
| isReadingStaticFile | boolean | No | 静的ファイル読み取りフラグ | - |

### 入力データソース

- コレクション・グローバルの設定ファイル（access設定）
- リクエストオブジェクト（ユーザー情報を含む）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (返り値) | AccessResult | true/false またはWhere条件 |

### AccessResultの詳細

| 返り値 | 型 | 意味 |
|--------|-----|------|
| true | boolean | アクセス許可 |
| false | boolean | アクセス拒否 |
| Where | object | 条件付きアクセス許可（Where条件でフィルタ） |

### 出力先

- 呼び出し元の操作関数
- エラー時：Forbiddenエラーをスロー

## 処理フロー

### 処理シーケンス

```
1. executeAccess呼び出し
   └─ 引数からreq、access関数、その他オプションを取得

2. access関数の存在確認
   └─ 存在する場合：access関数を呼び出し
   └─ 存在しない場合：デフォルト動作

3. access関数の実行（存在する場合）
   └─ id、data、isReadingStaticFile、reqを渡して呼び出し
   └─ 返り値（resolvedConstraint）を取得

4. 結果の評価
   └─ resolvedConstraintがfalsyの場合：
      └─ disableErrorsがfalse：Forbiddenエラーをスロー
      └─ disableErrorsがtrue：falseを返却
   └─ resolvedConstraintがtruthyの場合：そのまま返却

5. デフォルト動作（access関数なしの場合）
   └─ req.userが存在する場合：trueを返却
   └─ req.userが存在しない場合：
      └─ disableErrorsがfalse：Forbiddenエラーをスロー
      └─ disableErrorsがtrue：falseを返却
```

### フローチャート

```mermaid
flowchart TD
    A[executeAccess呼び出し] --> B{access関数あり?}
    B -->|Yes| C[access関数実行]
    B -->|No| D{req.userあり?}
    C --> E{結果がtruthy?}
    E -->|Yes| F[結果を返却]
    E -->|No| G{disableErrors?}
    G -->|Yes| H[falseを返却]
    G -->|No| I[Forbiddenエラー]
    D -->|Yes| J[trueを返却]
    D -->|No| G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルト許可 | access関数未定義かつログイン済みの場合は許可 | access関数なし |
| BR-02 | デフォルト拒否 | access関数未定義かつ未ログインの場合は拒否 | access関数なし |
| BR-03 | 条件付き許可 | Where条件を返すと条件付きアクセス許可 | access関数あり |
| BR-04 | エラー無効化 | disableErrorsがtrueの場合はエラーをスローしない | 全ケース |
| BR-05 | 静的ファイルフラグ | isReadingStaticFileでファイル読み取り判定 | アップロード操作 |

### 計算ロジック

特になし（条件判定のみ）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| executeAccess | - | なし | アクセス制御のみ（DB操作なし） |

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

executeAccess関数自体はデータベースを直接操作しない。返却されたWhere条件は、呼び出し元でデータベースクエリに使用される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | アクセス拒否時（disableErrors=false） | 権限の確認、ログイン状態の確認 |

### リトライ仕様

アクセス拒否はリトライ不可。権限設定の変更が必要。

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

- executeAccess自体はトランザクションに影響しない
- 呼び出し元のトランザクション内で実行

## パフォーマンス要件

- access関数は高速に実行されること（通常は数ミリ秒以内）
- 複雑なWhere条件はデータベースクエリのパフォーマンスに影響

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

- アクセス制御はセキュリティの中核機能
- access関数内での適切な権限チェックが必要
- Where条件によるデータ漏洩防止
- req.userの改ざん防止（認証システムと連携）

## 備考

- access関数はasync関数として定義可能
- Where条件を返すことで、データベースレベルでのフィルタリングが可能
- コレクション、グローバル、フィールドそれぞれにaccess設定が可能

---

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

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

### 推奨読解順序

#### Step 1: executeAccess関数を理解する

アクセス制御の中核となるexecuteAccess関数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | executeAccess.ts | `packages/payload/src/auth/executeAccess.ts` | アクセス制御のメイン処理 |

**読解のコツ**: この関数は43行程度の小さな関数。シンプルだが、すべてのアクセス制御の基盤となる。

**主要処理フロー**:
1. **6-12行目**: OperationArgs型の定義（関数引数の型）
2. **13-16行目**: executeAccess関数のシグネチャ
3. **17-23行目**: access関数が定義されている場合の処理
4. **25-29行目**: resolvedConstraintがfalsyの場合のエラー処理
5. **31行目**: 結果の返却
6. **34-36行目**: access関数未定義でユーザーありの場合
7. **38-41行目**: access関数未定義でユーザーなしの場合

#### Step 2: Access型の定義を理解する

Access関数の型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | types.ts | `packages/payload/src/config/types.ts` | Access型の定義 |

**読解のコツ**: Access型は、アクセス制御関数の引数と返り値を定義。AccessResult型（boolean | Where）に注目。

#### Step 3: 実際の使用例を理解する

コレクション操作でのexecuteAccess使用例を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | find.ts | `packages/payload/src/collections/operations/find.ts` | find操作でのアクセス制御 |
| 3-2 | create.ts | `packages/payload/src/collections/operations/create.ts` | create操作でのアクセス制御 |
| 3-3 | delete.ts | `packages/payload/src/collections/operations/delete.ts` | delete操作でのアクセス制御 |

**読解のコツ**: 各操作でexecuteAccessを呼び出し、結果をWhere条件としてクエリに追加している点に注目。

#### Step 4: フィールドレベルのアクセス制御を理解する

afterReadフック内でのフィールドアクセス制御を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | promise.ts | `packages/payload/src/fields/hooks/afterRead/promise.ts` | フィールドレベルのアクセス制御 |

**主要処理フロー（promise.ts）**:
- **374-390行目**: フィールドのaccess.read関数が定義されている場合の処理
- **375-384行目**: overrideAccessがtrueの場合はアクセス制御をスキップ
- **386-388行目**: アクセス拒否時はフィールド値を削除

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

```
[コレクション操作]
    │
    ├─ find
    │      └─ executeAccess(collection.access.read)
    │             └─ Where条件を返却
    │                    └─ DBクエリに適用
    │
    ├─ findByID
    │      └─ executeAccess(collection.access.read)
    │
    ├─ create
    │      └─ executeAccess(collection.access.create)
    │
    ├─ update / updateByID
    │      └─ executeAccess(collection.access.update)
    │
    ├─ delete / deleteByID
    │      └─ executeAccess(collection.access.delete)
    │
    └─ restoreVersion
           └─ executeAccess(collection.access.update)

[グローバル操作]
    │
    ├─ findOne
    │      └─ executeAccess(global.access.read)
    │
    └─ update
           └─ executeAccess(global.access.update)

[フィールドレベル]
    │
    └─ afterRead
           └─ field.access.read
                  └─ フィールド値の削除（アクセス拒否時）
```

### データフロー図

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

req (user情報)
    │
    └───▶ executeAccess ───▶ access関数呼び出し ───▶ AccessResult
              │                    │                     │
              │               [true/false/Where]         │
              │                    │                     │
              │              結果評価                     │
              │                    │                     │
              └────────────────────┴─────────────────────┴───▶ 呼び出し元へ
                                                               │
                                                          [true] → 操作許可
                                                          [false] → Forbiddenエラー
                                                          [Where] → 条件付きクエリ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| executeAccess.ts | `packages/payload/src/auth/executeAccess.ts` | ソース | アクセス制御のメイン処理 |
| types.ts | `packages/payload/src/config/types.ts` | ソース | Access型の定義 |
| Forbidden.ts | `packages/payload/src/errors/Forbidden.ts` | ソース | アクセス拒否エラー |
| find.ts | `packages/payload/src/collections/operations/find.ts` | ソース | find操作でのアクセス制御使用例 |
| create.ts | `packages/payload/src/collections/operations/create.ts` | ソース | create操作でのアクセス制御使用例 |
| update.ts | `packages/payload/src/collections/operations/update.ts` | ソース | update操作でのアクセス制御使用例 |
| delete.ts | `packages/payload/src/collections/operations/delete.ts` | ソース | delete操作でのアクセス制御使用例 |
| findByID.ts | `packages/payload/src/collections/operations/findByID.ts` | ソース | findByID操作でのアクセス制御使用例 |
| promise.ts | `packages/payload/src/fields/hooks/afterRead/promise.ts` | ソース | フィールドレベルアクセス制御 |
