# 機能設計書 15-テキスト取得

## 概要

本ドキュメントは、Etherpadにおけるテキスト取得機能（getText）の設計仕様を定義する。この機能は、指定されたパッドのプレーンテキストコンテンツを取得するためのAPIを提供する。

### 本機能の処理概要

テキスト取得機能は、パッドに保存されているテキストコンテンツをプレーンテキスト形式で取得する機能である。最新のテキストだけでなく、特定のリビジョン番号を指定して過去の状態のテキストを取得することも可能。

**業務上の目的・背景**：
共同編集されたドキュメントのテキストを外部システムで利用したい場合や、バックアップ目的でテキストを取得したい場合に使用される。また、テキスト処理・分析を行う外部システムとの連携、検索インデックスの構築、レポート生成などにも活用される。書式情報が不要でプレーンテキストのみが必要なユースケースに最適。

**機能の利用シーン**：
- パッドの内容を外部システムにエクスポート
- テキスト分析・自然言語処理との連携
- 検索エンジンへのインデックス作成
- バックアップスクリプトでのテキスト保存
- 過去リビジョンの内容確認

**主要な処理内容**：
1. 対象パッドの存在確認
2. リビジョン番号の指定確認（オプション）
3. 指定リビジョンまたは最新テキストの取得
4. プレーンテキスト形式での返却

**関連システム・外部連携**：
- REST API（GET /api/2/pads/text）を通じて外部システムから呼び出し可能
- ExportTxtモジュールを使用してテキスト変換

**権限による制御**：
- APIキーまたはOAuth2トークンによる認証が必要
- パッドの内容を取得できるため、機密情報へのアクセス制御を考慮

## 関連画面

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

## 機能種別

データ参照（Read操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| padID | string | Yes | テキストを取得するパッドのID | 正規表現に一致、存在するパッドであること |
| rev | string/number | No | 取得するリビジョン番号（省略時は最新） | 整数、0以上かつhead以下 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | number | 結果コード（0: 成功、1: エラー、4: 認証エラー） |
| message | string | 結果メッセージ（"ok" または エラーメッセージ） |
| data | object | テキストを含むオブジェクト |
| data.text | string | パッドのプレーンテキスト（改行含む） |

### 出力先

HTTPレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. APIリクエスト受信
   └─ GET /api/2/pads/text?padID=xxx&rev=n
2. 認証チェック
   └─ APIキーまたはOAuth2トークンの検証
3. パラメータ抽出
   └─ padID, revの取得
4. リビジョン番号検証（指定時）
   └─ 整数変換、範囲チェック
5. パッド取得
   └─ getPadSafe(padID, true)
6. テキスト取得
   ├─ rev指定あり: getInternalRevisionAText(rev)
   └─ rev指定なし: pad.atext から直接取得
7. プレーンテキスト変換
   └─ exportTxt.getTXTFromAtext()
8. レスポンス返却
   └─ {code: 0, message: "ok", data: {text: "..."}}
```

### フローチャート

```mermaid
flowchart TD
    A[開始: getText API呼び出し] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D[パッド存在確認]
    D -->|存在しない| E[400 padID does not exist]
    D -->|存在する| F{rev指定あり?}
    F -->|Yes| G[リビジョン番号検証]
    G -->|不正| H[400 rev is higher than head]
    G -->|正常| I[getInternalRevisionAText]
    F -->|No| J[pad.atextから取得]
    I --> K[getTXTFromAtext]
    J --> K
    K --> L[200 OK: text返却]
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-015-01 | 最新テキスト | rev未指定時は最新のテキストを返却 | revパラメータなし |
| BR-015-02 | 履歴アクセス | 指定されたリビジョンのテキストを返却 | revパラメータあり |
| BR-015-03 | 範囲チェック | revがhead以上の場合はエラー | rev > headRevisionNumber |
| BR-015-04 | プレーンテキスト | 書式情報なしのプレーンテキストを返却 | 常時 |

### 計算ロジック

リビジョン指定時のテキスト復元:
1. キーリビジョン（100の倍数）のATextを取得
2. キーリビジョンから指定リビジョンまでのChangesetを順次適用
3. 復元されたATextからテキストを抽出

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 参照 | pad:{padID} | SELECT | パッドメタデータ取得 |
| 参照 | pad:{padID}:revs:{n} | SELECT | リビジョン情報取得（rev指定時） |

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

#### pad:{padID}

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | atext | 最新テキスト | rev未指定時 |
| SELECT | head | 最新リビジョン番号 | 範囲チェック用 |

#### pad:{padID}:revs:{n}

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | meta.atext | キーリビジョンのAText | 100の倍数リビジョン |
| SELECT | changeset | 変更セット | リビジョン復元用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | apierror | パッドが存在しない | 正しいパッドIDを指定 |
| 1 | apierror | revがhead以上 | 有効なリビジョン番号を指定 |
| 1 | apierror | revが数値でない | 整数を指定 |
| 4 | authError | 認証情報が無効 | 正しいAPIキーまたはトークンを使用 |

### リトライ仕様

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

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

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

## パフォーマンス要件

- 最新テキスト取得: パッドオブジェクトから直接取得で高速
- 過去リビジョン取得: キーリビジョンからの復元処理が必要で、リビジョン差が大きいほど時間がかかる
- 100リビジョンごとにキーリビジョンが保存されるため、最大99回のChangeset適用

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

- APIキーまたはOAuth2認証が必須
- パッドの内容がそのまま返却されるため、機密情報の漏洩に注意
- リビジョン番号の推測によるブルートフォース攻撃の可能性（レート制限で対応）

## 備考

- 返却されるテキストは末尾に改行文字が含まれる
- リスト形式のテキストは特殊文字で表現される場合がある
- マルチバイト文字（日本語等）も正しく取得可能

---

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

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

### 推奨読解順序

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

パッドのテキスト保存形式を把握することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Pad.ts | `src/node/db/Pad.ts` | atextプロパティ（43行目）、text()メソッド（269-271行目） |
| 1-2 | PadType.ts | `src/node/types/PadType.ts` | AText型の定義 |

**読解のコツ**: atextはtext（プレーンテキスト）とattribs（属性情報）を持つオブジェクト。text()メソッドはatext.textを返すだけのシンプルなメソッド。

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

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

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

**主要処理フロー**:
1. **596-609行目**: GET /pads/text のルート定義
2. **50行目**: getTextの引数（padID, rev）

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

実際のテキスト取得ロジックを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | API.ts | `src/node/db/API.ts` | getText関数（160-187行目） |
| 3-2 | Pad.ts | `src/node/db/Pad.ts` | getInternalRevisionAText関数（208-221行目） |
| 3-3 | ExportTxt.ts | `src/node/utils/ExportTxt.ts` | getTXTFromAtext関数（47-264行目） |

**主要処理フロー**:
- **API.ts 160-164行目**: リビジョン番号のパース
- **API.ts 167行目**: パッド取得
- **API.ts 171-175行目**: リビジョン範囲チェック
- **API.ts 180行目**: getInternalRevisionATextでリビジョンのテキスト取得
- **API.ts 185行目**: getTXTFromAtextで最新テキスト取得

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

```
GET /api/2/pads/text (RestAPI.ts)
    │
    └─ apiHandler.handle() (APIHandler.ts)
           │
           └─ api.getText() (API.ts:160-187)
                  │
                  ├─ checkValidRev(rev) (162-164行目)
                  │      └─ 整数変換・検証
                  │
                  ├─ getPadSafe(padID, true) (167行目)
                  │      └─ パッド取得・存在確認
                  │
                  ├─ [rev指定あり]
                  │      ├─ pad.getHeadRevisionNumber() (168行目)
                  │      ├─ 範囲チェック (173-175行目)
                  │      └─ pad.getInternalRevisionAText(rev) (180行目)
                  │             ├─ getKeyRevisionNumber() (209行目)
                  │             ├─ _getKeyRevisionAText() (213行目)
                  │             └─ getRevisionChangeset() ループ (215行目)
                  │
                  └─ [rev指定なし]
                         └─ exportTxt.getTXTFromAtext(pad, pad.atext) (185行目)
```

### データフロー図

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

padID         ───────▶ getPadSafe() ──────────────▶ Padオブジェクト
rev                          │
                             ▼
                    ┌─[rev指定あり]─────────────────────────┐
                    │                                       │
                    │  getInternalRevisionAText(rev)        │
                    │         │                             │
                    │         ├─▶ キーリビジョン取得         │
                    │         │                             │
                    │         └─▶ Changeset適用 ──▶ AText   │
                    │                                       │
                    └─[rev指定なし]─────────────────────────┘
                             │
                             ├─▶ pad.atext（最新）
                             │
                             ▼
                    getTXTFromAtext()
                             │
                             └─▶ プレーンテキスト
                             │
                             ▼
                    {text: "..."} ───────▶ JSON Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| API.ts | `src/node/db/API.ts` | ソース | getText関数の実装 |
| Pad.ts | `src/node/db/Pad.ts` | ソース | Padクラス、getInternalRevisionAText |
| ExportTxt.ts | `src/node/utils/ExportTxt.ts` | ソース | getTXTFromAtext関数 |
| RestAPI.ts | `src/node/handler/RestAPI.ts` | ソース | REST APIエンドポイント定義 |
| APIHandler.ts | `src/node/handler/APIHandler.ts` | ソース | API呼び出しハンドリング |
| checkValidRev.ts | `src/node/utils/checkValidRev.ts` | ソース | リビジョン番号検証 |
| PadManager.ts | `src/node/db/PadManager.ts` | ソース | パッド取得 |
| DB.ts | `src/node/db/DB.ts` | ソース | データベースアクセス層 |
