# 機能設計書 82-ポリシー管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおけるポリシー管理機能の設計について記述する。RBAC（Role-Based Access Control）モジュールの構成要素として、アクセス制御ポリシーの作成・取得・更新・削除を行う。

### 本機能の処理概要

**業務上の目的・背景**：ECサイト運営では、「商品の閲覧のみ可能」「注文の編集が可能」「全機能へのアクセス可能」など、きめ細かなアクセス権限の設定が求められる。ポリシー管理機能は、リソース（resource）と操作（operation）の組み合わせでアクセス権限を定義し、これをロールに紐付けることで柔軟な権限管理を実現する。セキュリティコンプライアンス、最小権限の原則、監査対応などの課題を解決する。

**機能の利用シーン**：新機能開発時のアクセス権限定義、セキュリティポリシーの見直し、監査ログのための権限一覧出力、特定リソースへのアクセス制御設定などで利用される。

**主要な処理内容**：
1. ポリシーの作成（createRbacPolicies）：リソース、操作、名前、説明を指定してポリシーを新規作成
2. ポリシーの一覧取得（listRbacPolicies）：フィルタ条件を指定してポリシーを検索・取得
3. ポリシーの詳細取得（retrieveRbacPolicy）：IDを指定して特定のポリシーを取得
4. ポリシーの更新（updateRbacPolicies）：ポリシー情報を更新
5. ポリシーの削除（deleteRbacPolicies）：不要なポリシーをソフトデリート
6. 登録ポリシーの同期（syncRegisteredPolicies）：コード定義とDBの同期

**関連システム・外部連携**：ロール管理機能（ロールへのポリシー割り当て）、認証・認可ミドルウェア（リクエスト時の権限チェック）と連携する。

**権限による制御**：ポリシー管理機能自体が`rbac_policy:create`、`rbac_policy:read`、`rbac_policy:update`、`rbac_policy:delete`などのポリシーによってアクセス制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （画面未実装）| - | 本機能はAPI経由で利用 |

## 機能種別

CRUD操作 / 同期処理

## 入力仕様

### 入力パラメータ

#### ポリシー作成（createRbacPolicies）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | Yes | ポリシーキー（resource:operation形式） | 一意制約 |
| resource | string | Yes | 対象リソース名 | 空文字不可 |
| operation | string | Yes | 操作種別 | 空文字不可 |
| name | string | No | ポリシー表示名 | - |
| description | string | No | ポリシーの説明 | - |
| metadata | object | No | カスタムメタデータ | JSON形式 |

#### ポリシー一覧取得（listRbacPolicies）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string/string[] | No | ポリシーID | - |
| key | string/string[] | No | ポリシーキー | - |
| resource | string/string[] | No | リソース名 | - |
| operation | string/string[] | No | 操作種別 | - |
| q | string | No | 検索クエリ | - |

### 入力データソース

API経由でのJSON形式リクエストボディ、およびアプリケーションコード内のPolicy定義

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | ポリシーID（プレフィックス: rpol_） |
| key | string | ポリシーキー（resource:operation） |
| resource | string | 対象リソース名 |
| operation | string | 操作種別 |
| name | string/null | ポリシー表示名 |
| description | string/null | ポリシーの説明 |
| metadata | object/null | カスタムメタデータ |
| created_at | Date | 作成日時 |
| updated_at | Date | 更新日時 |
| deleted_at | Date/null | 削除日時（ソフトデリート） |

### 出力先

APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. アプリケーション起動
   └─ syncRegisteredPoliciesが自動実行

2. 登録ポリシー抽出
   └─ Policyオブジェクトからポリシー定義を取得

3. 既存ポリシー取得
   └─ DBから全ポリシー（ソフトデリート含む）を取得

4. 差分計算
   └─ 新規作成、更新、復元、削除対象を分類

5. DB同期
   └─ 復元 → 作成/更新/削除を並列実行
```

### フローチャート

```mermaid
flowchart TD
    A[アプリ起動] --> B[syncRegisteredPolicies]
    B --> C[Policyオブジェクトから定義取得]
    C --> D[DBから既存ポリシー取得]
    D --> E{差分チェック}

    E -->|新規| F[policiesToCreate追加]
    E -->|更新| G[policiesToUpdate追加]
    E -->|復元| H[policiesToRestore追加]
    E -->|削除| I[policiesToSoftDelete追加]

    F --> J[復元処理実行]
    G --> J
    H --> J
    I --> J

    J --> K[promiseAllで並列DB操作]
    K --> L[同期完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-1 | キー一意制約 | 同一keyのポリシーは作成不可 | ポリシー作成時 |
| BR-82-2 | キー形式 | keyはresource:operation形式 | ポリシー作成時 |
| BR-82-3 | スーパー管理者除外 | *:*キーは同期処理で削除対象外 | ポリシー同期時 |
| BR-82-4 | ソフトデリート | 削除はソフトデリートで実行 | ポリシー削除時 |
| BR-82-5 | 復元優先 | ソフトデリート済みポリシーは復元後に更新 | ポリシー同期時 |
| BR-82-6 | ワイルドカード除外 | resource=*, operation=*の組み合わせは同期対象外 | ポリシー同期時 |

### 計算ロジック

ポリシーキーの計算：`key = ${resource}:${operation}`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createRbacPolicies | rbac_policy | INSERT | ポリシーレコード作成 |
| listRbacPolicies | rbac_policy | SELECT | ポリシー一覧取得 |
| retrieveRbacPolicy | rbac_policy | SELECT | 単一ポリシー取得 |
| updateRbacPolicies | rbac_policy | UPDATE | ポリシー情報更新 |
| deleteRbacPolicies | rbac_policy | UPDATE | deleted_at設定 |
| restoreRbacPolicies | rbac_policy | UPDATE | deleted_atをNULLに |
| syncRegisteredPolicies | rbac_policy | INSERT/UPDATE/DELETE | 一括同期 |

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

#### rbac_policy

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | rpol_プレフィックス + UUID | 自動生成 |
| INSERT | key | resource:operation形式 | 一意 |
| INSERT | resource | リソース名 | 必須 |
| INSERT | operation | 操作種別 | 必須 |
| INSERT | name | 表示名 | 任意 |
| INSERT | description | 説明 | 任意 |
| UPDATE | deleted_at | 現在日時 | ソフトデリート時 |
| UPDATE | deleted_at | NULL | 復元時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| DUPLICATE_ERROR | 重複エラー | 同一keyのポリシーが存在 | 別keyを使用 |
| NOT_FOUND | 検索エラー | 指定IDのポリシーが存在しない | 正しいIDを指定 |
| INVALID_DATA | 検証エラー | 必須フィールドが未入力 | 必須項目を入力 |

### リトライ仕様

データベースデッドロック発生時は、トランザクションマネージャーにより自動リトライされる。

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

- syncRegisteredPoliciesは`@InjectTransactionManager()`デコレータによりトランザクション管理される
- 復元処理は作成/更新/削除処理の前に実行される（依存関係のため）
- promiseAllで並列実行される処理は同一トランザクション内

## パフォーマンス要件

- ポリシー一覧取得：500件以下で500ms以内
- 同期処理：100ポリシー以下で2秒以内
- key/resource/operationインデックスによる検索高速化

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

- ポリシー管理操作にはRBACポリシーによる認可が必要
- スーパー管理者ポリシー（*:*）は特別扱いで削除されない
- ソフトデリートによりデータ復旧可能性を確保
- ポリシー変更は即座に権限チェックに反映される

## 備考

- ポリシー定義は`@medusajs/framework/utils`のPolicyオブジェクトで管理
- 各モジュールがPolicyを登録し、起動時に自動同期される
- DBに存在するがコードに未定義のポリシーは自動的にソフトデリートされる

---

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

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

### 推奨読解順序

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

ポリシーエンティティの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rbac-policy.ts | `packages/modules/rbac/src/models/rbac-policy.ts` | key/resource/operation/name/descriptionフィールド、インデックス定義 |

**読解のコツ**: ポリシーは`key`フィールドが一意制約を持ち、`resource`と`operation`の組み合わせで構成される。3つのフィールドすべてに検索用インデックスが設定されている。

#### Step 2: ポリシー同期処理を理解する

アプリケーション起動時の同期ロジックが最重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | rbac-module-service.ts | `packages/modules/rbac/src/services/rbac-module-service.ts` | syncRegisteredPoliciesメソッド |

**主要処理フロー**:
1. **39行目**: `SUPER_ADMIN_KEY = "*:*"`の定義
2. **85-169行目**: `syncRegisteredPolicies`メソッド全体
3. **89-97行目**: Policyオブジェクトから登録ポリシーを抽出し、keyを生成
4. **102-106行目**: DBから既存ポリシーを`withDeleted: true`で取得（ソフトデリート含む）
5. **108行目**: 既存ポリシーをMapに変換してO(1)アクセス可能に
6. **115-145行目**: 新規作成・更新・復元対象の分類ロジック
   - **116-118行目**: `*:*`パターンはスキップ
   - **127-128行目**: 未存在なら新規作成
   - **129-137行目**: ソフトデリート済みなら復元リストに追加
   - **138-144行目**: 変更があれば更新リストに追加
7. **147-154行目**: コードに未定義で削除されていないポリシーをソフトデリート対象に
8. **157-159行目**: 復元処理を先に実行
9. **161-168行目**: `promiseAll`で作成・更新・削除を並列実行

#### Step 3: MedusaServiceの基底CRUD操作を理解する

ポリシーのCRUD操作はMedusaServiceの基底実装を利用。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rbac-module-service.ts | `packages/modules/rbac/src/services/rbac-module-service.ts` | クラス定義、MedusaService継承 |

**主要処理フロー**:
- **42-47行目**: `MedusaService({ RbacRole, RbacPolicy, ... })`で基底サービスを生成
- 基底サービスが自動的に`createRbacPolicies`、`listRbacPolicies`、`retrieveRbacPolicy`、`updateRbacPolicies`、`deleteRbacPolicies`メソッドを提供

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

```
アプリケーション起動
    │
    └─ RbacModuleService.__hooks.onApplicationStart
           │
           └─ syncRegisteredPolicies()
                  │
                  ├─ Policy (登録ポリシー定義)
                  │
                  ├─ listRbacPolicies({ withDeleted: true })
                  │      └─ rbacPolicyService.list()
                  │
                  ├─ restoreRbacPolicies()
                  │      └─ rbacPolicyService.restore()
                  │
                  └─ promiseAll([
                         rbacPolicyService.create()
                         rbacPolicyService.upsert()
                         rbacPolicyService.softDelete()
                     ])
```

### データフロー図

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

Policyオブジェクト ───▶ syncRegisteredPolicies() ───▶ DBポリシー同期
     │                         │
     │                         ├─▶ 既存ポリシー取得
     │                         │
     │                         ├─▶ 差分計算
     │                         │
     └─────────────────────────├─▶ 復元/作成/更新/削除
                                      │
                                      └─▶ rbac_policyテーブル更新

APIリクエスト ───▶ MedusaService.createRbacPolicies() ───▶ RbacPolicyDTO
                          │
                          └─▶ rbacPolicyService.create()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rbac-module-service.ts | `packages/modules/rbac/src/services/rbac-module-service.ts` | サービス | ポリシー管理の同期・CRUD処理 |
| rbac-policy.ts | `packages/modules/rbac/src/models/rbac-policy.ts` | モデル | ポリシーエンティティ定義 |
| rbac-role-policy.ts | `packages/modules/rbac/src/models/rbac-role-policy.ts` | モデル | ロール-ポリシー中間テーブル |
| index.ts | `packages/modules/rbac/src/index.ts` | エクスポート | モジュールエクスポート |
