# アーキテクチャ設計書

## 概要

本ドキュメントは、Etherpad Lite（バージョン2.6.1）のアーキテクチャ設計を記述したものである。Etherpadはリアルタイム協調編集を実現するWebアプリケーションであり、Node.js上で動作するサーバーサイドアプリケーションと、ブラウザ上で動作するクライアントサイドアプリケーションから構成される。

## システム全体構成

### アーキテクチャ概要図

アーキテクチャ構成図は[アーキテクチャ構成図.md](./アーキテクチャ構成図.md)を参照。

### システム境界と外部連携

| 外部システム | 連携方式 | 用途 |
| --- | --- | --- |
| データベース（ueberdb2） | ueberdb2ライブラリ経由 | パッド、ユーザー、セッション等のデータ永続化。dirty、MySQL、PostgreSQL、SQLite等に対応 |
| Abiword | プロセス起動 | ドキュメントインポート/エクスポート（DOC、ODT等） |
| LibreOffice | プロセス起動 | ドキュメントインポート/エクスポート（PDF、DOC等） |
| クライアントブラウザ | HTTP/HTTPS、Socket.IO | エディタUI、リアルタイム同期 |
| プラグインエコシステム | npm/pnpm | 機能拡張プラグインの管理 |
| OAuth2/OIDC プロバイダー | OAuth2.0/OpenID Connect | 外部認証連携（SSO） |

## レイヤー構成

### アーキテクチャスタイル

**モジュラー・レイヤードアーキテクチャ** + **フックベースプラグインシステム**

Etherpadは明確なレイヤー分離を持つモジュラーアーキテクチャを採用している。各機能はモジュールとして分離され、フックシステムを通じて拡張可能である。

### レイヤー定義

| レイヤー | 責務 | 主なコンポーネント |
| --- | --- | --- |
| Presentation | クライアントサイドUI、HTTPリクエスト処理 | admin/, ui/, src/templates/, src/static/js/pad*.ts |
| Handler | WebSocket/HTTPメッセージのルーティングと処理 | src/node/handler/PadMessageHandler.ts, SocketIORouter.ts, APIHandler.ts |
| Application | ビジネスロジック、API機能の提供 | src/node/db/API.ts, src/node/hooks/ |
| Domain | ドメインモデル、パッド・著者・セッション管理 | src/node/db/Pad.ts, AuthorManager.ts, SessionManager.ts, GroupManager.ts |
| Infrastructure | データ永続化、外部サービス連携 | src/node/db/DB.ts, src/node/utils/Abiword.ts, LibreOffice.ts |
| Security | 認証・認可、セキュリティ機能 | src/node/security/, src/node/hooks/express/webaccess.ts |

### レイヤー間の依存関係ルール

1. **上位レイヤーから下位レイヤーへの依存のみ許可**
   - Presentation → Handler → Application → Domain → Infrastructure
2. **横断的関心事（Security）は全レイヤーから参照可能**
3. **禁止される参照**
   - Domain層からPresentation層への直接参照
   - Infrastructure層からHandler層への直接参照
4. **フックシステムによる依存の逆転**
   - プラグインはフックを通じて任意のレイヤーに介入可能

## モジュール構成

### ドメイン分割

| ドメイン | 責務 | 関連モジュール |
| --- | --- | --- |
| Pad | パッドの作成・編集・削除、リビジョン管理 | Pad.ts, PadManager.ts, PadMessageHandler.ts |
| Author | 著者情報の管理、カラー・名前設定 | AuthorManager.ts |
| Session | セッションライフサイクル管理 | SessionManager.ts, SessionStore.ts |
| Group | グループパッドの管理 | GroupManager.ts |
| Chat | チャットメッセージの送受信 | ChatMessage.ts, pad_chat.ts |
| Import/Export | ドキュメントのインポート/エクスポート | ImportHandler.ts, ExportHandler.ts, ExportHtml.ts |
| Plugin | プラグインのロード・管理 | pluginfw/plugins.ts, hooks.ts |

### パッケージ構造

```
etherpad-lite/
├── admin/                      # 管理画面（React）
│   ├── src/
│   └── package.json
├── ui/                         # OIDC認証UI
│   ├── src/
│   └── package.json
├── src/                        # メインアプリケーション（ep_etherpad-lite）
│   ├── node/                   # サーバーサイドコード
│   │   ├── db/                 # データベース・ドメインモデル層
│   │   │   ├── DB.ts           # データベース接続管理
│   │   │   ├── Pad.ts          # パッドドメインモデル
│   │   │   ├── PadManager.ts   # パッド管理
│   │   │   ├── AuthorManager.ts
│   │   │   ├── SessionManager.ts
│   │   │   ├── GroupManager.ts
│   │   │   ├── SecurityManager.ts
│   │   │   └── API.ts          # HTTP API実装
│   │   ├── handler/            # メッセージハンドラー層
│   │   │   ├── PadMessageHandler.ts  # Socket.IOメッセージ処理
│   │   │   ├── SocketIORouter.ts     # ルーティング
│   │   │   ├── APIHandler.ts
│   │   │   ├── ImportHandler.ts
│   │   │   └── ExportHandler.ts
│   │   ├── hooks/              # Expressフック
│   │   │   ├── express.ts      # Expressサーバー設定
│   │   │   └── express/        # 各種ミドルウェア
│   │   ├── security/           # セキュリティモジュール
│   │   │   ├── OAuth2Provider.ts
│   │   │   ├── OIDCAdapter.ts
│   │   │   └── SecretRotator.ts
│   │   ├── utils/              # ユーティリティ
│   │   └── server.ts           # エントリーポイント
│   ├── static/                 # フロントエンド静的ファイル
│   │   └── js/                 # クライアントサイドJS/TS
│   │       ├── Changeset.ts    # Changeset処理
│   │       ├── AttributePool.ts
│   │       ├── collab_client.ts
│   │       ├── pad*.ts         # パッド関連UI
│   │       └── pluginfw/       # プラグインフレームワーク
│   ├── templates/              # HTMLテンプレート
│   └── locales/                # 国際化リソース
├── bin/                        # CLIスクリプト
├── doc/                        # ドキュメント
└── var/                        # ランタイムデータ
```

### コンポーネント依存関係

主要コンポーネント間の依存関係：

1. **server.ts** → DB.ts, hooks/express.ts, pluginfw
2. **PadMessageHandler.ts** → Pad.ts, AuthorManager.ts, SecurityManager.ts
3. **API.ts** → PadManager.ts, AuthorManager.ts, GroupManager.ts, SessionManager.ts
4. **webaccess.ts** → SecurityManager.ts, ReadOnlyManager.ts
5. **Pad.ts** → DB.ts, AuthorManager.ts, PadManager.ts

## ミドルウェア構成

### データベース

| 種類 | ミドルウェア | バージョン | 用途 |
| --- | --- | --- | --- |
| 抽象化レイヤー | ueberdb2 | ^5.0.23 | データベース抽象化（複数DBバックエンドをサポート） |
| デフォルト | dirty | (ueberdb2内蔵) | 開発/テスト用ファイルベースDB |
| RDB（オプション） | MySQL/PostgreSQL/SQLite | - | 本番環境向けRDB |

### キャッシュ

| ミドルウェア | バージョン | 用途 | TTL |
| --- | --- | --- | --- |
| lru-cache | ^11.2.5 | パッドキャッシュ、リビジョンキャッシュ | 設定可能 |

### メッセージキュー

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| Socket.IO | ^4.8.3 | リアルタイム通信、パッド更新のブロードキャスト |

### 検索エンジン

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| - | - | 標準では検索エンジンは組み込まれていない（プラグインで拡張可能） |

### その他ミドルウェア

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| Express | ^5.2.1 | HTTPサーバー、ルーティング |
| express-session | ^1.19.0 | セッション管理 |
| express-rate-limit | ^8.2.1 | レート制限 |
| rate-limiter-flexible | ^9.1.0 | WebSocket側のレート制限 |
| log4js | ^6.9.1 | ロギング |
| prom-client | ^15.1.3 | Prometheusメトリクス |
| oidc-provider | 9.6.0 | OpenID Connect認証プロバイダー |

## データフロー

### リクエスト処理の流れ

**HTTPリクエスト（ページ表示・API）**

1. クライアントからHTTPリクエストを受信（Express）
2. ミドルウェアチェーン処理（cookieParser, session, webaccess.checkAccess）
3. `preAuthorize`/`authenticate`/`authorize`フックで認証・認可判定
4. ルートハンドラーで処理（specialpages, API, import/export等）
5. レスポンス送信

**Socket.IO接続とリアルタイム同期**

1. クライアントがSocket.IO接続を確立
2. `handleConnect`でセッション情報を初期化
3. `CLIENT_READY`メッセージで初期データ（clientVars）を送信
4. `USER_CHANGES`でChangesetを受信
5. Changesetをリベース・適用
6. 全クライアントに`NEW_CHANGES`をブロードキャスト
7. 送信元に`ACCEPT_COMMIT`を返信

### 非同期処理の流れ

**Changeset処理キュー**

1. ユーザーがテキストを編集
2. クライアントがChangesetを生成
3. `USER_CHANGES`メッセージをサーバーに送信
4. `Channels`クラスでパッドごとにシリアライズ処理
5. `handleUserChanges`でChangesetを処理
   - 最新リビジョンへのリベース
   - パッドへの適用
   - DBへの保存
6. 他クライアントへブロードキャスト

**プラグインフック処理**

1. フックポイントで`hooks.aCallAll`を呼び出し
2. 登録済みプラグインの該当フック関数を順次実行
3. 結果を集約して返却

### データ永続化の流れ

1. パッド操作（編集、チャット、設定変更）発生
2. `Pad.appendRevision`または`saveToDatabase`を呼び出し
3. ueberdb2を通じてDBに書き込み
4. DBドライバーが実際のストレージに永続化
5. キャッシュを更新

## 横断的関心事

### 認証・認可

| 方式 | 実装箇所 | 対象 |
| --- | --- | --- |
| HTTP Basic認証 | webaccess.ts | /admin, requireAuthentication=true時の全ページ |
| OAuth2/OIDC | OAuth2Provider.ts, OIDCAdapter.ts | SSO認証設定時 |
| APIキー認証 | APIKeyHandler.ts | REST API（レガシー方式） |
| セッション認証 | SecurityManager.ts | グループパッドへのアクセス |
| フック拡張 | preAuthorize, authenticate, authorize | プラグインによる認証拡張 |

### ロギング・監査

| 種類 | 実装方式 | 保存先 |
| --- | --- | --- |
| アプリケーションログ | log4js | stdout/ファイル（設定依存） |
| アクセスログ | log4js（access, http logger） | stdout/ファイル |
| メッセージログ | log4js（message logger） | stdout/ファイル |
| メトリクス | prom-client | /metrics エンドポイント |

### エラーハンドリング

| エラー種別 | ハンドリング方式 | レスポンス |
| --- | --- | --- |
| 認証エラー | webaccess.ts | 401 Unauthorized |
| 認可エラー | webaccess.ts, authnFailure/authzFailureフック | 403 Forbidden |
| APIエラー | APIHandler.ts, CustomError | JSON {code, message} |
| Socket.IOエラー | PadMessageHandler.ts | {disconnect: reason} |
| 未捕捉例外 | server.ts process.on('uncaughtException') | サーバーシャットダウン |

### トランザクション管理

| 範囲 | 管理方式 | 分離レベル |
| --- | --- | --- |
| パッドリビジョン | Channels クラスによるシリアライズ | パッド単位でのシリアル処理 |
| DB操作 | ueberdb2のトランザクション機能（DBドライバー依存） | DBドライバー依存 |

## 設計原則・コーディング規約

### 適用している設計原則

| 原則 | 適用箇所 | 実装例 |
| --- | --- | --- |
| フック/プラグインパターン | pluginfw/ | 拡張ポイントをフックとして定義し、プラグインで機能追加 |
| 非同期処理（async/await） | 全体 | DB操作、HTTP処理等すべてPromiseベース |
| モジュラー設計 | src/node/ | 機能ごとにモジュール分離 |
| Changeset/OT | Changeset.ts | Operational Transformationによるリアルタイム同期 |
| シングルトンDB接続 | DB.ts | アプリケーション全体で1つのDB接続を共有 |

### コーディング規約

1. **TypeScript使用** - 型安全性の確保（`.ts`ファイル）
2. **ESLint設定** - eslint-config-etherpadによるリンティング
3. **async/awaitパターン** - コールバックではなくPromiseベース
4. **JSDoc/TSDocコメント** - 関数・クラスへのドキュメントコメント
5. **ES Modules** - `"type": "module"`によるESM使用
6. **Apache 2.0ライセンス** - オープンソースライセンス準拠

## 備考

### リアルタイム同期の仕組み（Changeset/OT）

Etherpadのリアルタイム同期はOperational Transformation（OT）に基づく**Changeset**アルゴリズムを使用している。

- **Changeset**: テキスト変更を表現するコンパクトなフォーマット
- **AttributePool**: 属性（太字、色等）を数値IDで管理
- **follow関数**: 並行編集時のChangesetリベース

### プラグインシステム

Etherpadは`ep.json`で定義されるフックシステムにより高い拡張性を持つ。

主要フック：
- `padCreate`, `padUpdate`, `padLoad`, `padRemove`
- `clientVars`, `userJoin`, `userLeave`
- `preAuthorize`, `authenticate`, `authorize`
- `expressCreateServer`, `socketio`

### モノレポ構成

pnpmワークスペースによるモノレポ構成：
- `src/` (ep_etherpad-lite) - メインパッケージ
- `admin/` - 管理画面（React + Vite）
- `ui/` - OIDC認証UI（Vite）
- `bin/` - CLIツール
- `doc/` - ドキュメント生成
