# 画面設計書 10-パッド管理画面

## 概要

本ドキュメントは、Etherpad Liteのパッド管理画面の設計内容を記述するものである。この画面は、全パッドの一覧表示、検索、削除、リビジョンクリーンアップ、新規パッド作成機能を提供する管理画面である。

### 本画面の処理概要

**業務上の目的・背景**：システム管理者がEtherpad上の全パッドを一元管理するための機能を提供する。パッドの棚卸し、不要パッドの削除、ディスク容量節約のためのリビジョンクリーンアップ、テスト用パッドの作成など、運用管理に必要な操作を集約している。

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

**主要な操作・処理内容**：
1. パッド一覧の表示（ページネーション付き）
2. パッド名による検索・フィルタリング
3. パッドの削除（確認ダイアログ付き）
4. リビジョンクリーンアップ（古いリビジョンを削除してディスク節約）
5. 新規パッドの作成
6. パッドを開く（新しいタブで編集画面へ）
7. ソート切り替え（パッド名、ユーザー数、最終編集日時、リビジョン数）

**画面遷移**：
- 遷移元: サイドメニュー
- 遷移先: サイドメニュー経由で他の管理画面、パッド編集画面（新しいタブ）

**権限による表示制御**：管理者権限（is_admin: true）を持つユーザーのみアクセス可能。WebSocket接続時にセッションの権限が検証される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | パッド管理 | 主機能 | パッドの検索・一覧表示・削除・リビジョンクリーンアップ |
| 12 | 全パッド一覧取得 | 主機能 | すべてのパッドIDを一覧で取得して表示 |
| 6 | パッド作成 | 補助機能 | 新規パッド作成ダイアログからパッドを作成 |
| 8 | パッド削除 | 補助機能 | 削除ボタンでパッドを削除 |
| 23 | 最終編集日時取得 | 主機能 | パッド一覧に最終編集日時を表示 |
| 25 | アクティブユーザー数取得 | 主機能 | パッド一覧にアクティブユーザー数を表示 |
| 22 | リビジョン数取得 | 主機能 | パッド一覧にリビジョン数を表示 |

## 画面種別

一覧 / 管理

## URL/ルーティング

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

## 入出力項目

| 項目名 | 項目ID | 入力/出力 | データ型 | 必須 | 最大長 | 説明 |
|--------|--------|----------|---------|------|--------|------|
| 検索キーワード | searchTerm | 入力 | テキスト | - | - | パッド名フィルタリング用 |
| 新規パッド名 | padName | 入力 | テキスト | 必須 | - | 作成するパッドの名前 |

## 表示項目

| 項目名 | 項目ID | 説明 |
|--------|--------|------|
| ページタイトル | - | 「Manage Pads」（i18n: ep_admin_pads:ep_adminpads2_manage-pads） |
| 新規作成ボタン | - | PlusIconアイコン |
| 検索フィールド | - | SearchFieldコンポーネント |
| パッド一覧テーブル | - | パッド名、ユーザー数、最終編集日時、リビジョン数、アクション列 |
| 削除ボタン | - | Trash2アイコン |
| クリーンアップボタン | - | FileStackアイコン |
| 開くボタン | - | Eyeアイコン |
| ページネーション | pad-pagination | Previous/Next ボタン、ページ表示 |
| 削除確認ダイアログ | - | Dialog.Root（削除確認） |
| 新規作成ダイアログ | - | Dialog.Root（パッド名入力） |
| エラーダイアログ | - | Dialog.Root（エラー表示） |

## イベント仕様

### 1-パッド一覧取得

画面アクセス時および検索/ソート/ページ変更時、WebSocket経由でパッド読み込みリクエストが送信される（`padLoad`イベント）。サーバーはパッド一覧を検索・ソートして返送する（`results:padLoad`イベント）。

### 2-パッド検索

検索フィールドにキーワードを入力すると、500msのデバウンス後に検索パラメータが更新され、padLoadリクエストが送信される。パッド名の部分一致でフィルタリングされる。

### 3-パッド削除

削除ボタン（Trash2アイコン）をクリックすると、確認ダイアログが表示される。「OK」を押すと、WebSocket経由で削除リクエストが送信される（`deletePad`イベント）。削除完了後（`results:deletePad`イベント）、一覧から該当パッドが削除される。

### 4-リビジョンクリーンアップ

クリーンアップボタン（FileStackアイコン）をクリックすると、WebSocket経由でクリーンアップリクエストが送信される（`cleanupPadRevisions`イベント）。settings.cleanup.enabledがtrueの場合のみ実行される。完了後（`results:cleanupPadRevisions`イベント）、リビジョン数が更新される。

### 5-新規パッド作成

新規作成ボタン（PlusIcon）をクリックすると、作成ダイアログが表示される。パッド名を入力して送信すると、WebSocket経由で作成リクエストが送信される（`createPad`イベント）。成功時（`results:createPad`にsuccess）はトースト通知とダイアログ閉じ、一覧再読み込み。失敗時（errorあり）はトースト通知でエラー表示。

### 6-パッドを開く

開くボタン（Eyeアイコン）をクリックすると、新しいタブでパッド編集画面（`/p/{padName}`）が開く。

### 7-ソート切り替え

テーブルヘッダーをクリックすると、その列でソートが切り替わる（padName, userCount, lastEdited, revisionNumber）。昇順/降順がトグルで切り替わる。

### 8-ページネーション

Previous/Nextボタンで前後のページに移動する。ページ番号表示で現在位置を確認できる。1ページあたり12件表示。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| パッド一覧取得 | pad:* | SELECT | 全パッドIDを取得 |
| パッド削除 | pad:{padId}* | DELETE | パッド関連の全データを削除 |
| パッド作成 | pad:{padId} | INSERT | 新規パッドを作成 |
| クリーンアップ | pad:{padId}:revs:* | DELETE | 古いリビジョンを削除 |

### テーブル別更新項目詳細

#### pad:{padId}

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | 全体 | 指定padIdのデータ全削除 | 関連データも含む |
| INSERT | atext, pool, head | 初期値 | 新規パッド作成時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| ep_admin_pads:ep_adminpads2_manage-pads | タイトル | Manage Pads | ページタイトル |
| ep_admin_pads:ep_adminpads2_padname | ヘッダー | Pad Name | テーブルヘッダー |
| ep_admin_pads:ep_adminpads2_pad-user-count | ヘッダー | User Count | テーブルヘッダー |
| ep_admin_pads:ep_adminpads2_last-edited | ヘッダー | Last Edited | テーブルヘッダー |
| ep_admin_pads:ep_adminpads2_action | ヘッダー | Actions | テーブルヘッダー |
| ep_admin_pads:ep_adminpads2_search-heading | プレースホルダー | Search... | 検索フィールド |
| ep_admin_pads:ep_adminpads2_delete.value | ボタンタイトル | Delete | 削除ボタン |
| ep_admin_pads:ep_adminpads2_cleanup | ボタンタイトル | Cleanup | クリーンアップボタン |
| ep_admin_pads:ep_adminpads2_confirm | 確認 | Are you sure you want to delete {padID}? | 削除確認ダイアログ |
| index.newPad | タイトル | New Pad | 作成ダイアログタイトル |
| index.createOpenPad | ボタン | Create/Open | パッドを開くボタン |
| admin_settings.createPad | ボタン | Create | 作成ボタン |

## 例外処理

| 例外状態 | 対応処理 | 表示内容 |
|---------|---------|---------|
| パッド削除失敗 | エラーログ出力 | サーバー側でログ |
| パッド作成失敗（既存） | トースト通知 | 「Pad already exists」 |
| クリーンアップ無効 | エラーダイアログ | 「Cleanup disabled...」 |
| クリーンアップ失敗 | エラーダイアログ | エラーメッセージ表示 |
| WebSocket切断 | 自動再接続 | 接続復帰時に再読み込み |
| 権限不足 | 接続拒否 | WebSocket接続が確立されない |

## 備考

- 1ページあたりの表示件数は12件固定（queryPadLimit）
- 検索は500msデバウンス付き
- 最終編集日時はtoLocaleString()で表示
- クリーンアップはsettings.cleanup.enabledがtrueの場合のみ有効
- クリーンアップ後のリビジョン数はsettings.cleanup.keepRevisionsの値になる
- Radix UI Dialogを使用してモーダルダイアログを実装
- react-hook-formでパッド作成フォームを管理

---

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

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

### 推奨読解順序

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

パッド管理では、検索クエリと検索結果の2種類のデータ構造を扱う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PadSearch.ts | `admin/src/utils/PadSearch.ts` | PadSearchQuery, PadSearchResult, PadType型定義 |
| 1-2 | store.ts | `admin/src/store/store.ts` | pads, settingsSocket の状態管理 |

**読解のコツ**: `PadType`にはpadName, lastEdited, userCount, revisionNumberが含まれる。

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

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

**主要処理フロー**:
1. **17行目**: PadPageコンポーネント定義
2. **18-34行目**: 状態変数の初期化
3. **43-49行目**: useDebounce - 検索デバウンス処理
4. **51-58行目**: useEffect - padLoadリクエスト
5. **60-123行目**: useEffect - WebSocketイベントリスナー設定
6. **65-67行目**: results:padLoad - パッド一覧受信
7. **70-77行目**: results:deletePad - 削除完了
8. **86-103行目**: results:createPad - 作成完了
9. **105-123行目**: results:cleanupPadRevisions - クリーンアップ完了
10. **126-132行目**: deletePad, cleanupPad, onPadCreate 関数
11. **142-199行目**: ダイアログ群のレンダリング
12. **200-265行目**: テーブルのレンダリング
13. **266-282行目**: ページネーション

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

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

**主要処理フロー**:
- **106-241行目**: padLoad - パッド一覧取得・検索・ソート
- **244-252行目**: deletePad - パッド削除
- **258-271行目**: createPad - パッド作成
- **273-305行目**: cleanupPadRevisions - リビジョンクリーンアップ

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

```
[ブラウザ] GET /admin/pads
    │
    ├─ React SPA (PadPage.tsx)
    │      │
    │      ├─ WebSocket接続 (/settings)
    │      │      │
    │      │      └─ [サーバー] adminsettings.ts
    │      │              │
    │      │              ├─ padLoad
    │      │              │      ├─ padManager.listAllPads()
    │      │              │      ├─ フィルタリング (pattern)
    │      │              │      ├─ ソート (sortBy, ascending)
    │      │              │      └─ ページネーション (offset, limit)
    │      │              │
    │      │              ├─ deletePad
    │      │              │      ├─ padManager.doesPadExists()
    │      │              │      └─ pad.remove()
    │      │              │
    │      │              ├─ createPad
    │      │              │      ├─ padManager.doesPadExists()
    │      │              │      └─ padManager.getPad() (作成)
    │      │              │
    │      │              └─ cleanupPadRevisions
    │      │                     └─ deleteRevisions()
    │      │
    │      └─ UIレンダリング
    │             ├─ ダイアログ群
    │             ├─ 検索フィールド
    │             ├─ パッド一覧テーブル
    │             └─ ページネーション
```

### データフロー図

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

検索キーワード ─────▶ useDebounce (500ms) ────▶ searchParams更新
                                                       │
                                                       ▼
画面アクセス ──────▶ WebSocket 'padLoad' ────▶ パッド一覧取得
ソート変更                                             │
ページ変更                                             ▼
                                               'results:padLoad' ──▶ テーブル表示

削除ボタン ────────▶ 確認ダイアログ ─────────▶ WebSocket 'deletePad'
                                                       │
                                                       ▼
                                               'results:deletePad' ▶ 一覧更新

新規作成 ─────────▶ 作成ダイアログ ─────────▶ WebSocket 'createPad'
                                                       │
                                                       ▼
                                               'results:createPad'
                                                       │
                              ┌───────────────────┴───────────────────┐
                              ▼                                       ▼
                        成功                                     失敗
                        トースト                                 トースト
                        ダイアログ閉                             エラー表示
                        一覧再読み込み

クリーンアップ ───▶ WebSocket 'cleanupPadRevisions'
                                                       │
                                                       ▼
                                               'results:cleanupPadRevisions'
                                               リビジョン数更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PadPage.tsx | `admin/src/pages/PadPage.tsx` | ソース | パッド管理画面コンポーネント |
| PadSearch.ts | `admin/src/utils/PadSearch.ts` | ソース | 検索関連型定義 |
| store.ts | `admin/src/store/store.ts` | ソース | 状態管理ストア |
| adminsettings.ts | `src/node/hooks/express/adminsettings.ts` | ソース | WebSocketハンドラー |
| PadManager.ts | `src/node/db/PadManager.ts` | ソース | パッド管理ロジック |
| Cleanup.ts | `src/node/utils/Cleanup.ts` | ソース | リビジョンクリーンアップ |
| SearchField.tsx | `admin/src/components/SearchField.tsx` | ソース | 検索フィールドコンポーネント |
| IconButton.tsx | `admin/src/components/IconButton.tsx` | ソース | アイコンボタンコンポーネント |
| useDebounce.ts | `admin/src/utils/useDebounce.ts` | ソース | デバウンスフック |
