# 機能設計書 20-属性プール取得

## 概要

本ドキュメントは、Etherpadにおける属性プール取得機能（getAttributePool）の設計仕様を定義する。この機能は、指定されたパッドの属性プール（Attribute Pool）を取得するためのAPIを提供する。

### 本機能の処理概要

属性プール取得機能は、パッドに使用されているすべての属性（書式情報や著者情報）のマッピング情報を取得する機能である。属性プールはEtherpadのEasySyncプロトコルの中核的なデータ構造であり、テキストの書式設定や著者追跡に使用される属性を数値IDで管理する。

**業務上の目的・背景**：
Etherpadでは、テキストの書式（太字、斜体など）や著者情報（誰が編集したか）を「属性」として管理している。これらの属性はパッドごとに一意のIDが割り当てられ、属性プールで管理される。この情報は、Changesetの解析、カスタムエクスポート機能の実装、デバッグ目的などで使用される。

**機能の利用シーン**：
- Changesetの詳細解析
- カスタムエクスポート機能の開発
- パッドの書式情報の確認
- 著者情報の取得
- デバッグやトラブルシューティング
- サードパーティツールとの連携

**主要な処理内容**：
1. 対象パッドの存在確認
2. パッドオブジェクトから属性プールを取得
3. JSON形式で返却

**関連システム・外部連携**：
- REST API（GET /api/2/pads/attributePool）を通じて外部システムから呼び出し可能
- EasySyncプロトコルと密接に連携

**権限による制御**：
- APIキーまたはOAuth2トークンによる認証が必要
- パッドの内部構造情報へのアクセスとなる

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はAPIのみで提供され、直接関連する画面はない |

## 機能種別

データ参照（Read操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| padID | string | Yes | 属性プールを取得するパッドのID | 正規表現に一致、存在するパッドであること |

### 入力データソース

REST API経由でのHTTPリクエスト（GET /api/2/pads/attributePool）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | number | 結果コード（0: 成功、1: エラー、4: 認証エラー） |
| message | string | 結果メッセージ（"ok" または エラーメッセージ） |
| data | object | 属性プールを含むオブジェクト |
| data.pool | object | 属性プールオブジェクト |
| data.pool.numToAttrib | object | 数値ID→属性配列のマッピング |
| data.pool.attribToNum | object | 属性文字列→数値IDのマッピング |
| data.pool.nextNum | number | 次に割り当てられる属性ID |

### 出力例

```json
{
  "code": 0,
  "message": "ok",
  "data": {
    "pool": {
      "numToAttrib": {
        "0": ["author", "a.X4m8bBWJBZJnWGSh"],
        "1": ["author", "a.TotfBPzov54ihMdH"],
        "2": ["bold", "true"],
        "3": ["italic", "true"]
      },
      "attribToNum": {
        "author,a.X4m8bBWJBZJnWGSh": 0,
        "author,a.TotfBPzov54ihMdH": 1,
        "bold,true": 2,
        "italic,true": 3
      },
      "nextNum": 4
    }
  }
}
```

### 出力先

HTTPレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. APIリクエスト受信
   └─ GET /api/2/pads/attributePool?padID=xxx
2. 認証チェック
   └─ APIキーまたはOAuth2トークンの検証
3. パラメータ抽出
   └─ padIDの取得
4. パッド取得
   └─ getPadSafe(padID, true)
5. 属性プール取得
   └─ pad.pool
6. レスポンス返却
   └─ {code: 0, message: "ok", data: {pool: {...}}}
```

### フローチャート

```mermaid
flowchart TD
    A[開始: getAttributePool API呼び出し] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D[パッド存在確認]
    D -->|存在しない| E[400 padID does not exist]
    D -->|存在する| F[pad.pool取得]
    F --> G[200 OK: pool返却]
    G --> H[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-020-01 | 完全プール | パッドに使用されたすべての属性が含まれる | 常時 |
| BR-020-02 | 履歴属性含む | 過去に使用され現在は使用されていない属性も含む | 常時 |
| BR-020-03 | 双方向マッピング | numToAttribとattribToNumで双方向参照可能 | 常時 |
| BR-020-04 | ID順序保持 | 属性IDは追加順に連番で割り当てられる | 常時 |

### 計算ロジック

属性プールの構造:
- **numToAttrib**: 数値ID（0, 1, 2...）から属性配列（[キー, 値]）へのマッピング
- **attribToNum**: 属性文字列（"キー,値"形式）から数値IDへのマッピング
- **nextNum**: 次に新しい属性が追加される際に割り当てられるID

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 参照 | pad:{padID} | SELECT | パッドメタデータとpool取得 |

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

#### pad:{padID}

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | pool | 属性プールオブジェクト | AttributePoolインスタンス |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | apierror | パッドが存在しない | 正しいパッドIDを指定 |
| 4 | authError | 認証情報が無効 | 正しいAPIキーまたはトークンを使用 |

### リトライ仕様

データベース操作に関してはueberDB2のリトライ機構に依存。読み取り専用操作のため通常リトライは不要。

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

読み取り専用操作のため、トランザクション管理は不要。

## パフォーマンス要件

- パッドの属性数に関わらず高速に応答（O(1)でpool参照）
- 属性プールはメモリ上に保持されているため、DB参照は初回のみ
- 大量の属性（数千件以上）を持つパッドでもレスポンスサイズに注意

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

- APIキーまたはOAuth2認証が必須
- 属性プールには著者ID（a.xxxxx形式）が含まれる
- 著者IDからユーザー情報への逆引きは別APIが必要

## 備考

- 属性プールはパッドの作成時に初期化され、編集ごとに成長する
- 一度追加された属性は削除されない（履歴復元のため）
- 主な属性キー:
  - author: 著者ID（a.で始まる）
  - bold: 太字（true/false）
  - italic: 斜体（true/false）
  - underline: 下線（true/false）
  - strikethrough: 取り消し線（true/false）
  - list: リスト種別（bullet1, number1等）
  - heading: 見出しレベル（h1, h2等）
- プラグインによるカスタム属性も同様に管理される

---

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

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

### 推奨読解順序

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

属性プールの内部構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AttributePool.ts | `src/static/js/AttributePool.ts` | クラス定義（59-102行目） |
| 1-2 | Pad.ts | `src/node/db/Pad.ts` | pool プロパティ（61行目） |

**読解のコツ**: AttributePoolクラスはnumToAttrib（ID→属性）とattribToNum（属性→ID）の双方向マッピングを保持。putAttrib/getAttribメソッドで操作。

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

REST APIからの呼び出しフローを追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestAPI.ts | `src/node/handler/RestAPI.ts` | API定義（996-1010行目でgetAttributePoolのマッピング） |
| 2-2 | APIHandler.ts | `src/node/handler/APIHandler.ts` | パラメータ定義（91行目でgetAttributePoolの引数） |

**主要処理フロー**:
1. **996-1010行目**: GET /pads/attributePool のルート定義
2. **91行目**: getAttributePoolの引数（padID）

#### Step 3: ビジネスロジックを理解する

実際の属性プール取得ロジックを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | API.ts | `src/node/db/API.ts` | getAttributePool関数（109-112行目） |
| 3-2 | API.ts | `src/node/db/API.ts` | 返却値の構造（83-106行目のコメント） |

**主要処理フロー**:
- **API.ts 109行目**: 関数定義
- **API.ts 110行目**: getPadSafe(padID, true)でパッド取得
- **API.ts 111行目**: {pool: pad.pool}で属性プールを返却

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

```
GET /api/2/pads/attributePool (RestAPI.ts:996-1010)
    │
    └─ apiHandler.handle() (APIHandler.ts)
           │
           └─ api.getAttributePool() (API.ts:109-112)
                  │
                  ├─ getPadSafe(padID, true) (110行目)
                  │      │
                  │      └─ padManager.getPad(padID)
                  │             │
                  │             └─ new Pad(id).init()
                  │                    │
                  │                    └─ this.pool = new AttributePool()
                  │
                  └─ return {pool: pad.pool} (111行目)
                         │
                         └─ AttributePoolオブジェクト
                                ├─ numToAttrib: {0: [k,v], 1: [k,v], ...}
                                ├─ attribToNum: {"k,v": 0, "k,v": 1, ...}
                                └─ nextNum: N
```

### データフロー図

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

padID         ───────▶ getPadSafe() ──────────────▶ Padオブジェクト
                             │
                             ▼
                    pad.pool取得
                             │
                             └─▶ AttributePool
                                    │
                                    ├─▶ numToAttrib
                                    │      └─ {0: ["author","a.xxx"],
                                    │          1: ["bold","true"], ...}
                                    │
                                    ├─▶ attribToNum
                                    │      └─ {"author,a.xxx": 0,
                                    │          "bold,true": 1, ...}
                                    │
                                    └─▶ nextNum
                                           └─ 次の属性ID
                             │
                             ▼
                    {pool: {...}} ───────────────▶ JSON Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| API.ts | `src/node/db/API.ts` | ソース | getAttributePool関数の実装 |
| AttributePool.ts | `src/static/js/AttributePool.ts` | ソース | 属性プールクラス定義 |
| Pad.ts | `src/node/db/Pad.ts` | ソース | Padクラス、poolプロパティ |
| RestAPI.ts | `src/node/handler/RestAPI.ts` | ソース | REST APIエンドポイント定義 |
| APIHandler.ts | `src/node/handler/APIHandler.ts` | ソース | API呼び出しハンドリング |
| PadManager.ts | `src/node/db/PadManager.ts` | ソース | パッド取得処理 |
