# 機能設計書 61-プリファレンス

## 概要

本ドキュメントは、Payload CMSのプリファレンス（ユーザー設定・プリファレンス管理）機能について、その設計仕様を詳細に記載したものである。

### 本機能の処理概要

プリファレンス機能は、ユーザーごとの設定や好みを永続化し、管理画面のカスタマイズを可能にする機能である。

**業務上の目的・背景**：管理画面を使用する各ユーザーには、それぞれ異なるワークフローや好みがある。一覧画面での列表示設定、ソート順、ドキュメント編集画面でのフィールド折りたたみ状態、ナビゲーション設定など、ユーザーごとにカスタマイズ可能な要素を永続化することで、より効率的な作業環境を提供する。この機能により、ユーザーがログインするたびに同じ設定を再適用する必要がなくなり、生産性が向上する。

**機能の利用シーン**：
- 一覧画面で列の表示/非表示を切り替えた際に設定を保存
- ドキュメント編集画面でフィールドグループを折りたたんだ状態を記憶
- ダッシュボードのレイアウト設定を永続化
- ナビゲーションメニューの開閉状態を保存
- フォルダブラウズ表示の設定を保持

**主要な処理内容**：
1. プリファレンスの取得（findOne）：キーに基づいてユーザーのプリファレンス設定を取得
2. プリファレンスの更新（update）：キーと値のペアでプリファレンスを作成または更新（upsert）
3. プリファレンスの削除（delete）：特定のプリファレンス設定を削除
4. ユーザー削除時のプリファレンス一括削除（deleteUserPreferences）：ユーザー削除に伴う関連プリファレンスのクリーンアップ

**関連システム・外部連携**：
- データベースアダプター（MongoDB、PostgreSQL、SQLite等）との連携
- 認証システム（ユーザーコレクション）との連携

**権限による制御**：プリファレンスは各ユーザー自身のものだけにアクセス可能。他のユーザーのプリファレンスを読み取りまたは変更することは、アクセス制御により禁止されている。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | 一覧画面 | 主画面 | 列表示設定、ソート設定の保存・読込 |
| 10 | ドキュメント編集画面 | 主画面 | ドキュメント編集プリファレンスの保存・読込 |
| 16 | アカウント設定画面 | 主画面 | テーマ設定、UI設定の保存・読込 |

## 機能種別

CRUD操作（Create/Read/Update/Delete）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | Yes | プリファレンスを識別する一意のキー | 空文字不可 |
| value | unknown (JSON) | Yes（updateのみ） | 保存するプリファレンス値 | 有効なJSON形式 |
| user | PayloadRequest['user'] | Yes | 現在のユーザー情報 | ユーザーがログインしていること |
| req | PayloadRequest | Yes | リクエストオブジェクト | - |
| overrideAccess | boolean | No | アクセス制御をオーバーライドするか | - |

### 入力データソース

- REST API エンドポイント（`/api/payload-preferences/:key`）
- Admin UIからのAPI呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string \| number | プリファレンスドキュメントのID |
| key | string | プリファレンスキー |
| user | { relationTo: string, value: string \| number } | ユーザーリレーション |
| value | unknown | プリファレンス値（JSON形式） |
| createdAt | string | 作成日時 |
| updatedAt | string | 更新日時 |

### 出力先

- REST API レスポンス（JSON形式）
- データベース（`payload-preferences`コレクション）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ HTTPリクエストからkey、value、userを抽出

2. ユーザー認証確認
   └─ ユーザーがログインしていない場合はエラーを返す

3. アクセス制御チェック
   └─ ユーザー自身のプリファレンスのみアクセス可能

4. データベース操作実行
   └─ findOne: keyとuserで検索して返却
   └─ update: upsert操作で作成または更新
   └─ delete: 条件に合致するドキュメントを削除

5. レスポンス返却
   └─ 操作結果をJSON形式で返す
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{ユーザーログイン済み?}
    B -->|No| C[UnauthorizedError]
    B -->|Yes| D{操作種別}
    D -->|GET| E[findOne]
    D -->|POST| F[update]
    D -->|DELETE| G[deleteOperation]
    E --> H[Where条件構築]
    F --> H
    G --> H
    H --> I[key + user.value + user.relationTo]
    I --> J[データベース操作]
    J --> K[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ユーザー分離 | プリファレンスは各ユーザーに紐づき、他ユーザーからアクセス不可 | 全操作 |
| BR-02 | 認証必須 | 未認証ユーザーはプリファレンス操作不可 | 全操作 |
| BR-03 | キー一意性 | 同一ユーザー内ではキーは一意 | update時 |
| BR-04 | JSON形式検証 | value はJSON形式として有効である必要がある | update時 |

### 計算ロジック

特になし（単純なCRUD操作）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| findOne | payload-preferences | SELECT | キーとユーザーでプリファレンス取得 |
| update | payload-preferences | UPSERT | プリファレンスの作成または更新 |
| delete | payload-preferences | DELETE | プリファレンスの削除 |
| deleteUserPreferences | payload-preferences | DELETE (Many) | ユーザー削除時の一括削除 |

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

#### payload-preferences

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | key, user.value, user.relationTo | WHERE条件として使用 | 複合条件 |
| UPSERT | key, value, user | リクエストから取得した値 | 存在しない場合はINSERT |
| DELETE | key, user.value, user.relationTo | WHERE条件として使用 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | UnauthorizedError | ユーザー未認証 | ログインを促す |
| 404 | NotFound | 削除対象が存在しない | - |
| 400 | ValidationError | valueがJSON形式でない | 有効なJSON形式で再送信 |

### リトライ仕様

データベース接続エラーの場合は、データベースアダプターのリトライ機構に依存

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

- 単一のプリファレンス操作は個別のトランザクションで実行
- deleteUserPreferencesは一括削除のため、単一トランザクションで実行

## パフォーマンス要件

- keyフィールドとuserフィールドにはインデックスが設定されている
- 通常のプリファレンス操作は数十ミリ秒以内に完了すること

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

- ユーザー認証が必須
- アクセス制御によりユーザー自身のプリファレンスのみ操作可能
- valueフィールドはJSON形式の検証が行われる
- `payload-preferences`コレクションはAdmin UIで非表示に設定

## 備考

- プリファレンスコレクションは内部コレクションとして自動生成される
- ドキュメントロックは無効化されている（`lockDocuments: false`）

---

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

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

### 推奨読解順序

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

まず、プリファレンスで使用される型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/payload/src/preferences/types.ts` | プリファレンスのリクエスト型、各種プリファレンス型の定義 |
| 1-2 | keys.ts | `packages/payload/src/preferences/keys.ts` | プリファレンスキー定数の定義 |

**読解のコツ**: `PreferenceRequest`と`PreferenceUpdateRequest`がすべての操作の基本型となる。`CollectionPreferences`や`DocumentPreferences`は具体的なユースケースを示している。

#### Step 2: コレクション設定を理解する

プリファレンスコレクションの設定と、エンドポイント・アクセス制御を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | config.ts | `packages/payload/src/preferences/config.ts` | コレクション設定、アクセス制御、エンドポイント定義 |

**主要処理フロー**:
1. **9-29行目**: `preferenceAccess`関数でユーザー自身のプリファレンスのみアクセス可能なWhere条件を構築
2. **33-105行目**: `getPreferencesCollection`関数でコレクション設定を生成
3. **42-57行目**: REST APIエンドポイント（GET/POST/DELETE）の定義
4. **59-82行目**: userフィールドの定義とリレーション設定
5. **91-101行目**: valueフィールドのJSON検証

#### Step 3: 各オペレーションを理解する

実際のCRUD操作を処理するオペレーション関数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | findOne.ts | `packages/payload/src/preferences/operations/findOne.ts` | プリファレンス取得ロジック |
| 3-2 | update.ts | `packages/payload/src/preferences/operations/update.ts` | プリファレンス更新（upsert）ロジック |
| 3-3 | delete.ts | `packages/payload/src/preferences/operations/delete.ts` | プリファレンス削除ロジック |

**主要処理フロー**:
- **findOne.ts 19-25行目**: key、user.value、user.relationToによるWhere条件構築
- **update.ts 20-42行目**: Where条件構築とupsert操作
- **delete.ts 20-32行目**: Where条件構築とdeleteOne操作

#### Step 4: リクエストハンドラーを理解する

HTTPリクエストを処理するハンドラーを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | findOne.ts | `packages/payload/src/preferences/requestHandlers/findOne.ts` | GETリクエストハンドラー |
| 4-2 | update.ts | `packages/payload/src/preferences/requestHandlers/update.ts` | POSTリクエストハンドラー |
| 4-3 | delete.ts | `packages/payload/src/preferences/requestHandlers/delete.ts` | DELETEリクエストハンドラー |

**主要処理フロー**:
- **各ハンドラー**: リクエストボディのパース、routeParamsからkeyの取得、オペレーション呼び出し、レスポンス返却

#### Step 5: ユーザー削除時の処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | deleteUserPreferences.ts | `packages/payload/src/preferences/deleteUserPreferences.ts` | ユーザー削除時のプリファレンス一括削除 |

**主要処理フロー**:
- **16-48行目**: 認証コレクションの場合はユーザーに紐づくプリファレンスを削除、それ以外はキーベースで削除

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

```
[REST API Request]
    │
    ├─ findByIDHandler (requestHandlers/findOne.ts)
    │      └─ findOne (operations/findOne.ts)
    │             └─ payload.db.find
    │
    ├─ updateHandler (requestHandlers/update.ts)
    │      └─ update (operations/update.ts)
    │             └─ payload.db.upsert
    │
    └─ deleteHandler (requestHandlers/delete.ts)
           └─ deleteOperation (operations/delete.ts)
                  └─ payload.db.deleteOne
```

### データフロー図

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

HTTPリクエスト ───▶ RequestHandler ───▶ Operation ───▶ DB操作 ───▶ JSONレスポンス
  ├─ key                  │                │
  ├─ value                │                │
  └─ user (from auth)     │                │
                          │                │
                    リクエスト解析     Where条件構築
                    データ抽出       CRUD実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| types.ts | `packages/payload/src/preferences/types.ts` | ソース | 型定義 |
| keys.ts | `packages/payload/src/preferences/keys.ts` | ソース | キー定数 |
| config.ts | `packages/payload/src/preferences/config.ts` | ソース | コレクション設定 |
| findOne.ts | `packages/payload/src/preferences/operations/findOne.ts` | ソース | 取得オペレーション |
| update.ts | `packages/payload/src/preferences/operations/update.ts` | ソース | 更新オペレーション |
| delete.ts | `packages/payload/src/preferences/operations/delete.ts` | ソース | 削除オペレーション |
| findOne.ts | `packages/payload/src/preferences/requestHandlers/findOne.ts` | ソース | GETハンドラー |
| update.ts | `packages/payload/src/preferences/requestHandlers/update.ts` | ソース | POSTハンドラー |
| delete.ts | `packages/payload/src/preferences/requestHandlers/delete.ts` | ソース | DELETEハンドラー |
| deleteUserPreferences.ts | `packages/payload/src/preferences/deleteUserPreferences.ts` | ソース | ユーザー削除時処理 |
