# 通知設計書 13-デモモード通知

## 概要

本ドキュメントは、RuoYiシステムにおけるデモモード通知（DemoModeException）の設計について記載する。デモモードが有効な環境において、データ変更操作が制限されていることをユーザーに通知する機構を定義する。

### 本通知の処理概要

デモモード通知は、システムがデモモード（demoEnabled=true）で動作している場合に、データ変更を伴う操作（登録・更新・削除等）が実行された際にユーザーへ操作制限を通知する機構である。DemoModeExceptionがスローされると、GlobalExceptionHandlerによりキャッチされ、固定のエラーメッセージ「演示模式，不允许操作」がJSONレスポンスとして返却される。

**業務上の目的・背景**：RuoYiシステムを公開デモサイトとして運用する場合、不特定多数のユーザーがシステムを試用することになる。このとき、データの永続的な変更（ユーザー追加、設定変更、データ削除等）を許可すると、デモ環境が汚染され、他のユーザーの体験が損なわれる。デモモード機能により、閲覧・検索は許可しつつ、変更操作を制限することで安全なデモ環境を提供する。

**通知の送信タイミング**：デモモードが有効（ruoyi.demoEnabled=true）な環境で、データ変更を伴うAPI（POST/PUT/DELETE等のHTTPメソッド、または特定の業務操作）が呼び出された際にDemoModeExceptionがスローされ、通知が発生する。

**通知の受信者**：HTTPリクエストを送信したクライアント（ブラウザ、APIクライアント）が受信者となる。JSONレスポンスとして返却される。

**通知内容の概要**：固定メッセージ「演示模式，不允许操作」（デモモードのため操作できません）がエラーメッセージとして返却される。例外にカスタムメッセージを設定する機能はなく、常に同じメッセージが返却される。

**期待されるアクション**：ユーザーはデモモードでは変更操作ができないことを理解し、閲覧・検索操作に留める。実際にシステムを利用したい場合は、正式版の導入を検討するか、ローカル環境でデモモードを無効化して動作確認を行う。

## 通知種別

アプリ内通知（HTTPレスポンス）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無 |

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

HTTPリクエストを送信したクライアントに対して直接レスポンスとして返却する。送信先の決定はHTTPプロトコルにより自動的に行われる。

## 通知テンプレート

### JSONレスポンス

| 項目 | 内容 |
|-----|------|
| レスポンス形式 | JSON |
| HTTPステータス | 200 OK |

### 本文テンプレート

```json
{
  "code": 500,
  "msg": "演示模式，不允许操作"
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| msg | エラーメッセージ | 固定値「演示模式，不允许操作」 | Yes |
| code | ステータスコード | AjaxResult.Type.ERROR (500) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | データ変更操作 | demoEnabled=true の場合 | 登録・更新・削除等の変更操作 |
| API呼び出し | POST/PUT/DELETE等 | demoEnabled=true の場合 | データ変更を伴うHTTPメソッド |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| demoEnabled=false | デモモードが無効な場合は通知されない |
| 参照系操作 | GET等の参照系操作は制限されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[データ変更操作リクエスト] --> B{demoEnabled?}
    B -->|true| C[DemoModeException生成・スロー]
    B -->|false| D[通常処理継続]
    C --> E[GlobalExceptionHandler.handleDemoModeException]
    E --> F[AjaxResult.error作成]
    F --> G[JSONレスポンス返却]
    G --> H[終了]
    D --> I[業務処理実行]
    I --> H
```

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

### 参照テーブル一覧

該当なし（デモモード判定は設定値により行われる）

### 更新テーブル一覧

該当なし（デモモード時はデータ更新が行われない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| デモモード制限 | demoEnabled=trueで変更操作 | 固定エラーメッセージを返却 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（同期処理のため） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（システム稼働中は常時）

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

- デモモードはシステム設定（application.yml）で制御されるため、リクエストパラメータで無効化することはできない
- 固定メッセージを返却するため、システム内部情報は漏洩しない
- デモモードであってもログイン認証は必要（認証なしでの全機能開放ではない）

## 備考

- DemoModeExceptionは空のコンストラクタのみを持ち、カスタムメッセージは設定できない
- 実例演示メニュー（demoEnabled時に表示）とは別の概念であり、デモモード制限はシステム全体のデータ変更を制限する
- 設定ファイル（application.yml）の`ruoyi.demoEnabled`で制御

---

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

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

### 推奨読解順序

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

まず、例外クラスと設定クラスの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DemoModeException.java | `ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java` | デモモード例外クラス、空のコンストラクタのみ |
| 1-2 | RuoYiConfig.java | `ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java` | demoEnabledフィールド、isDemoEnabled()メソッド |
| 1-3 | application.yml | `ruoyi-admin/src/main/resources/application.yml` | ruoyi.demoEnabled設定 |

**読解のコツ**: DemoModeExceptionはRuntimeExceptionを継承しており、シンプルな例外クラスである。メッセージはハンドラー側で固定設定される。

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

例外ハンドラーの処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | GlobalExceptionHandler.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java` | @ExceptionHandler(DemoModeException.class)によるハンドリング |

**主要処理フロー**:
1. **144行目**: `@ExceptionHandler(DemoModeException.class)` - DemoModeExceptionをキャッチ
2. **145行目**: `public AjaxResult handleDemoModeException(DemoModeException e)` - ハンドラーメソッド
3. **147行目**: `return AjaxResult.error("演示模式，不允许操作")` - 固定メッセージでエラーレスポンス返却

#### Step 3: 設定と画面表示を理解する

デモモード設定が画面にどのように反映されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SysIndexController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java` | demoEnabled値を画面に渡す処理 |
| 3-2 | index.html | `ruoyi-admin/src/main/resources/templates/index.html` | demoEnabled時の「実例演示」メニュー表示 |
| 3-3 | index-topnav.html | `ruoyi-admin/src/main/resources/templates/index-topnav.html` | トップナビ型での「実例演示」メニュー表示 |

**主要処理フロー**:
- **SysIndexController 65行目**: `mmap.put("demoEnabled", RuoYiConfig.isDemoEnabled())` - テンプレートにdemoEnabled値を渡す
- **index.html 74行目**: `<li th:if="${demoEnabled}">` - demoEnabled時にメニュー表示
- **index-topnav.html 93,243行目**: 同様にdemoEnabled時にタブ・メニュー表示

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

```
Controller (任意のデータ変更API)
    │
    ├─ [demoEnabled=true時]
    │      │
    │      └─ throw new DemoModeException()
    │             │
    │             └─ GlobalExceptionHandler.handleDemoModeException()
    │                    │
    │                    └─ AjaxResult.error("演示模式，不允许操作")
    │                           │
    │                           └─ JSONレスポンス返却
    │
    └─ [demoEnabled=false時]
           │
           └─ 通常の業務処理実行
```

### データフロー図

```
[設定]                    [処理]                         [出力]

application.yml ──▶ RuoYiConfig.isDemoEnabled() ──┐
(demoEnabled=true)                                │
                                                  ▼
変更操作リクエスト ──▶ DemoModeException ──▶ GlobalExceptionHandler
                                                  │
                                                  ▼
                                           AjaxResult (JSON)
                                           {"code":500,"msg":"演示模式，不允许操作"}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DemoModeException.java | `ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java` | ソース | デモモード例外クラス定義 |
| GlobalExceptionHandler.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java` | ソース | 全体例外ハンドラー |
| RuoYiConfig.java | `ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java` | ソース | グローバル設定クラス |
| AjaxResult.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java` | ソース | Ajaxレスポンス構造体 |
| application.yml | `ruoyi-admin/src/main/resources/application.yml` | 設定 | アプリケーション設定 |
| SysIndexController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java` | ソース | インデックスコントローラ |
| index.html | `ruoyi-admin/src/main/resources/templates/index.html` | テンプレート | サイドナビ型インデックスページ |
| index-topnav.html | `ruoyi-admin/src/main/resources/templates/index-topnav.html` | テンプレート | トップナビ型インデックスページ |
