# 通知設計書 22-システム通知

## 概要

本ドキュメントは、Ghost CMS管理画面に表示されるシステム通知（アラート/情報通知）機能の設計仕様を記載する。

### 本通知の処理概要

Ghost管理画面（Admin）に表示されるアプリ内通知機能である。リリース通知、カスタム通知、セキュリティアラートなど、サイト管理者に対して重要な情報をリアルタイムで伝達する。この通知はブラウザ上の管理画面に直接表示され、ユーザーの操作を中断することなく情報を提示できる。

**業務上の目的・背景**：サイト管理者は日常的に管理画面を使用してコンテンツ管理を行う。新しいGhostバージョンのリリース、セキュリティ上の重要な警告、カスタム運用通知などを管理画面で直接表示することで、管理者が重要な情報を見逃さずに済む。メール通知とは異なり、即座に管理者の目に入る形で情報を提供できる。

**通知の送信タイミング**：主に2つのトリガーがある。(1) 更新チェックサービスから通知を受信した際に`notifications.add` APIを通じて追加される。(2) Ghost内部のサービスやAPI経由で直接追加される場合もある。

**通知の受信者**：Ghost管理画面にログインしているすべてのユーザーが対象。ただし、通知の「seen」状態はユーザーごとに管理され、一度閲覧・消去した通知は再表示されない。

**通知内容の概要**：新バージョンリリース情報、セキュリティアラート、カスタム運用メッセージなど。各通知には`type`（info/warn/error/alert）、`status`（alert/notification）、`dismissible`（消去可能かどうか）などの属性がある。

**期待されるアクション**：管理者は通知内容を確認し、必要に応じて推奨されるアクション（アップデート実施、設定変更など）を行う。消去可能な通知は確認後に閉じることができる。

## 通知種別

アプリ内通知（管理画面通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（API経由でsettingsに保存） |
| 優先度 | 通知タイプにより異なる（alert > notification） |
| リトライ | N/A（データベース保存） |

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

1. 通知は`settings`テーブルの`notifications`キーにJSON配列として保存される
2. 管理画面ログイン時にAPIを通じて通知一覧を取得
3. 各ユーザーの`seen`状態に基づいて未読通知のみをフィルタリングして表示
4. バージョン比較ロジックにより、古いリリース通知は自動的に非表示

## 通知テンプレート

### 管理画面通知の場合

| 項目 | 内容 |
|-----|------|
| 表示位置 | 管理画面上部または下部（`location`プロパティ） |
| タイプ | `info`, `warn`, `error`, `alert` |
| ステータス | `alert`, `notification` |
| 消去可能 | `dismissible`プロパティで制御 |

### メッセージ構造

```json
{
    "id": "f8ff6c80-aa61-11e7-a126-6119te37e2b8",
    "type": "info",
    "status": "alert",
    "message": "Ghost 5.0 is now available! Check out the release notes.",
    "dismissible": true,
    "top": true,
    "location": "bottom",
    "seen": false,
    "addedAt": "2024-01-01T00:00:00.000Z",
    "createdAtVersion": "5.0.0",
    "custom": false
}
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| id | 通知の一意識別子 | 自動生成（ObjectId）または外部提供 | Yes |
| type | 通知タイプ | 通知作成時に指定 | No（デフォルト: info） |
| status | 通知ステータス | 通知作成時に指定 | No（デフォルト: alert） |
| message | 通知メッセージ本文 | 通知作成時に指定 | Yes |
| dismissible | 消去可能フラグ | 通知作成時に指定 | No（デフォルト: true） |
| top | 画面上部表示フラグ | 通知作成時に指定 | No |
| location | 表示位置 | 通知作成時に指定 | No（デフォルト: bottom） |
| custom | カスタム通知フラグ | 通知作成時に指定 | No |
| createdAtVersion | 作成時Ghostバージョン | ghostVersion.full | No（自動設定） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| APIコール | `notifications.add` | なし | 内部APIまたは更新チェックサービスから呼び出し |
| 更新チェック | 更新チェックレスポンス受信 | `messages`配列に通知が含まれる場合 | 定期更新チェックからの通知登録 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 重複チェック | 同一IDの通知が既に存在する場合は追加されない |
| バージョンフィルタ | リリース通知はGhostバージョンより新しい場合のみ表示 |
| 閲覧済みチェック | ユーザーが閲覧済み（seen）の通知は非表示 |
| カスタム通知グループ | 通知グループ設定によるフィルタリング |

## 処理フロー

### 通知追加フロー

```mermaid
flowchart TD
    A[通知追加リクエスト] --> B[既存通知一覧取得]
    B --> C{重複チェック}
    C -->|重複あり| D[スキップ]
    C -->|重複なし| E[デフォルト値マージ]
    E --> F{リリース通知?}
    F -->|Yes| G[既存リリース通知を削除]
    F -->|No| H[通知配列に追加]
    G --> H
    H --> I[settings.notifications更新]
    I --> J[終了]
    D --> J
```

### 通知表示フロー

```mermaid
flowchart TD
    A[管理画面アクセス] --> B[notifications API呼出]
    B --> C[settings.notifications取得]
    C --> D[seen状態フィルタ]
    D --> E[バージョンフィルタ]
    E --> F[日付順ソート]
    F --> G[管理画面に表示]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| settings | 通知データの保存 | `key = 'notifications'` |

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

#### settings

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| value | 通知JSON配列 | `key = 'notifications'` |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| settings | UPDATE | notifications配列の更新 |

#### settings更新詳細

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | value | 通知配列JSON | `key = 'notifications'` |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 消去不可エラー | `dismissible: false`の通知を消去しようとした場合 | NoPermissionErrorを返す |
| 通知不存在エラー | 存在しないIDの通知を操作しようとした場合 | NotFoundErrorを返す |
| データ破損 | notifications配列が不正な形式 | `dangerousDestroyAll()`で自己修復 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | N/A（同期処理） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（リアルタイム表示）

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

- 通知の消去（destroy）は認証されたユーザーのみが実行可能
- `dismissible: false`の通知は消去不可（重要なセキュリティ警告など）
- 通知メッセージはHTMLを含む可能性があり、XSS対策が必要（管理画面側で対応）
- `seenBy`配列によりユーザーごとの閲覧状態を管理

## 備考

- 通知データは`settingsCache`を通じてキャッシュされ、パフォーマンスが最適化されている
- リリース通知は1件のみ保持され、新しいリリース通知が追加されると古いものは削除される
- `createdAtVersion`プロパティにより、Ghostアップグレード後に古い通知を自動的にフィルタリング可能
- `dangerousDestroyAll()`はデータ破損時の自己修復機能として用意されている

---

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

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

### 推奨読解順序

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

通知オブジェクトの構造とsettings保存形式を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | default-settings.json | `ghost/core/core/server/data/schema/default-settings/default-settings.json` | 19-22行目、notificationsのデフォルト値（空配列） |
| 1-2 | notifications.js | `ghost/core/core/server/services/notifications/notifications.js` | 123-135行目、add()メソッドのdefaults/overrides定義 |

**読解のコツ**: 通知オブジェクトは`id`, `type`, `status`, `message`, `dismissible`, `top`, `location`, `seen`, `seenBy`, `addedAt`, `createdAtVersion`, `custom`などのプロパティを持つ。

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

通知サービスの初期化と公開APIを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `ghost/core/core/server/services/notifications/index.js` | サービスインスタンスのエクスポート |

**主要処理フロー**:
1. **5-8行目**: `Notifications`クラスのインスタンス化とエクスポート

#### Step 3: 通知管理ロジックを理解する

`Notifications`クラスの各メソッドの処理を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | notifications.js | `ghost/core/core/server/services/notifications/notifications.js` | Notificationsクラス全体 |

**主要処理フロー**:
- **29-48行目**: `fetchAllNotifications()` - 全通知取得と自己修復
- **72-121行目**: `browse()` - 通知一覧取得（フィルタリング込み）
- **123-181行目**: `add()` - 通知追加
- **192-229行目**: `destroy()` - 通知消去（seen状態に変更）
- **248-256行目**: `dangerousDestroyAll()` - 完全削除（自己修復用）

#### Step 4: バージョンフィルタリングを理解する

リリース通知のバージョン比較ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | notifications.js | `ghost/core/core/server/services/notifications/notifications.js` | 77-118行目 |

**主要処理フロー**:
- **78-79行目**: `createdAtVersion`とブログバージョンの比較
- **87-114行目**: レガシーな通知のバージョン検出（正規表現使用）

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

```
API Controller (notifications)
    │
    └─ notifications.browse({user})
           │
           ├─ fetchAllNotifications()
           │      │
           │      ├─ settingsCache.get('notifications')
           │      │
           │      └─ areNotificationsValid() → 不正時: dangerousDestroyAll()
           │
           ├─ wasSeen(notification, user) → 各通知の閲覧状態確認
           │
           └─ バージョンフィルタリング → semver比較

    │
    └─ notifications.add({notifications})
           │
           ├─ fetchAllNotifications()
           │
           ├─ 重複チェック（id比較）
           │
           ├─ デフォルト値マージ
           │
           └─ [リリース通知] 既存リリース通知削除

    │
    └─ notifications.destroy({notificationId, user})
           │
           ├─ fetchAllNotifications()
           │
           ├─ dismissibleチェック
           │
           └─ seen = true, seenBy.push(user.id)
```

### データフロー図

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

更新チェックサービス
または内部API ────────▶ notifications.add()
                              │
                              ▼
                        fetchAllNotifications()
                              │
                              ▼
                        重複チェック
                              │
                              ▼
                        デフォルト値適用
                              │
                              ▼
                        settings更新 ──────────────────▶ settingsテーブル
                                                         (key=notifications)

管理画面アクセス ────────▶ notifications.browse()
                              │
                              ▼
                        fetchAllNotifications()
                              │
                              ▼
                        seenフィルタ
                              │
                              ▼
                        バージョンフィルタ
                              │
                              ▼
                        日付ソート ────────────────────▶ 管理画面表示

通知消去クリック ────────▶ notifications.destroy()
                              │
                              ▼
                        seen = true設定
                              │
                              ▼
                        seenBy配列に追加
                              │
                              ▼
                        settings更新 ──────────────────▶ settingsテーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notifications.js | `ghost/core/core/server/services/notifications/notifications.js` | ソース | 通知管理のメインロジック |
| index.js | `ghost/core/core/server/services/notifications/index.js` | ソース | サービスインスタンスのエクスポート |
| default-settings.json | `ghost/core/core/server/data/schema/default-settings/default-settings.json` | 設定 | notificationsのデフォルト値定義 |
| update-check-service.js | `ghost/core/core/server/services/update-check/update-check-service.js` | ソース | 通知追加の呼び出し元 |
