# 機能設計書 21-インターセプトルート（Intercepting Routes）

## 概要

本ドキュメントは、Next.js App Routerにおけるインターセプトルート（Intercepting Routes）機能の設計を記述する。インターセプトルートは、既存のルートへのナビゲーションを別のルートで「インターセプト（横取り）」し、モーダル表示やオーバーレイ表示を実現するための仕組みである。

### 本機能の処理概要

**業務上の目的・背景**：モダンWebアプリケーションでは、一覧画面から詳細をモーダルで表示し、URLを共有した場合はフルページで表示するというUXパターンが一般的である。インターセプトルートは、このような「ソフトナビゲーション時はモーダル表示、ハードナビゲーション（URL直接アクセス）時はフルページ表示」というパターンをファイルシステムベースのルーティングで宣言的に実現するために必要な機能である。

**機能の利用シーン**：SNSのフィード画面で写真をクリックするとモーダルで拡大表示し、URLを直接開くと写真の専用ページが表示されるケース。ECサイトの商品一覧から商品詳細をモーダルで表示するケース。ダッシュボードのリスト項目をクリックして詳細をオーバーレイ表示するケースなど。

**主要な処理内容**：
1. ファイルシステム上の`(.)`、`(..)`、`(..)(..)`、`(...)`マーカーの検出と解析
2. インターセプトルートのリライトルール生成（`NEXT_URL`ヘッダーによるマッチング）
3. クライアントサイドルーターでのインターセプトルート判定とツリー管理
4. ビルド時のインターセプトルートパスの正規化とバリデーション

**関連システム・外部連携**：App Routerのルーティングシステム、並列ルート（Parallel Routes）と組み合わせて使用されることが多い。ビルドシステムにおけるマニフェスト生成とも連携する。

**権限による制御**：特になし。ルーティングレベルの機能のため、認証・認可はアプリケーション層で制御する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | インターセプトルートは画面機能マッピングに直接関連する画面定義はないが、App Routerの並列ルート機構と組み合わせてモーダルUI等を実現する |

## 機能種別

ルーティング制御 / URL書き換え（Rewrite）生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| appPaths | string[] | Yes | App Routerで定義された全アプリケーションパスの配列 | 各パスは`/`で始まる文字列 |
| basePath | string | No | アプリケーションのベースパス（デフォルト: `''`） | 有効なパスプレフィックス |
| path（解析対象） | string | Yes | インターセプトマーカーを含むルートパス | `(.)`、`(..)`、`(..)(..)`、`(...)`のいずれかを含む |

### 入力データソース

- ファイルシステム上のappディレクトリ構造（ビルド時にスキャンされる）
- `NEXT_URL`リクエストヘッダー（ランタイムでの遷移元URL判定に使用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| rewrites | Rewrite[] | インターセプトルートのリライトルール配列 |
| interceptingRoute | string | インターセプト元のルート（遷移元） |
| interceptedRoute | string | インターセプトされるルート（遷移先） |

### 出力先

- ビルドマニフェスト（routes-manifest.json）のリライトルールとして出力
- ランタイムのリクエスト処理パイプラインでリライトルールとして適用

## 処理フロー

### 処理シーケンス

```
1. ビルド時のインターセプトルート解析
   └─ appディレクトリをスキャンし、インターセプトマーカーを含むパスを検出
2. マーカー種別の判定
   └─ (.) = 同階層、(..) = 1階層上、(..)(..) = 2階層上、(...) = ルートからマッチ
3. interceptingRouteとinterceptedRouteの算出
   └─ マーカー位置でパスを分割し、マーカー種別に基づいてルートを計算
4. リライトルールの生成
   └─ source（マッチ対象パス）、destination（リライト先）、has条件（NEXT_URLヘッダー）を設定
5. ランタイムでのリライト適用
   └─ クライアントサイドナビゲーション時にNEXT_URLヘッダーを送信し、サーバーがリライトルールに基づいてインターセプトルートのコンポーネントを返却
```

### フローチャート

```mermaid
flowchart TD
    A[ビルド開始] --> B[appPathsをスキャン]
    B --> C{インターセプトマーカーを含む?}
    C -->|No| D[スキップ]
    C -->|Yes| E[マーカー種別を判定]
    E --> F["extractInterceptionRouteInformation()"]
    F --> G[interceptingRoute算出]
    F --> H[interceptedRoute算出]
    G --> I[リライトルール生成]
    H --> I
    I --> J[source: interceptedRouteのregex]
    I --> K["has: NEXT_URLヘッダーでinterceptingRouteをマッチ"]
    I --> L[destination: 元のappPath]
    J --> M[routes-manifestに出力]
    K --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | マーカー優先順位 | `(..)(..)`、`(.)`、`(..)`、`(...)`の順で最初にマッチしたマーカーを使用 | パスにインターセプトマーカーが含まれる場合 |
| BR-21-02 | 同階層インターセプト | `(.)`マーカーは同一階層のルートをインターセプト | interceptingRouteが`/`でない場合、interceptedRoute = interceptingRoute + '/' + remainingPath |
| BR-21-03 | 1階層上インターセプト | `(..)`マーカーはinterceptingRouteの1階層上でマッチ | interceptingRouteが`/`の場合はエラー |
| BR-21-04 | 2階層上インターセプト | `(..)(..)`マーカーはinterceptingRouteの2階層上でマッチ | interceptingRouteのセグメント数が2以下の場合はエラー |
| BR-21-05 | ルートインターセプト | `(...)`マーカーはルートディレクトリからマッチ | 常に`/` + remainingPath |
| BR-21-06 | Route Groups除外 | interceptingRouteの正規化時にRoute Groups（括弧付きフォルダ）は除外される | `normalizeAppPath`によりRoute Groupセグメントが除去される |

### 計算ロジック

マーカー種別に基づくinterceptedRoute算出ロジック：
- `(.)`: interceptingRoute === '/' ? `/${interceptedRoute}` : `${interceptingRoute}/${interceptedRoute}`
- `(..)`: interceptingRouteの最後のセグメントを除去し、interceptedRouteを連結
- `(..)(..)`: interceptingRouteの最後の2セグメントを除去し、interceptedRouteを連結
- `(...)`: `/${interceptedRoute}`（ルートから直接）

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

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

該当なし。インターセプトルートはファイルシステムベースのルーティング機能であり、データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Invalid interception route | パスにマーカーが含まれるが正しい形式でない | エラーメッセージに正しい形式を表示 |
| - | Invalid (..) at root | `(..)`マーカーをルートレベルで使用 | `(.)`の使用を推奨するメッセージを表示 |
| - | Invalid (..)(..) at root | `(..)(..)`マーカーをルートまたは1階層で使用 | セグメント数不足のエラーを表示 |

### リトライ仕様

リトライ不要。ビルド時のバリデーションエラーであり、開発者がファイル構造を修正する必要がある。

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

該当なし。

## パフォーマンス要件

- ビルド時のリライトルール生成はアプリケーションパス数に対して線形時間 O(n)
- ランタイムのリライトマッチングは正規表現ベースで高速に処理される

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

- `NEXT_URL`ヘッダーはNext.js内部ヘッダーであり、外部からの偽装を防ぐためにサーバー側で適切に検証される
- リライトルールはビルド時に静的に生成されるため、実行時の改ざんリスクは低い

## 備考

- インターセプトルートは並列ルート（Parallel Routes）と組み合わせて使用することが推奨される
- ハードナビゲーション（ページリロード、URL直接アクセス）時にはインターセプトは発生せず、通常のルーティングが適用される

---

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

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

### 推奨読解順序

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

インターセプトルートの核となるマーカー定義と型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | interception-routes.ts | `packages/next/src/shared/lib/router/utils/interception-routes.ts` | マーカー定数`INTERCEPTION_ROUTE_MARKERS`と`InterceptionRouteInformation`型の定義 |

**読解のコツ**: `INTERCEPTION_ROUTE_MARKERS`配列の順序が重要。`(..)(..)`が最初にチェックされるのは、`(..)`のプレフィックスマッチを防ぐためである。

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

リライトルール生成の起点を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | generate-interception-routes-rewrites.ts | `packages/next/src/lib/generate-interception-routes-rewrites.ts` | `generateInterceptionRoutesRewrites`関数がリライトルール生成のメインエントリーポイント |

**主要処理フロー**:
1. **16-17行目**: appPathsをループしてインターセプトルートかどうか判定
2. **18-19行目**: `extractInterceptionRouteInformation`でinterceptingRouteとinterceptedRouteを抽出
3. **21-33行目**: `getNamedRouteRegex`で各ルートの正規表現を生成
4. **35-43行目**: ヘッダーマッチ用の正規表現を調整（アンカー除去、ワイルドカード変換）
5. **45-56行目**: リライトオブジェクトを構築（source、destination、has条件）

#### Step 3: インターセプトルート解析ロジックを理解する

マーカーの解析とルート算出のロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | interception-routes.ts | `packages/next/src/shared/lib/router/utils/interception-routes.ts` | `extractInterceptionRouteInformation`関数のswitch文で各マーカーの処理を理解 |

**主要処理フロー**:
- **13-22行目**: `isInterceptionRouteAppPath`でパスにマーカーが含まれるか判定
- **39-108行目**: `extractInterceptionRouteInformation`でマーカー種別に応じたルート算出
- **60行目**: `normalizeAppPath`によりRoute Groupsを除外した正規化パスを取得
- **62-105行目**: switch文で`(.)`、`(..)`、`(...)`、`(..)(..)`それぞれの算出ロジック

#### Step 4: クライアントサイドのインターセプト判定を理解する

クライアントサイドルーターでのインターセプトルート検出。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | has-interception-route-in-current-tree.ts | `packages/next/src/client/components/router-reducer/reducers/has-interception-route-in-current-tree.ts` | ルーターツリー内のインターセプトルート検出 |
| 4-2 | fetch-server-response.ts | `packages/next/src/client/components/router-reducer/fetch-server-response.ts` | NEXT_URLヘッダーの送信処理 |

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

```
generateInterceptionRoutesRewrites() [src/lib/generate-interception-routes-rewrites.ts]
    |
    +-- isInterceptionRouteAppPath() [src/shared/lib/router/utils/interception-routes.ts]
    |       +-- INTERCEPTION_ROUTE_MARKERS のプレフィックスマッチ
    |
    +-- extractInterceptionRouteInformation() [src/shared/lib/router/utils/interception-routes.ts]
    |       +-- normalizeAppPath() [src/shared/lib/router/utils/app-paths.ts]
    |       +-- マーカー種別に応じたルート算出 (switch文)
    |
    +-- getNamedRouteRegex() [src/shared/lib/router/utils/route-regex.ts]
            +-- destination regex 生成
            +-- header regex 生成
            +-- source regex 生成
```

### データフロー図

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

appPaths (string[])     ──> isInterceptionRouteAppPath()     ──> フィルタリング
                             |
インターセプトパス       ──> extractInterceptionRouteInformation() ──> {interceptingRoute, interceptedRoute}
                             |
{interceptingRoute,     ──> getNamedRouteRegex() x3          ──> 正規表現パターン
 interceptedRoute}           |
                             |
正規表現パターン        ──> リライトオブジェクト構築           ──> Rewrite[]
                                                                   (routes-manifest.json)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| interception-routes.ts | `packages/next/src/shared/lib/router/utils/interception-routes.ts` | ソース | インターセプトルートのマーカー定義と解析ロジック |
| generate-interception-routes-rewrites.ts | `packages/next/src/lib/generate-interception-routes-rewrites.ts` | ソース | リライトルール生成のメインロジック |
| generate-interception-routes-rewrites.test.ts | `packages/next/src/lib/generate-interception-routes-rewrites.test.ts` | テスト | リライトルール生成のテスト |
| route-regex.ts | `packages/next/src/shared/lib/router/utils/route-regex.ts` | ソース | ルート正規表現の生成 |
| app-paths.ts | `packages/next/src/shared/lib/router/utils/app-paths.ts` | ソース | App Routerパスの正規化（normalizeAppPath） |
| has-interception-route-in-current-tree.ts | `packages/next/src/client/components/router-reducer/reducers/has-interception-route-in-current-tree.ts` | ソース | クライアントサイドツリー内のインターセプトルート検出 |
| fetch-server-response.ts | `packages/next/src/client/components/router-reducer/fetch-server-response.ts` | ソース | サーバーレスポンス取得時のNEXT_URLヘッダー送信 |
| compute-changed-path.ts | `packages/next/src/client/components/router-reducer/compute-changed-path.ts` | ソース | パス変更検出でのインターセプトルート考慮 |
| app-router-headers.ts | `packages/next/src/client/components/app-router-headers.ts` | ソース | NEXT_URLヘッダー定数の定義 |
| base-server.ts | `packages/next/src/server/base-server.ts` | ソース | サーバーサイドでのインターセプトルートリライト適用 |
