# 通知設計書 36-権限必須

## 概要

本ドキュメントは、InvenTreeモバイルアプリケーションにおける「権限必須」通知の設計仕様を定義するものです。この通知は、ホーム画面などで権限が必要な機能にアクセスしようとした際、クライアント側で権限チェックを行い、権限不足の場合にユーザーに表示されるスナックバー通知です。

### 本通知の処理概要

この通知は、ユーザーがアプリ内で権限を必要とする操作（例：購買発注一覧の表示）にアクセスしようとした際、クライアント側での事前権限チェックで権限不足が検出された場合にフィードバックを提供する機能です。

**業務上の目的・背景**：InvenTreeはロールベースのアクセス制御を採用しており、ユーザーの権限はサーバー接続時に取得されます。この通知により、APIリクエストを送信する前にクライアント側で権限不足を検出し、不要なネットワーク通信を回避しながらユーザーに適切なフィードバックを提供します。

**通知の送信タイミング**：ホーム画面のタイル（_listTile）をタップした際、`InvenTreeAPI().checkRole()` で権限チェックを行い、権限がない場合に即座に通知が発生します。

**通知の受信者**：通知は、アプリを操作している現在のユーザーに対してのみ表示されます。

**通知内容の概要**：国際化対応されたメッセージ「Permission Required」（または相当するローカライズ文字列）がスナックバーとして画面下部に表示されます。エラーを示すオレンジ色の背景と警告アイコン（exclamation_circle）が付加されます。

**期待されるアクション**：ユーザーは権限が不足していることを理解し、管理者に権限付与を依頼するか、権限の範囲内で操作を行うことが期待されます。

## 通知種別

アプリ内通知（スナックバー）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | なし |

### 送信先決定ロジック

アプリの現在アクティブなユーザーに対してのみ表示されます。

## 通知テンプレート

### スナックバー通知の場合

| 項目 | 内容 |
|-----|------|
| 背景色 | オレンジ（Colors.deepOrange） |
| アイコン | TablerIcons.exclamation_circle |
| 表示時間 | 5秒 |
| 閉じるボタン | あり |

### 本文テンプレート

```
{L10().permissionRequired}
```

実際の表示例（英語）：
```
Permission Required
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| permissionRequired | 権限必須メッセージ | L10()国際化リソース | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ホームタイルタップ | !allowed (checkRole失敗) | 権限が必要な機能へのアクセス試行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 権限あり | checkRole()がtrueを返す場合はコールバック実行 |
| roleが空 | ロールが設定されていない機能は権限チェックをスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ホームタイルタップ] --> B{ロール設定あり?}
    B -->|なし| C[コールバック実行]
    B -->|あり| D[checkRole実行]
    D --> E{権限あり?}
    E -->|あり| C
    E -->|なし| F[showSnackIcon呼び出し]
    F --> G[スナックバー表示]
    G --> H[何も実行しない]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（クライアントサイドのキャッシュされた権限情報を参照）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 権限不足 | ユーザーに操作権限がない | 通知表示、操作は実行しない |
| コンテキスト不在 | Flutterコンテキストが無効 | 通知をスキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（権限付与後に手動再試行） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（24時間対応）

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

- 必要な権限の詳細（ロール名など）はスナックバーに含まれない
- 認証済みユーザーのみがアプリを使用可能
- 権限情報はサーバー接続時に取得され、クライアントでキャッシュされる

## 備考

- この通知はAPIリクエスト前のクライアント側チェックで発生し、No.35の権限エラーとは異なる
- ホーム画面のタイルは権限がない場合、視覚的にグレーアウト表示される
- 国際化対応により、アプリの言語設定に応じたメッセージが表示される

---

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

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

### 推奨読解順序

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

まず、権限情報のキャッシュとcheckRole()メソッドを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api.dart | `lib/api.dart` | roles変数とcheckRole()メソッド（行242, 763-807） |

**読解のコツ**: rolesはMap<String, dynamic>型で、キーがロール名、値がパーミッションのリスト

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

_listTile()メソッドでの権限チェックと通知表示を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | home.dart | `lib/widget/home.dart` | _listTile()メソッド（行225-272） |

**主要処理フロー**:
1. **行225-233**: メソッド定義とパラメータ（role, permission含む）
2. **行238-240**: role/permissionが設定されている場合の権限チェック
3. **行257-265**: タップ時の処理
4. **行258-264**: `if (!allowed)` の場合、showSnackIcon呼び出し
5. **行259-263**: `showSnackIcon(L10().permissionRequired, icon: TablerIcons.exclamation_circle, success: false)`

#### Step 3: 視覚的フィードバックを理解する

権限がない場合のグレーアウト表示を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | home.dart | `lib/widget/home.dart` | _listTile内のアイコンカラー設定（行248-250） |

**主要処理フロー**:
- **行248-250**: `color: connected && allowed ? COLOR_ACTION : Colors.grey` - 権限がない場合はグレー

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

```
_InvenTreeHomePageState  [lib/widget/home.dart]
    │
    ├─ getListTiles()  [行277]
    │      └─ 各タイル生成（_listTile呼び出し）
    │
    └─ _listTile()  [行225]
           │
           ├─ InvenTreeAPI().checkRole()  [行239]
           │      └─ 権限チェック
           │
           └─ onTap時
                  │
                  ├─ if (!allowed)
                  │      └─ showSnackIcon()  [行259]
                  │             └─ L10().permissionRequired
                  │
                  └─ if (allowed && callback != null)
                         └─ callback()  [行267]
```

### データフロー図

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

ホームタイルタップ ───▶  _listTile.onTap              ───▶  スナックバー表示
                          ├─ checkRole()                      │
                          └─ 権限なし判定                     └─ 「Permission Required」
                                                                メッセージ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| home.dart | `lib/widget/home.dart` | ソース | ホーム画面、_listTile()メソッド |
| api.dart | `lib/api.dart` | ソース | checkRole()メソッド、roles変数 |
| snacks.dart | `lib/widget/snacks.dart` | ソース | showSnackIcon関数の実装 |
| l10.dart | `lib/l10.dart` | ソース | 国際化ヘルパー関数L10() |
| app_colors.dart | `lib/app_colors.dart` | ソース | COLOR_ACTION定義 |
