# 機能設計書 14-パッドID逆引き

## 概要

本ドキュメントは、Etherpadにおけるパッドパッド逆引き機能（getPadID）の設計仕様を定義する。この機能は、読み取り専用ID（roID）から元の編集可能なパッドIDを取得するためのAPIを提供する。

### 本機能の処理概要

パッドID逆引き機能は、r.で始まる読み取り専用IDから、対応する元のパッドIDを取得する機能である。これにより、読み取り専用リンクから元のパッドを特定できる。

**業務上の目的・背景**：
読み取り専用IDで共有されたパッドについて、管理者が元のパッドを特定したい場合がある。また、外部システムが読み取り専用IDを保持している場合に、元のパッドIDを取得してAPIを呼び出す必要があるケースに対応する。セキュリティ監査やアクセスログ分析において、読み取り専用アクセスを元パッドに紐付けるためにも使用される。

**機能の利用シーン**：
- 読み取り専用リンクから元パッドの管理
- 外部システムでの読み取り専用ID→パッドIDの変換
- アクセスログの分析・監査
- 読み取り専用URLからの編集権限付与判断

**主要な処理内容**：
1. 読み取り専用IDの受け取り
2. readonly2pad:テーブルからパッドIDを検索
3. パッドIDが見つかった場合は返却、見つからない場合はエラー

**関連システム・外部連携**：
- REST API（POST /api/2/pads/padId）を通じて外部システムから呼び出し可能

**権限による制御**：
- APIキーまたはOAuth2トークンによる認証が必要
- 読み取り専用IDから元のパッドIDを取得できるため、アクセス制御上の考慮が必要

## 関連画面

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

## 機能種別

データ参照（Read操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| roID | string | Yes | 読み取り専用ID（r.で始まるID） | 存在するマッピングがあること |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

HTTPレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. APIリクエスト受信
   └─ POST /api/2/pads/padId
2. 認証チェック
   └─ APIキーまたはOAuth2トークンの検証
3. パラメータ抽出
   └─ roIDの取得
4. パッドID検索
   └─ readOnlyManager.getPadId(roID)
5. 結果確認
   ├─ 見つかった場合: パッドIDを返却
   └─ 見つからない場合: エラーを返却
6. レスポンス返却
   └─ {code: 0, message: "ok", data: {padID: "xxx"}}
```

### フローチャート

```mermaid
flowchart TD
    A[開始: getPadID API呼び出し] --> B{認証チェック}
    B -->|失敗| C[401 Unauthorized]
    B -->|成功| D[roIDパラメータ取得]
    D --> E[readonly2pad:roID を検索]
    E --> F{padID存在?}
    F -->|No| G[400 padID does not exist]
    F -->|Yes| H[200 OK: padID返却]
    H --> I[終了]
    G --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-014-01 | 存在確認 | 読み取り専用IDに対応するパッドIDが存在しない場合はエラー | 常時 |
| BR-014-02 | 直接参照 | データベースから直接検索し、パッドの存在確認は行わない | 常時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 検索 | readonly2pad:{roID} | SELECT | パッドIDを検索 |

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

#### readonly2pad:{roID}

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | value | キー `readonly2pad:{roID}` | パッドID取得 |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

データベース操作に関してはueberDB2のリトライ機構に依存。

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

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

## パフォーマンス要件

- キーによる直接参照のため、高速なレスポンスが期待できる

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

- APIキーまたはOAuth2認証が必須
- 読み取り専用IDから元のパッドIDを取得できるため、パッドの存在が露出する
- 認証されたユーザーのみがこのAPIを使用可能

## 備考

- 対応するパッドが削除されている場合、マッピングも削除されているためエラーになる
- 本APIは読み取り専用IDの形式検証は行わない（r.プレフィックスのチェックなし）

---

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

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

### 推奨読解順序

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

読み取り専用IDとパッドIDのマッピング構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ReadOnlyManager.ts | `src/node/db/ReadOnlyManager.ts` | getPadId関数（60行目） |

**読解のコツ**: readonly2pad:キーからの単純な読み取り操作であることを理解する。

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

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

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

**主要処理フロー**:
1. **1093-1113行目**: POST /pads/padId のルート定義
2. **103行目**: getPadIDの引数（roID）

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

実際のID取得ロジックを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | API.ts | `src/node/db/API.ts` | getPadID関数（684-692行目） |
| 3-2 | ReadOnlyManager.ts | `src/node/db/ReadOnlyManager.ts` | getPadId関数（60行目） |

**主要処理フロー**:
- **API.ts 686行目**: readOnlyManager.getPadId(roID)を呼び出し
- **API.ts 687-689行目**: nullチェックとエラー処理
- **ReadOnlyManager.ts 60行目**: db.getで直接取得

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

```
POST /api/2/pads/padId (RestAPI.ts)
    │
    └─ apiHandler.handle() (APIHandler.ts)
           │
           └─ api.getPadID() (API.ts:684-692)
                  │
                  └─ readOnlyManager.getPadId(roID) (ReadOnlyManager.ts:60)
                         │
                         └─ db.get(`readonly2pad:${roID}`)
                                │
                                ├─ [存在] ─▶ padID返却
                                │
                                └─ [不存在] ─▶ null返却 ─▶ エラー
```

### データフロー図

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

roID          ───────▶ readOnlyManager.getPadId() ──────▶ padID
                              │
                              └─▶ db.get(readonly2pad:)
                                       │
                                       ├─[存在] ─▶ {padID: "xxx"}
                                       │
                                       └─[不在] ─▶ Error: padID does not exist
                              │
                              ▼
                       {padID: "xxx"} ───────▶ JSON Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| API.ts | `src/node/db/API.ts` | ソース | getPadID関数の実装 |
| ReadOnlyManager.ts | `src/node/db/ReadOnlyManager.ts` | ソース | getPadId関数の実装 |
| RestAPI.ts | `src/node/handler/RestAPI.ts` | ソース | REST APIエンドポイント定義 |
| APIHandler.ts | `src/node/handler/APIHandler.ts` | ソース | API呼び出しハンドリング |
| DB.ts | `src/node/db/DB.ts` | ソース | データベースアクセス層 |
