# 通知設計書 11-deleted

## 概要

本ドキュメントは、Etherpadにおけるパッド削除通知「deleted」の設計仕様を定義する。この通知は、ユーザーがアクセスしているパッドがサーバー側で削除された際に、接続中のクライアントに対して表示されるモーダル通知である。

### 本通知の処理概要

この通知はパッドが削除されたことをリアルタイムに接続中のユーザーに伝え、適切な対応を促すためのアプリ内モーダル通知である。

**業務上の目的・背景**：共同編集環境において、パッドの削除は重大なイベントである。ユーザーが編集中のドキュメントが削除された場合、その事実を即座に通知しなければ、ユーザーは存在しないドキュメントに対して操作を続けようとし、混乱やデータ不整合を引き起こす可能性がある。この通知により、ユーザーは現在のパッドが利用不可となったことを認識し、新しいパッドへの移動や別の作業への切り替えなど、次のアクションを判断できる。

**通知の送信タイミング**：サーバー側でパッドが削除された時点で、`kickSessionsFromPad`関数が呼び出され、そのパッドに接続中のすべてのソケットに対して`{disconnect: 'deleted'}`メッセージが送信される。クライアント側では、このメッセージを受信すると`pad_connectionstatus.ts`の`disconnected`関数が実行され、モーダルダイアログが表示される。

**通知の受信者**：削除されたパッドに現在接続しているすべてのユーザー（編集者・閲覧者を含む）。Socket.IOの`room`機能を使用して、該当パッドIDのルームに参加しているすべてのソケットに対してブロードキャストされる。

**通知内容の概要**：「Deleted.」というタイトルと「This pad has been removed.」という説明文が表示される。これらのテキストは多言語対応しており、ローカライズファイルから取得される。

**期待されるアクション**：ユーザーはこの通知を確認し、パッドが削除されたことを理解する。再接続ボタンは表示されないため、ブラウザの戻るボタンで別のページに移動するか、ブラウザタブを閉じる必要がある。

## 通知種別

アプリ内通知（モーダルダイアログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（WebSocket経由のリアルタイム通知） |
| 優先度 | 高 |
| リトライ | 無 |

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

Socket.IOの`room`機能を使用し、削除されたパッドIDに対応するルームに参加しているすべてのクライアントソケットに対してブロードキャストされる。具体的には`socketio.in(padID).emit('message', {disconnect: 'deleted'})`で実現される。

## 通知テンプレート

### モーダル通知の場合

| 項目 | 内容 |
|-----|------|
| タイトル | pad.modals.deleted（ローカライズキー） |
| メッセージ | pad.modals.deleted.explanation（ローカライズキー） |
| 表示形式 | モーダルダイアログ + オーバーレイ |

### 本文テンプレート

```html
<div class="deleted">
  <h1 data-l10n-id="pad.modals.deleted"></h1>
  <p data-l10n-id="pad.modals.deleted.explanation"></p>
</div>
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| pad.modals.deleted | 通知タイトル「Deleted.」 | src/locales/*.json | Yes |
| pad.modals.deleted.explanation | 説明文「This pad has been removed.」 | src/locales/*.json | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | Pad.remove()実行 | パッドに接続中のユーザーが存在すること | PadMessageHandler.kickSessionsFromPadが呼ばれる |
| 画面操作 | 設定画面からのパッド削除 | 削除権限を持つユーザーによる操作 | パッドの最初のリビジョン作成者のみ削除可能 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 接続ユーザーなし | パッドに誰も接続していない場合は通知不要 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[パッド削除リクエスト] --> B{削除権限チェック}
    B -->|権限あり| C[Pad.remove実行]
    B -->|権限なし| D[エラーメッセージ送信]
    C --> E[kickSessionsFromPad呼び出し]
    E --> F{接続ユーザー存在?}
    F -->|存在する| G[disconnect:deleted送信]
    F -->|存在しない| H[処理終了]
    G --> I[クライアント側で受信]
    I --> J[disconnected関数実行]
    J --> K[モーダル表示]
    K --> L[オーバーレイ表示]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| pad:{padId} | パッドの存在確認 | 削除前の確認 |

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

#### pad:{padId}

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| atext | パッドの内容 | 削除対象の特定 |
| head | リビジョン番号 | 削除権限の確認（最初のリビジョン作成者） |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| pad:{padId} | DELETE | パッドデータの削除 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| WebSocket切断 | 通知送信前にクライアントが切断 | 送信スキップ（接続中のクライアントのみに通知） |
| 権限不足 | 削除権限がないユーザーが削除を試行 | エラーメッセージを返却 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（パッド削除は即座に通知される必要がある）

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

- パッド削除は最初のリビジョン作成者（パッドの作成者）のみが実行可能
- 通知には削除されたパッドの内容は含まれず、削除された事実のみを通知
- 認証されたセッション経由でのみ削除操作が可能

## 備考

- この通知にはForce reconnectボタンは表示されない（再接続しても意味がないため）
- 自動再接続タイマーも適用されない
- ユーザーは手動でブラウザの戻るボタンを使用するか、別のパッドに移動する必要がある

---

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

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

### 推奨読解順序

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

まず、WebSocketメッセージの形式を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | kickSessionsFromPad関数で送信されるメッセージ形式`{disconnect: 'deleted'}`を確認 |

**読解のコツ**: TypeScriptファイルではexports.で始まる関数がモジュール外から呼び出し可能な公開関数である。

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

処理の起点となるサーバー側のパッド削除処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | kickSessionsFromPad関数（181-189行目）が通知送信のエントリーポイント |

**主要処理フロー**:
1. **181行目**: `exports.kickSessionsFromPad`関数定義開始
2. **186行目**: `_getRoomSockets(padID).length === 0`で接続ユーザーの有無を確認
3. **189行目**: `socketio.in(padID).emit('message', {disconnect: 'deleted'})`でブロードキャスト

#### Step 3: クライアント側の受信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pad_connectionstatus.ts | `src/static/js/pad_connectionstatus.ts` | disconnected関数（54-86行目）でメッセージ受信後の処理を確認 |
| 3-2 | pad_modals.ts | `src/static/js/pad_modals.ts` | showModal関数（35-43行目）でモーダル表示処理を確認 |

**主要処理フロー**:
- **54行目**: `disconnected: (msg) =>`で切断理由を受け取る
- **65-77行目**: `knownReasons`配列に'deleted'が含まれているか確認
- **84行目**: `padmodals.showModal(k)`でモーダル表示

#### Step 4: HTML構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pad.html | `src/templates/pad.html` | deleted用のdiv要素（291-294行目）を確認 |

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

```
Pad.remove() [パッド削除]
    │
    └─ PadMessageHandler.kickSessionsFromPad(padID)
           │
           ├─ _getRoomSockets(padID) [接続ユーザー確認]
           │
           └─ socketio.in(padID).emit('message', {disconnect: 'deleted'})
                  │
                  └─ [クライアント側]
                         │
                         ├─ pad_connectionstatus.disconnected('deleted')
                         │      │
                         │      └─ padmodals.showModal('deleted')
                         │             │
                         │             └─ padeditbar.toggleDropDown('connectivity')
                         │
                         └─ padmodals.showOverlay()
```

### データフロー図

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

サーバー側パッド削除 ───▶ kickSessionsFromPad ───▶ WebSocketメッセージ送信
                                                        │
                                                        ▼
                                               クライアント受信
                                                        │
                                                        ▼
                         padmodals.showModal ◀─── disconnected関数
                                │
                                ▼
                         モーダルダイアログ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | ソース | サーバー側メッセージ処理、kickSessionsFromPad関数定義 |
| pad_connectionstatus.ts | `src/static/js/pad_connectionstatus.ts` | ソース | クライアント側接続状態管理、disconnected関数定義 |
| pad_modals.ts | `src/static/js/pad_modals.ts` | ソース | モーダルダイアログ表示制御 |
| pad.html | `src/templates/pad.html` | テンプレート | モーダルHTML構造定義 |
| en.json | `src/locales/en.json` | 設定 | 英語ローカライズ文字列（pad.modals.deleted等） |
| ja.json | `src/locales/ja.json` | 設定 | 日本語ローカライズ文字列 |
