# 画面設計書 8-設定管理画面

## 概要

本ドキュメントは、Etherpad Liteの設定管理画面の設計内容を記述するものである。この画面は、settings.jsonの内容を直接編集・保存し、サーバーの再起動を行うことができる管理機能を提供する。

### 本画面の処理概要

**業務上の目的・背景**：Etherpadの動作はsettings.jsonファイルで制御される。本画面は、システム管理者がWeb UIを通じて設定ファイルを直接編集できるようにし、サーバーへのSSHアクセスなしに設定変更を可能にする。設定変更後はサーバーの再起動も画面から実行でき、運用効率を向上させる。

**画面へのアクセス方法**：管理画面のサイドメニューから「Settings」を選択してアクセス。URLパスは `/admin/settings`。

**主要な操作・処理内容**：
1. 現在のsettings.json内容の表示（テキストエリア）
2. 設定内容の編集
3. 設定の保存（Saveボタン）
4. サーバーの再起動（Restartボタン）
5. サンプル設定へのリンク（本番用、開発用）

**画面遷移**：
- 遷移元: サイドメニュー
- 遷移先: サイドメニュー経由で他の管理画面、外部リンク（GitHub Wiki）

**権限による表示制御**：管理者権限（is_admin: true）を持つユーザーのみアクセス可能。settings.showSettingsInAdminPageがfalseの場合、設定内容は「NOT_ALLOWED」と表示され編集不可となる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | 設定管理 | 主機能 | settings.jsonの内容を表示・編集・保存 |
| 69 | 設定ファイル読み込み | 主機能 | settings.jsonから現在の設定を読み込み表示 |

## 画面種別

編集 / 設定

## URL/ルーティング

- **URL**: `/admin/settings`
- **HTTPメソッド**: GET（画面表示）
- **WebSocket名前空間**: `/settings`
- **コンポーネント**: `admin/src/pages/SettingsPage.tsx`

## 入出力項目

| 項目名 | 項目ID | 入力/出力 | データ型 | 必須 | 最大長 | 説明 |
|--------|--------|----------|---------|------|--------|------|
| 設定内容 | settings | 入力/出力 | テキスト（JSON） | - | - | settings.jsonの全内容 |

## 表示項目

| 項目名 | 項目ID | 説明 |
|--------|--------|------|
| ページタイトル | - | 「Current Settings」（i18n: admin_settings.current） |
| 設定テキストエリア | settings（class） | settings.json内容の表示・編集エリア |
| 保存ボタン | - | Saveアイコン + ラベル |
| 再起動ボタン | - | RotateCwアイコン + ラベル |
| サンプル設定リンク（本番） | - | 「Example Production Settings」 |
| サンプル設定リンク（開発） | - | 「Example Development Settings」 |

## イベント仕様

### 1-設定読み込み

画面アクセス時、WebSocket経由で設定読み込みリクエストが送信される（`load`イベント）。サーバーはsettings.jsonファイルを読み込み、内容を返送する（`settings`イベント）。settings.showSettingsInAdminPageがfalseの場合は「NOT_ALLOWED」が返される。

### 2-設定編集

テキストエリアで設定内容を編集すると、Zustandストアの`settings`状態が更新される。リアルタイムでローカル状態に反映されるが、保存するまでサーバーには送信されない。

### 3-設定保存

保存ボタン（Saveアイコン）をクリックすると以下の処理が実行される：
1. 入力内容がJSONとして有効かチェック（`isJSONClean`関数）
2. 有効な場合、WebSocket経由で保存リクエスト送信（`saveSettings`イベント）
3. サーバーがsettings.jsonファイルに書き込み
4. 成功時：トースト通知「Successfully saved settings」
5. 失敗時：トースト通知「Error saving settings」（JSON不正の場合）

### 4-サーバー再起動

再起動ボタン（RotateCwアイコン）をクリックすると、WebSocket経由で再起動リクエストが送信される（`restartServer`イベント）。サーバーは設定をリロードし、プラグインを更新し、loadSettingsフックとrestartServerフックを呼び出す。

### 5-サンプル設定リンク

「Example Production Settings」または「Example Development Settings」をクリックすると、GitHub Wikiの該当ページが新しいタブで開く。

## データベース更新仕様

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

設定管理はファイルシステム（settings.json）への書き込みであり、データベースには直接影響しない。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| 設定保存 | settings.json | ファイル書き込み | 設定ファイルを更新 |
| サーバー再起動 | メモリ | 設定リロード | 設定を再読み込みしてサーバー状態を更新 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| admin_settings.current | タイトル | Current Settings | ページタイトル |
| admin_settings.current_save.value | ボタンタイトル | Save | 保存ボタン |
| admin_settings.current_restart.value | ボタンタイトル | Restart | 再起動ボタン |
| admin_settings.current_example-prod | リンク | Example Production Settings | 本番サンプルリンク |
| admin_settings.current_example-devel | リンク | Example Development Settings | 開発サンプルリンク |
| - | 成功 | Successfully saved settings | 保存成功時（トースト） |
| - | エラー | Error saving settings | 保存失敗時（トースト） |

## 例外処理

| 例外状態 | 対応処理 | 表示内容 |
|---------|---------|---------|
| 設定読み込みエラー | エラーログ出力 | logger.error |
| 設定保存エラー | エラーログ出力 | logger.error |
| JSON構文エラー | 保存阻止 | 「Error saving settings」トースト |
| 権限不足 | 内容非表示 | 「NOT_ALLOWED」表示 |
| WebSocket切断 | 自動再接続 | 接続復帰時に再読み込み |

## 備考

- 設定内容はJSON形式のテキストとして表示・編集される
- コメント行（//）は`cleanComments`関数で処理される
- 保存前にJSONの妥当性チェックが行われる（`isJSONClean`関数）
- サーバー再起動はダウンタイムなしのホットリロード
- settings.showSettingsInAdminPageがfalseの場合、セキュリティのため設定内容は表示されない
- 外部リンクには`rel="noopener noreferrer"`と`target="_blank"`が設定される

---

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

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

### 推奨読解順序

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

設定管理では、settings.jsonの内容がテキストとしてストアに保持される。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | store.ts | `admin/src/store/store.ts` | settings, settingsSocket の状態管理 |
| 1-2 | utils.ts | `admin/src/utils/utils.ts` | isJSONClean, cleanComments 関数 |

**読解のコツ**: `cleanComments`は設定ファイル内のJavaScriptスタイルのコメント（//）を処理するためのユーティリティ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SettingsPage.tsx | `admin/src/pages/SettingsPage.tsx` | 設定管理画面コンポーネント全体 |

**主要処理フロー**:
1. **7行目**: SettingsPageコンポーネント定義
2. **8行目**: settingsSocket取得
3. **9行目**: settings取得（cleanComments適用）
4. **13行目**: テキストエリアでの設定表示
5. **14行目**: onChange でストア更新
6. **17-33行目**: 保存ボタン処理
7. **19行目**: isJSONCleanでバリデーション
8. **21行目**: saveSettingsイベント送信
9. **35-37行目**: 再起動ボタン処理
10. **42-47行目**: サンプル設定リンク

#### Step 3: サーバーサイドの設定処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | adminsettings.ts | `src/node/hooks/express/adminsettings.ts` | WebSocketイベントハンドラー |

**主要処理フロー**:
- **21-22行目**: Socket.IO名前空間 `/settings`
- **23-25行目**: 管理者権限チェック
- **27-40行目**: load - 設定ファイル読み込み
- **42-49行目**: saveSettings - 設定ファイル保存
- **307-313行目**: restartServer - サーバー再起動

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

```
[ブラウザ] GET /admin/settings
    │
    ├─ React SPA (SettingsPage.tsx)
    │      │
    │      ├─ WebSocket接続 (/settings)
    │      │      │
    │      │      └─ [サーバー] adminsettings.ts
    │      │              │
    │      │              ├─ load
    │      │              │      └─ fsp.readFile(settings.settingsFilename)
    │      │              │
    │      │              ├─ saveSettings
    │      │              │      └─ fsp.writeFile(settings.settingsFilename)
    │      │              │
    │      │              └─ restartServer
    │      │                     ├─ reloadSettings()
    │      │                     ├─ plugins.update()
    │      │                     └─ hooks.aCallAll('restartServer')
    │      │
    │      └─ UIレンダリング
    │             ├─ テキストエリア
    │             └─ ボタン群
```

### データフロー図

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

画面アクセス ──────▶ WebSocket 'load' ─────────▶ settings.json読み込み
                                                       │
                                                       ▼
                                               'settings' ─────────▶ テキストエリア表示

設定編集 ────────▶ setSettings() ─────────────▶ ストア更新
                   (onChange)                    (ローカル)

保存ボタン ──────▶ isJSONClean() ────────────▶ バリデーション
                                                       │
                              ┌───────────────────┴───────────────────┐
                              ▼                                       ▼
                        JSON有効                                JSON無効
                              │                                       │
                              ▼                                       ▼
                   WebSocket 'saveSettings'                   トースト「Error」
                              │
                              ▼
                   fsp.writeFile()
                              │
                              ▼
                   トースト「Success」

再起動ボタン ────▶ WebSocket 'restartServer' ──▶ 設定リロード
                                                   プラグイン更新
                                                   フック呼び出し
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SettingsPage.tsx | `admin/src/pages/SettingsPage.tsx` | ソース | 設定管理画面コンポーネント |
| store.ts | `admin/src/store/store.ts` | ソース | 状態管理ストア |
| utils.ts | `admin/src/utils/utils.ts` | ソース | isJSONClean, cleanComments |
| adminsettings.ts | `src/node/hooks/express/adminsettings.ts` | ソース | WebSocketハンドラー |
| Settings.ts | `src/node/utils/Settings.ts` | ソース | 設定管理、reloadSettings |
| IconButton.tsx | `admin/src/components/IconButton.tsx` | ソース | アイコンボタンコンポーネント |
