# 機能設計書 87-リンクリダイレクト

## 概要

本ドキュメントは、「リンクリダイレクト」機能の設計を定義する。リンクリダイレクト機能は、短縮URLやトラッキングリンクのリダイレクト処理を行い、メール内リンクのクリック追跡などに利用される。

### 本機能の処理概要

LinkRedirectsServiceは、一意の短縮URLを生成し、元のURLへのリダイレクトを処理する。リダイレクト時にはイベントを発行し、クリック追跡を可能にする。

**業務上の目的・背景**：ニュースレターやメール配信において、リンクのクリック数を追跡するために、元のURLを短縮URLでラップする必要がある。また、URLの変更に対応するための柔軟なリダイレクト機構を提供する。

**機能の利用シーン**：
- ニュースレター内リンクのクリック追跡
- メールキャンペーンの効果測定
- 短縮URLによるURL管理
- リンク解析・統計収集

**主要な処理内容**：
1. ユニークな短縮URL（/r/xxxxxxxx形式）の生成
2. HTTPリダイレクトの処理（302リダイレクト）
3. RedirectEventの発行（クリック追跡用）
4. リダイレクトマッピングの保存・取得

**関連システム・外部連携**：
- DomainEvents - イベント発行
- link-tracking サービス - クリック追跡との連携
- email-analytics サービス - メール分析との連携

**権限による制御**：短縮URL自体には認証は不要（公開URL）。管理側の操作には管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | ニュースレター分析画面 | 補助機能 | クリック追跡結果の表示 |

## 機能種別

URL管理 / リダイレクトサービス

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| from | URL | Yes | リダイレクト元URL（短縮URL） | 有効なURL |
| to | URL | Yes | リダイレクト先URL | 有効なURL |
| filter | string | No | 検索フィルタ | NQL形式 |

### 入力データソース

- HTTPリクエスト（リダイレクト処理）
- メールサービス（リンク生成）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| LinkRedirect | object | リダイレクト設定オブジェクト |
| HTTP 302 | response | リダイレクトレスポンス |
| RedirectEvent | event | クリック追跡イベント |

### 出力先

- データベース（redirects テーブル）
- HTTPレスポンス
- DomainEventsキュー

## 処理フロー

### 処理シーケンス

```
1. 短縮URL生成（addRedirect）
   └─ getSlugUrlでユニークスラグ生成
   └─ LinkRedirectオブジェクト作成
   └─ リポジトリに保存
2. リダイレクト処理（handleRequest）
   └─ リクエストURLからLinkRedirect取得
   └─ RedirectEvent発行
   └─ X-Robots-Tag: noindex, nofollow設定
   └─ 302リダイレクト実行
```

### フローチャート

```mermaid
flowchart TD
    A[HTTPリクエスト /r/xxxxxx] --> B[handleRequest]
    B --> C[URL解析]
    C --> D{LinkRedirect存在?}
    D -->|Yes| E[RedirectEvent発行]
    E --> F[X-Robots-Tag設定]
    F --> G[302 リダイレクト]
    D -->|No| H[next() - 404へ]

    I[リンク生成リクエスト] --> J[getSlugUrl]
    J --> K[ランダムスラグ生成]
    K --> L{スラグ重複?}
    L -->|Yes| K
    L -->|No| M[addRedirect]
    M --> N[LinkRedirect保存]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-01 | スラグ一意性 | 短縮URLのスラグは一意 | 常時 |
| BR-87-02 | noindex設定 | リダイレクトURLは検索エンジンからインデックスしない | リダイレクト時 |
| BR-87-03 | プレフィックス | 短縮URLは/r/で始まる | 常時 |
| BR-87-04 | イベント発行 | リダイレクト時にRedirectEventを発行 | リダイレクト成功時 |

### 計算ロジック

スラグ生成: `crypto.randomBytes(4).toString('hex')` で8文字のランダム文字列を生成

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 生成 | redirects | INSERT | 新規リダイレクト設定の作成 |
| 取得 | redirects | SELECT | URLによるリダイレクト設定の取得 |
| 検索 | redirects | SELECT | フィルタによるID一覧取得 |

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

#### redirects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | from | 短縮URL | ユニーク |
| INSERT | to | リダイレクト先URL | - |
| SELECT | from | リクエストURL | WHERE条件 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | NotFound | 存在しない短縮URL | next()で404へ |
| - | InternalError | リポジトリエラー | next(e)でエラーハンドラへ |

### リトライ仕様

スラグ重複時は自動リトライ

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

リポジトリ層でトランザクション管理

## パフォーマンス要件

- リダイレクト処理は高速（DB検索の最小化）

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

- オープンリダイレクト攻撃への対策（信頼されたURLのみ登録）
- X-Robots-Tag設定によるSEOスパム防止

## 備考

- リンクトラッキングサービスと連携してクリック統計を収集

---

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

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

### 推奨読解順序

#### Step 1: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.js | `ghost/core/core/server/services/link-redirection/index.js` | サービスエクスポート |
| 1-2 | link-redirects-service.js | `ghost/core/core/server/services/link-redirection/link-redirects-service.js` | メインサービス |

**読解のコツ**: LinkRedirectsServiceがメインクラス。コンストラクタでbaseURLとrepositoryを受け取り、handleRequestがExpressミドルウェアとして動作する。

#### Step 2: ドメインモデルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | link-redirect.js | `ghost/core/core/server/services/link-redirection/link-redirect.js` | リダイレクトモデル |
| 2-2 | redirect-event.js | `ghost/core/core/server/services/link-redirection/redirect-event.js` | イベントクラス |

#### Step 3: リポジトリ層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | link-redirect-repository.js | `ghost/core/core/server/services/link-redirection/link-redirect-repository.js` | データアクセス |

**主要処理フロー**（link-redirects-service.js）:
- **14-38行目**: コンストラクタ、baseURL設定
- **45-52行目**: getSlugUrl - ユニークスラグ生成
- **69-78行目**: addRedirect - リダイレクト追加
- **96-117行目**: handleRequest - リダイレクト処理

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

```
Express Router
    │
    └─ LinkRedirectsService.handleRequest
           │
           ├─ linkRedirectRepository.getByURL
           │      └─ DB検索
           │
           ├─ RedirectEvent.create
           │      └─ イベント生成
           │
           ├─ DomainEvents.dispatch
           │      └─ イベント発行（link-tracking連携）
           │
           └─ res.redirect(302)
                  └─ HTTPリダイレクト
```

### データフロー図

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

Email Link      ───▶ addRedirect            ───▶ Short URL
  (original URL)     (slug generation)           (/r/xxxxxxxx)

HTTP Request    ───▶ handleRequest          ───▶ 302 Redirect
  (/r/xxxxxxxx)      (lookup & redirect)         (to original)
                            │
                            └───▶ RedirectEvent ───▶ Click Tracking
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `ghost/core/core/server/services/link-redirection/index.js` | ソース | エクスポート |
| link-redirects-service.js | `ghost/core/core/server/services/link-redirection/link-redirects-service.js` | ソース | メインサービス |
| link-redirect.js | `ghost/core/core/server/services/link-redirection/link-redirect.js` | ソース | ドメインモデル |
| redirect-event.js | `ghost/core/core/server/services/link-redirection/redirect-event.js` | ソース | イベントクラス |
| link-redirect-repository.js | `ghost/core/core/server/services/link-redirection/link-redirect-repository.js` | ソース | リポジトリ |
