# 機能設計書 35-権限・ロール管理

## 概要

本ドキュメントは、InvenTreeシステムにおける権限・ロール管理機能の設計を定義する。ユーザーやグループに対する操作権限の設定と検証を行う機能を提供する。

### 本機能の処理概要

権限・ロール管理機能は、InvenTreeシステム内の各機能やデータに対するアクセス制御を実現する。Djangoの標準権限システムを拡張し、ルールセット（RuleSet）によるドメイン別の権限管理を提供する。

**業務上の目的・背景**：在庫管理システムでは、部門や役職によってアクセスできるデータや実行できる操作が異なる。例えば、購買部門は発注関連の操作が可能だが、在庫データの変更は制限されるなど、きめ細かなアクセス制御が必要となる。

**機能の利用シーン**：
- 新しい部門やチーム用のグループ作成と権限設定
- ユーザーのグループ割り当て変更
- 部品カテゴリや在庫ロケーションへのアクセス制限
- オーダー承認権限の付与
- 管理者権限の委譲

**主要な処理内容**：
1. ルールセット（RuleSet）によるドメイン別権限管理
2. グループベースの権限割り当て
3. Django権限との連携
4. Ownerモデルによるオブジェクトレベルの所有権管理
5. 権限チェック処理

**関連システム・外部連携**：
- Django auth（認証・権限フレームワーク）
- Django REST Framework（API権限）

**権限による制御**：権限・ロール管理自体はadminロールセットを持つスタッフユーザーのみ操作可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | グループ詳細画面 | 主画面 | グループの権限設定・メンバー管理 |
| 34 | 管理センター画面 | 主画面 | ユーザー/アクセス管理パネル |

## 機能種別

セキュリティ / アクセス制御

## 入力仕様

### RuleSet入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | str | Yes | ルールセット名 | RuleSetEnum値のいずれか |
| can_view | bool | No | 閲覧権限 | true/false |
| can_add | bool | No | 追加権限 | true/false |
| can_change | bool | No | 変更権限 | true/false |
| can_delete | bool | No | 削除権限 | true/false |
| group | int | Yes | 対象グループID | 有効なグループID |

### 入力データソース

- グループ詳細画面からのフォーム入力
- REST API経由のJSON入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pk | int | ルールセットID |
| name | str | ルールセット名 |
| can_view | bool | 閲覧権限 |
| can_add | bool | 追加権限 |
| can_change | bool | 変更権限 |
| can_delete | bool | 削除権限 |
| group | int | 対象グループID |

### 出力先

- REST APIレスポンス（JSON）
- グループ詳細画面への表示
- データベース（users_ruleset）

## 処理フロー

### 処理シーケンス

```
1. 権限チェックリクエスト
   └─ API/ビューからの呼び出し
2. ユーザーのグループ取得
   └─ User.groups.all()
3. グループのRuleSet取得
   └─ RuleSet.objects.filter(group__in=groups)
4. 権限判定
   └─ 該当ルールセットの権限フラグ確認
5. 結果返却
   └─ True/False
```

### フローチャート

```mermaid
flowchart TD
    A[権限チェック要求] --> B{スーパーユーザー?}
    B -->|Yes| C[アクセス許可]
    B -->|No| D[ユーザーのグループ取得]
    D --> E[RuleSet検索]
    E --> F{該当RuleSet存在?}
    F -->|No| G[アクセス拒否]
    F -->|Yes| H{権限フラグチェック}
    H -->|許可| C
    H -->|拒否| G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | スーパーユーザー権限 | スーパーユーザーはすべての権限を持つ | 全操作 |
| BR-35-02 | グループ継承 | ユーザーは所属グループの権限を継承 | 権限チェック時 |
| BR-35-03 | 複数グループOR結合 | 複数グループの権限はOR結合で評価 | 権限チェック時 |
| BR-35-04 | adminルールセット | adminロールはユーザー・グループ管理権限を含む | admin操作時 |
| BR-35-05 | Owner制約 | Ownerが設定されたオブジェクトはOwnerのみ操作可能（設定時） | オブジェクト操作時 |

### 計算ロジック

権限チェック:
```python
has_permission = user.is_superuser or any(
    ruleset.can_{action}
    for group in user.groups.all()
    for ruleset in group.rule_sets.filter(name=ruleset_name)
)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| RuleSet作成 | users_ruleset | INSERT | ルールセット作成 |
| RuleSet更新 | users_ruleset | UPDATE | 権限フラグ更新 |
| RuleSet削除 | users_ruleset | DELETE | ルールセット削除 |
| 権限チェック | users_ruleset | SELECT | 権限検証 |
| グループ作成 | auth_group | INSERT | グループ作成、自動RuleSet作成 |

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

#### users_ruleset

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name, group_id, can_view/add/change/delete | 入力値 | |
| UPDATE | can_view, can_add, can_change, can_delete | 入力値 | |
| SELECT | group__in, name | ユーザーのグループとルールセット名 | |
| DELETE | pk | 削除対象ID | グループ削除時カスケード |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | PermissionDenied | 権限不足 | 必要な権限をグループに付与 |
| 400 | ValidationError | 無効なルールセット名 | RuleSetEnumの値を使用 |

### リトライ仕様

特別なリトライ仕様は不要。権限チェックは即座に結果を返却。

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

- ルールセット更新は個別のトランザクションで処理
- グループ作成時のルールセット自動生成は単一トランザクション

## パフォーマンス要件

- 権限チェック：10ms以内
- ルールセットはメモリキャッシュ対応

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

- 権限設定変更はadminロールセット保持者のみ
- 最低1名のスーパーユーザー維持を推奨
- 権限変更のログ記録

## 備考

RuleSetEnumの定義:
- ADMIN: 管理者権限
- PART_CATEGORY: 部品カテゴリ
- PART: 部品
- STOCK_LOCATION: 在庫ロケーション
- STOCK: 在庫アイテム
- BUILD: 製造指示
- PURCHASE_ORDER: 発注
- SALES_ORDER: 受注
- RETURN_ORDER: 返品

各RuleSetに関連付けられるDjangoモデル一覧はruleset.pyのget_ruleset_models()で定義。

---

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

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

### 推奨読解順序

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

権限管理に関連するモデルと定数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ruleset.py | `src/backend/InvenTree/users/ruleset.py` | RuleSetEnum（9-21行目）とRULESET_CHOICES（25-35行目） |
| 1-2 | ruleset.py | `src/backend/InvenTree/users/ruleset.py` | get_ruleset_models()（46-168行目）でルールセットとモデルのマッピング |
| 1-3 | models.py | `src/backend/InvenTree/users/models.py` | RuleSet（201-294行目）とOwner（296-458行目）の定義 |

**読解のコツ**:
- RuleSetEnumはStringEnumを継承し、各ルールセットタイプを文字列で定義
- get_ruleset_models()は各ルールセットが管理するDjangoモデル一覧を返す
- get_ruleset_ignore()は権限チェック対象外のテーブルを返す

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

REST APIエンドポイントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | api.py | `src/backend/InvenTree/users/api.py` | RoleDetailでルール詳細（332-344行目） |
| 2-2 | api.py | `src/backend/InvenTree/users/api.py` | GroupListとGroupDetail（91-130行目） |

**主要処理フロー**:
- GroupDetail.perform_destroy()でグループ削除時の検証
- RuleDetailでルールセット情報の取得

#### Step 3: 権限チェック処理を理解する

権限検証の仕組みを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | permissions.py | `src/backend/InvenTree/users/permissions.py` | 権限クラスの定義 |
| 3-2 | models.py | `src/backend/InvenTree/users/models.py` | RuleSet.check_table_permission（257-294行目） |

**主要処理フロー**:
- **257-275行目**: check_table_permissionでテーブル単位の権限チェック
- **276-294行目**: check_permission_boolでブール値での権限チェック

#### Step 4: Ownerモデルを理解する

オブジェクトレベルの所有権管理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | models.py | `src/backend/InvenTree/users/models.py` | Ownerクラス（296-458行目） |

**主要処理フロー**:
- **314-339行目**: get_owners_matching_user()でユーザーに関連するOwnerを取得
- **341-358行目**: get_api_url()でAPIエンドポイントを取得
- **380-393行目**: create()で既存Ownerチェック付きの作成

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

```
API リクエスト
    │
    ├─ StaffRolePermissionOrReadOnly
    │      └─ has_permission()
    │             └─ user.is_staff & role check
    │
    └─ オブジェクト権限チェック
           └─ has_object_permission()
                  └─ Owner.get_owners_matching_user()

RuleSet
    │
    ├─ check_table_permission(table, permission)
    │      └─ グループのRuleSetを検索
    │
    └─ check_permission_bool(group, role, permission)
           └─ 特定ルールの権限フラグ確認

Owner
    │
    ├─ get_owners_matching_user(user)
    │      └─ ユーザーと所属グループに関連するOwner取得
    │
    └─ owner_model()
           └─ ContentTypeからモデルクラス取得
```

### データフロー図

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

APIリクエスト ───▶ 権限クラス ───▶ has_permission()
        │                  │
        ▼                  ▼
   ユーザー情報      グループ取得
        │                  │
        │                  ▼
        │         RuleSet検索 ───▶ 権限フラグ確認
        │                  │
        │                  ▼
        └────────────── 許可/拒否
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ruleset.py | `src/backend/InvenTree/users/ruleset.py` | ソース | ルールセット定義 |
| models.py | `src/backend/InvenTree/users/models.py` | ソース | RuleSet, Ownerモデル |
| api.py | `src/backend/InvenTree/users/api.py` | ソース | グループ・ロールAPI |
| permissions.py | `src/backend/InvenTree/users/permissions.py` | ソース | 権限クラス定義 |
| serializers.py | `src/backend/InvenTree/users/serializers.py` | ソース | シリアライザ |
