# 機能設計書 37-クライアントメッセージ送信

## 概要

本ドキュメントは、Etherpadのクライアントメッセージ送信機能（sendClientsMessage）の設計仕様を記載する。

### 本機能の処理概要

本機能は、指定されたパッドに接続している全クライアントにカスタムメッセージを送信するAPI機能である。主にプラグインによるシグナリングや、管理者からの通知配信に使用される。

**業務上の目的・背景**：Etherpadはプラグインシステムを持ち、様々な機能拡張が可能である。この機能は、サーバーサイドからクライアントに対してカスタムメッセージを送信することで、プラグイン間の通信や管理者からのアナウンスを実現する。チャットメッセージとは異なり、データベースには保存されず、リアルタイムの通知専用である。

**機能の利用シーン**：管理画面からの全クライアントへの通知、プラグインによるカスタムイベントの送信、緊急メンテナンス通知など。

**主要な処理内容**：
1. パッドIDとメッセージ文字列の検証
2. パッドの存在確認
3. COLLABROOMメッセージの構築
4. Socket.IO経由で接続クライアントに配信

**関連システム・外部連携**：REST API経由でHTTPリクエストを受け付ける。Socket.IO経由で接続中クライアントにメッセージを配信する。

**権限による制御**：APIキー認証またはSSO認証により、API呼び出しの認可を行う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | コミュニケーション画面 | 主画面 | 接続中の全ユーザーへメッセージを送信 |

## 機能種別

リアルタイム通知

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| padID | string | Yes | 対象パッドのID | 文字列型であること、パッドが存在すること |
| msg | string | Yes | 送信するメッセージ | 文字列型であること |

### 入力データソース

REST API POSTリクエストのボディとしてJSON形式でパラメータを受け取る。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | integer | 結果コード（0: 成功） |
| message | string | 結果メッセージ（"ok"） |
| data | null | 正常終了時はnull |

### 出力先

- HTTPレスポンスとしてJSON形式で返却
- Socket.IO経由で接続中クライアントにCOLLABROOMイベントとして配信

## 処理フロー

### 処理シーケンス

```
1. APIリクエスト受信
   └─ POST /api/2/pads/clientsMessage
2. 認証・認可チェック
   └─ APIキーまたはSSOトークンの検証
3. パッド存在確認
   └─ getPadSafe()でパッドの存在を確認
4. メッセージ構築
   └─ {type: 'COLLABROOM', data: {type: msg, time: timestamp}}
5. クライアント配信
   └─ socketio.in(padID).emit('message', msg)
```

### フローチャート

```mermaid
flowchart TD
    A[APIリクエスト受信] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D{パッド存在確認}
    D -->|存在しない| E[padID does not exist]
    D -->|存在する| F[COLLABROOMメッセージ構築]
    F --> G[Socket.IO配信]
    G --> H[JSONレスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | パッド存在必須 | 指定されたパッドIDが存在しない場合はエラー | 常時 |
| BR-37-02 | 文字列メッセージのみ | msgは文字列として送信される（オブジェクトは不可） | 常時 |
| BR-37-03 | 即座配信 | メッセージは即座に接続クライアントに配信される | 常時 |
| BR-37-04 | 非永続 | メッセージはデータベースに保存されない | 常時 |

### 計算ロジック

メッセージ構造は以下の形式で送信される：
```javascript
{
  type: 'COLLABROOM',
  data: {
    type: <msg>,        // 入力されたメッセージ文字列
    time: <timestamp>   // 送信時刻（ミリ秒エポック）
  }
}
```

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| パッド存在確認 | pad:{padID} | SELECT | パッドの存在確認のみ（書き込みなし） |

### テーブル別操作詳細

メッセージはデータベースに保存されないため、書き込み操作なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | apierror | padIDが文字列でない | 正しい形式のpadIDを指定 |
| 1 | apierror | パッドが存在しない | 存在するパッドIDを指定 |
| 4 | 認証エラー | APIキーが無効 | 正しいAPIキーを使用 |

### リトライ仕様

リトライは不要（リアルタイム通知のため、失敗時は再送信で対応）

## トランザクション仕様

データベースへの書き込みがないため、トランザクション管理は不要。

## パフォーマンス要件

- レスポンス時間: 100ms以内（通常条件下）
- Socket.IO配信は同期的に行われる

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

- APIキー認証またはSSO認証が必須
- HTTP API経由では文字列のみ受け付けるため、変更セットやチャットメッセージの偽装は困難
- クライアント側でメッセージの処理を適切に行う必要がある

## 備考

API Version 1.1で追加された機能。プラグインにおいてクライアントとサーバー間の通信に使用される。クライアント側ではhandleClientMessageフックで受信処理を行う。

---

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

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

### 推奨読解順序

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

まず、送信されるメッセージの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | handleCustomMessage関数で構築されるメッセージ構造（475-485行目） |

**読解のコツ**: メッセージはCOLLABROOMタイプでラップされ、data.typeにユーザー指定の文字列が設定される。

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

REST APIのエンドポイント定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestAPI.ts | `src/node/handler/RestAPI.ts` | POST /pads/clientsMessageのマッピング定義（824-847行目） |

**主要処理フロー**:
1. **824-847行目**: エンドポイント定義とsendClientsMessage関数へのマッピング

#### Step 3: API関数の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | API.ts | `src/node/db/API.ts` | sendClientsMessage関数の実装（778-781行目） |

**主要処理フロー**:
- **779行目**: getPadSafe()でパッド存在確認
- **780行目**: handleCustomMessage()呼び出し

#### Step 4: メッセージ送信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | handleCustomMessage()関数（475-485行目） |

**主要処理フロー**:
- **476行目**: 現在時刻の取得
- **477-483行目**: メッセージオブジェクトの構築
- **484行目**: socketio.in(padID).emit()で配信

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

```
RestAPI.expressCreateServer
    │
    ├─ app.use('/api/2', ...)
    │      └─ apiHandler.handle('1.1', 'sendClientsMessage', fields)
    │              └─ API.sendClientsMessage(padID, msg)
    │                      ├─ getPadSafe(padID, true)
    │                      └─ padMessageHandler.handleCustomMessage(padID, msg)
    │                              ├─ const time = Date.now()
    │                              ├─ msg = {type: 'COLLABROOM', data: {type, time}}
    │                              └─ socketio.in(padID).emit('message', msg)
    │
    └─ res.json(response)
```

### データフロー図

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

padID ───────────▶ getPadSafe() ───────────▶ パッド存在確認
                           │
msg ─────────────▶ handleCustomMessage()
                           │
                           ▼
                  メッセージ構築
                  {type: 'COLLABROOM',
                   data: {type: msg, time}}
                           │
                           ▼
                  socketio.in(padID).emit() ──▶ 接続クライアント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| API.ts | `src/node/db/API.ts` | ソース | sendClientsMessage関数の実装 |
| PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | ソース | handleCustomMessage関数 |
| RestAPI.ts | `src/node/handler/RestAPI.ts` | ソース | REST APIエンドポイント定義 |
