# 通知設計書 1-Admin Notification

## 概要

本ドキュメントは、Shopwareの管理画面（Administration）向けリアルタイム通知機能「Admin Notification」の設計書である。この通知機能は、システム内部の重要なイベントや状態変化を管理者にリアルタイムで伝達するためのアプリ内通知システムである。

### 本通知の処理概要

Admin Notificationは、管理画面にログインしている管理者やAPI連携先に対して、システム内で発生した重要なイベントをリアルタイムで通知する機能である。

**業務上の目的・背景**：ECサイトの運営において、プラグインのインストール完了、システムアップデートの通知、エラー発生など、管理者が即座に把握すべき情報を適時に伝達する必要がある。従来のメール通知では即時性に欠けるため、管理画面内でのリアルタイム通知が求められた。

**通知の送信タイミング**：API（POST /api/notification）を通じて通知が作成された時点、またはシステム内部のイベント（例：NewServicesInstalledEvent）発生時に通知が生成される。フロントエンドは5秒間隔でポーリングし、新規通知を取得する。

**通知の受信者**：管理画面にログインしている管理者ユーザー。adminOnlyフラグがtrueの場合は管理者のみ、falseの場合はrequiredPrivilegesで指定された権限を持つユーザーが受信可能。

**通知内容の概要**：ステータス（positive/warning/error等）、メッセージ本文、作成者情報（ユーザーまたはIntegration）が含まれる。

**期待されるアクション**：通知内容に応じて、管理者は適切な対応（画面のリロード、設定変更、エラー調査等）を行う。

## 通知種別

アプリ内通知（管理画面リアルタイム通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（ポーリング方式） |
| 優先度 | 高 |
| リトライ | なし（データベース永続化） |

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

1. 通知取得時にログインユーザーのContextを確認
2. adminOnlyがtrueの場合：ユーザーが管理者（isAdmin）であれば表示
3. adminOnlyがfalseの場合：requiredPrivilegesに指定された権限をすべて持つユーザーに表示
4. 権限チェックは`NotificationService::isAllow()`メソッドで実行

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| 表示形式 | トースト通知 |
| ステータス種別 | positive / warning / error / info |

### 本文テンプレート

```
{message}
```

メッセージはAPI呼び出し時またはシステム内部で動的に設定される。

### 添付ファイル

なし（アプリ内通知のため添付ファイル非対応）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| status | 通知ステータス | API/システム | Yes |
| message | 通知メッセージ | API/システム | Yes |
| adminOnly | 管理者限定フラグ | API/システム | No（デフォルト: false） |
| requiredPrivileges | 必要権限リスト | API/システム | No（デフォルト: []） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | POST /api/notification | 認証済み、レート制限内 | 外部からの通知作成 |
| システムイベント | NewServicesInstalledEvent | サービスインストール完了 | 新サービスインストール時の管理者通知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| レート制限超過 | 同一ユーザー/Integration+IPからの過剰なリクエスト |
| 必須パラメータ不足 | status, messageが空の場合 |
| 認証エラー | AdminApiSource以外からのアクセス |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[通知作成リクエスト/イベント発生] --> B[認証・権限チェック]
    B -->|OK| C[パラメータバリデーション]
    B -->|NG| D[認証エラー返却]
    C -->|OK| E[レート制限チェック]
    C -->|NG| F[バリデーションエラー返却]
    E -->|OK| G[通知データ作成]
    E -->|NG| H[レート制限エラー返却]
    G --> I[DBへ永続化]
    I --> J[通知ID返却]

    K[フロントエンド] --> L[5秒間隔でポーリング]
    L --> M[GET /api/notification/message]
    M --> N[権限に基づく通知取得]
    N --> O[トースト通知表示]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| notification | 通知データ取得 | 作成日時でソート |
| user | 作成者情報取得 | createdByUserId参照 |
| integration | 作成者Integration情報取得 | createdByIntegrationId参照 |

### テーブル別参照項目詳細

#### notification

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 通知識別子 | PRIMARY KEY |
| status | ステータス表示 | - |
| message | メッセージ表示 | - |
| admin_only | 管理者限定判定 | - |
| required_privileges | 権限チェック | - |
| created_at | タイムスタンプ比較 | WHERE created_at > latestTimestamp |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| notification | INSERT | 通知レコード作成 |

#### notification

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | id | UUID | Uuid::randomHex() |
| INSERT | status | APIパラメータ | positive/warning/error等 |
| INSERT | message | APIパラメータ | 通知メッセージ |
| INSERT | admin_only | APIパラメータ | デフォルトfalse |
| INSERT | required_privileges | APIパラメータ | JSON配列 |
| INSERT | created_by_integration_id | Context取得 | Integration ID |
| INSERT | created_by_user_id | Context取得 | User ID |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 認証エラー | AdminApiSource以外からのアクセス | NotificationException::invalidAdminSource |
| バリデーションエラー | status/messageが空 | NotificationException::invalidRequestParameter |
| レート制限エラー | 短時間に大量リクエスト | NotificationException::notificationThrottled |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限単位 | ユーザーID または Integration+クライアントIP |
| 制限内容 | RateLimiterによる制御 |

### 配信時間帯

制限なし（24時間365日）

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

- AdminApiSourceによる認証必須
- レート制限による過負荷防止
- 権限ベースのアクセス制御（requiredPrivileges）
- 通知テーブルへの直接アクセスはSYSTEM_SCOPEでのみ許可

## 備考

- 通知データはデータベースに永続化されるため、画面リロード後も未読通知を取得可能
- フロントエンドはAdminNotificationWorkerにより5秒間隔で自動ポーリング
- ユーザー設定（user_config）に最終読み取りタイムスタンプを保存し、重複表示を防止

---

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

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

### 推奨読解順序

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

まず、通知エンティティの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | NotificationDefinition.php | `src/Core/Framework/Notification/NotificationDefinition.php` | 通知テーブルのフィールド定義、デフォルト値を確認 |
| 1-2 | NotificationEntity.php | `src/Core/Framework/Notification/NotificationEntity.php` | エンティティのプロパティ、getter/setterを確認 |

**読解のコツ**: EntityDefinitionクラスはShopwareのDAL（Data Abstraction Layer）の基盤。defineFields()メソッドでフィールド定義、getDefaults()でデフォルト値を確認。

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

処理の起点となるAPIコントローラーを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NotificationController.php | `src/Core/Framework/Notification/Api/NotificationController.php` | saveNotification/fetchNotificationの2つのエンドポイントを確認 |

**主要処理フロー**:
1. **行42-97**: saveNotification() - 通知作成API
2. **行99-113**: fetchNotification() - 通知取得API

#### Step 3: ビジネスロジック層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NotificationService.php | `src/Core/Framework/Notification/NotificationService.php` | createNotification/getNotificationsメソッドの実装 |

**主要処理フロー**:
- **行33-38**: createNotification() - SYSTEM_SCOPEでの通知作成
- **行43-91**: getNotifications() - 権限に基づく通知取得
- **行93-105**: formatNotifications() - 権限フィルタリング
- **行110-118**: isAllow() - 権限チェック

#### Step 4: フロントエンド連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | admin-notification-worker.js | `src/Administration/Resources/app/administration/src/core/worker/admin-notification-worker.js` | ポーリング処理、通知表示の実装 |

**主要処理フロー**:
- **行22-29**: start() - ワーカー開始
- **行32-55**: loadNotifications() - 5秒間隔のポーリング
- **行64-68**: createNotification() - トースト通知表示

#### Step 5: システムイベントからの通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ServiceLifecycleSubscriber.php | `src/Core/Service/Subscriber/ServiceLifecycleSubscriber.php` | NewServicesInstalledEventの処理 |
| 5-2 | Notification.php | `src/Core/Service/Notification.php` | newServicesInstalled()メソッドの実装 |

**主要処理フロー**:
- **行42-45**: sendInstalledNotification() - イベント処理
- **行20-32** (Notification.php): newServicesInstalled() - 通知作成

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

```
[API呼び出し] POST /api/notification
    │
    └─ NotificationController::saveNotification()
           │
           ├─ RateLimiter::ensureAccepted()
           │
           └─ NotificationService::createNotification()
                  │
                  └─ EntityRepository::create()

[システムイベント] NewServicesInstalledEvent
    │
    └─ ServiceLifecycleSubscriber::sendInstalledNotification()
           │
           └─ Notification::newServicesInstalled()
                  │
                  └─ NotificationService::createNotification()

[フロントエンド] AdminNotificationWorker
    │
    └─ loadNotifications() [5秒間隔]
           │
           └─ GET /api/notification/message
                  │
                  └─ NotificationController::fetchNotification()
                         │
                         └─ NotificationService::getNotifications()
```

### データフロー図

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

API Request ─────────▶ NotificationController ─────▶ JSON Response
  - status               saveNotification()            - id
  - message
  - adminOnly
  - requiredPrivileges

SystemEvent ─────────▶ ServiceLifecycleSubscriber ──▶ DB Insert
  NewServicesInstalledEvent   sendInstalledNotification()

PollingRequest ──────▶ NotificationController ─────▶ JSON Response
  - limit                fetchNotification()           - notifications[]
  - latestTimestamp                                    - timestamp
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NotificationController.php | `src/Core/Framework/Notification/Api/NotificationController.php` | ソース | APIエンドポイント |
| NotificationService.php | `src/Core/Framework/Notification/NotificationService.php` | ソース | ビジネスロジック |
| NotificationDefinition.php | `src/Core/Framework/Notification/NotificationDefinition.php` | ソース | エンティティ定義 |
| NotificationEntity.php | `src/Core/Framework/Notification/NotificationEntity.php` | ソース | エンティティクラス |
| NotificationCollection.php | `src/Core/Framework/Notification/NotificationCollection.php` | ソース | コレクションクラス |
| NotificationException.php | `src/Core/Framework/Notification/NotificationException.php` | ソース | 例外クラス |
| ServiceLifecycleSubscriber.php | `src/Core/Service/Subscriber/ServiceLifecycleSubscriber.php` | ソース | イベントサブスクライバー |
| Notification.php | `src/Core/Service/Notification.php` | ソース | サービス通知ヘルパー |
| admin-notification-worker.js | `src/Administration/Resources/app/administration/src/core/worker/admin-notification-worker.js` | ソース | フロントエンドワーカー |
| worker.init.ts | `src/Administration/Resources/app/administration/src/app/init-post/worker.init.ts` | ソース | ワーカー初期化 |
