# 機能設計書 24-Dynamic Routes

## 概要

本ドキュメントは、Next.jsにおけるDynamic Routes機能の設計を記述する。Dynamic Routesは、`[param]`、`[...slug]`、`[[...slug]]`といった規約により動的なURLセグメントを定義し、パスパラメータの取得を可能にするルーティング機能である。

### 本機能の処理概要

**業務上の目的・背景**：Webアプリケーションでは、同じページテンプレートで異なるデータを表示する必要がある（例：`/products/1`、`/products/2`など）。Dynamic Routesは、ファイルシステムベースのルーティングにおいて動的なURLパスパラメータを定義・取得する仕組みを提供し、事前にすべてのパスを定義せずに柔軟なルーティングを実現する。

**機能の利用シーン**：ブログの個別記事ページ（`/blog/[slug]`）、商品詳細ページ（`/products/[id]`）、カテゴリ別一覧（`/categories/[...path]`）、オプショナルなキャッチオールルート（`/docs/[[...slug]]`）など。

**主要な処理内容**：
1. ファイルシステム上の`[param]`パターンの検出と解析
2. 動的セグメントの正規表現生成（RouteRegex）
3. URLパスからのパラメータ抽出（RouteMatcher）
4. ビルド時の静的パス生成（`generateStaticParams`/`getStaticPaths`との連携）
5. ランタイムでの動的パラメータの`params`オブジェクトへの注入

**関連システム・外部連携**：App RouterおよびPages Routerの両方で使用される。SSG（`getStaticPaths`/`generateStaticParams`）と連携して静的パスを生成する。

**権限による制御**：特になし。動的ルートそのものにはアクセス制御は含まれない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Dynamic Routesはすべての動的URLパスを持つ画面の基盤であり、直接的な画面定義はない |

## 機能種別

ルーティング制御 / パラメータ抽出

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ルートパス | string | Yes | 動的セグメントを含むファイルパス | `[param]`、`[...slug]`、`[[...slug]]`形式 |
| URLパス | string | Yes | 実際のリクエストURL | 有効なURLパス |

### 入力データソース

- ファイルシステム上のappディレクトリまたはpagesディレクトリの構造
- HTTPリクエストのURLパス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| params | Record<string, string \| string[]> | 動的パラメータのキー・値マッピング |
| routeRegex | RouteRegex | ルートの正規表現とグループ情報 |
| isDynamic | boolean | ルートが動的かどうかの判定結果 |

### 出力先

- ページコンポーネントの`params` prop
- `useParams()`フックの戻り値
- `generateStaticParams`/`getStaticPaths`への入力情報

## 処理フロー

### 処理シーケンス

```
1. 動的ルート判定
   └─ isDynamicRoute()で[param]パターンの存在を正規表現でチェック
2. 正規表現生成
   └─ getRouteRegex()でルートパスから正規表現とグループ情報を生成
3. パラメータ抽出
   └─ getRouteMatcher()で生成したマッチャーにURLパスを適用
4. パラメータ注入
   └─ 抽出したパラメータをコンポーネントのprops/フックに注入
```

### フローチャート

```mermaid
flowchart TD
    A["ルート定義: /blog/[slug]"] --> B["isDynamicRoute() で判定"]
    B --> C["getRouteRegex() で正規表現生成"]
    C --> D["/blog/(?<slug>[^/]+?)(?:/)?$"]
    D --> E["リクエスト: /blog/hello-world"]
    E --> F["getRouteMatcher() でマッチング"]
    F --> G["params = { slug: 'hello-world' }"]
    G --> H["コンポーネントにparams注入"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | 単一パラメータ | `[param]`は1つのURLセグメントにマッチ | 単一の角括弧セグメント |
| BR-24-02 | キャッチオール | `[...slug]`は1つ以上のURLセグメントにマッチ | 三点リーダー付き角括弧 |
| BR-24-03 | オプショナルキャッチオール | `[[...slug]]`は0個以上のURLセグメントにマッチ | 二重角括弧 |
| BR-24-04 | 厳密モード | デフォルトの厳密モードでは`[param]`の前後にプレフィックス/サフィックスを付けられない | `isDynamicRoute`のstrict=true |
| BR-24-05 | SSG連携 | 動的ルートでSSGを使う場合は`getStaticPaths`（Pages）または`generateStaticParams`（App）が必須 | isSSG && pageIsDynamic |

### 計算ロジック

正規表現生成ロジック：
- `[param]` -> `(?<param>[^/]+?)`（1セグメントにマッチ）
- `[...slug]` -> `(?<slug>.+?)`（1つ以上のセグメントにマッチ）
- `[[...slug]]` -> `(?<slug>.+?)?`（0個以上のセグメントにオプショナルマッチ）

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

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

該当なし。Dynamic Routes自体はデータベースに直接アクセスしない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | getStaticPaths必須エラー | 動的SSGページに`getStaticPaths`がない | `getStaticPaths`を実装する |
| - | getStaticPaths不要エラー | 非動的ページに`getStaticPaths`がある | `getStaticPaths`を削除する |
| - | getStaticProps必須エラー | `getStaticPaths`があるのに`getStaticProps`がない | `getStaticProps`を実装する |
| 404 | Not Found | URLが定義済みの動的ルートにマッチしない | fallback設定を確認 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- 動的ルート判定はコンパイル済み正規表現による高速マッチング
- ルート正規表現はビルド時に生成されキャッシュされる

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

- パラメータ値はURLデコードされて提供されるため、SQLインジェクション等への対策はアプリケーション層で必要
- キャッチオールルートでは予期しないパス構造のリクエストが来る可能性があるため、バリデーションが重要

## 備考

- Dynamic Routesの優先順位：静的ルート > 動的ルート > キャッチオールルート
- App Routerでは`params`はPromiseとして提供され、`await`で取得する

---

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

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

### 推奨読解順序

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

ルート正規表現の型定義とグループ情報を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | route-regex.ts | `packages/next/src/shared/lib/router/utils/route-regex.ts` | `RouteRegex`と`Group`インターフェースの定義（10-19行目） |

**読解のコツ**: `Group`の`repeat`はキャッチオールルート、`optional`はオプショナルキャッチオールを表す。

#### Step 2: 動的ルート判定を理解する

`isDynamicRoute`関数の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | is-dynamic.ts | `packages/next/src/shared/lib/router/utils/is-dynamic.ts` | 正規表現`TEST_ROUTE`と`TEST_STRICT_ROUTE`による動的ルート判定 |

**主要処理フロー**:
1. **7行目**: `TEST_ROUTE` - 緩いマッチ（プレフィックス/サフィックスを許容）
2. **10行目**: `TEST_STRICT_ROUTE` - 厳密マッチ（セグメント全体が`[param]`形式）
3. **19-29行目**: インターセプトルートの場合はinterceptedRouteに対して判定

#### Step 3: 正規表現生成とマッチングを理解する

ルートパスから正規表現を生成し、URLマッチングを行う処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | route-regex.ts | `packages/next/src/shared/lib/router/utils/route-regex.ts` | `getRouteRegex`と`getNamedRouteRegex`の実装 |
| 3-2 | route-matcher.ts | `packages/next/src/shared/lib/router/utils/route-matcher.ts` | `getRouteMatcher`でURLパスとルート正規表現をマッチング |

#### Step 4: パラメータ抽出を理解する

動的セグメントからのパラメータ抽出処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | get-dynamic-param.ts | `packages/next/src/shared/lib/router/utils/get-dynamic-param.ts` | `PARAMETER_PATTERN`による動的パラメータのパース |
| 4-2 | get-segment-param.tsx | `packages/next/src/shared/lib/router/utils/get-segment-param.tsx` | セグメントからパラメータ情報を抽出 |

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

```
isDynamicRoute() [is-dynamic.ts]
    |
    +-- isInterceptionRouteAppPath() (インターセプトルート判定)
    +-- TEST_STRICT_ROUTE / TEST_ROUTE (正規表現マッチ)

getRouteRegex() [route-regex.ts]
    |
    +-- PARAMETER_PATTERN による動的セグメント検出
    +-- 正規表現グループ(repeat/optional)の構築
    +-- RegExpオブジェクト生成

getRouteMatcher() [route-matcher.ts]
    |
    +-- RouteRegexのreでURLパスをマッチ
    +-- captureグループからパラメータを抽出
```

### データフロー図

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

/blog/[slug]/page.tsx ──> isDynamicRoute()             ──> true
                           |
[slug]                ──> getRouteRegex()               ──> /blog/(?<slug>[^/]+?)
                           |
/blog/hello-world     ──> getRouteMatcher()             ──> { slug: 'hello-world' }
                           |
params                ──> コンポーネント/フックに注入    ──> props.params
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| is-dynamic.ts | `packages/next/src/shared/lib/router/utils/is-dynamic.ts` | ソース | 動的ルート判定 |
| is-dynamic.test.ts | `packages/next/src/shared/lib/router/utils/is-dynamic.test.ts` | テスト | 動的ルート判定のテスト |
| route-regex.ts | `packages/next/src/shared/lib/router/utils/route-regex.ts` | ソース | ルート正規表現生成 |
| route-regex.test.ts | `packages/next/src/shared/lib/router/utils/route-regex.test.ts` | テスト | 正規表現生成のテスト |
| route-matcher.ts | `packages/next/src/shared/lib/router/utils/route-matcher.ts` | ソース | URLパスとルートのマッチング |
| get-dynamic-param.ts | `packages/next/src/shared/lib/router/utils/get-dynamic-param.ts` | ソース | 動的パラメータのパースロジック |
| get-segment-param.tsx | `packages/next/src/shared/lib/router/utils/get-segment-param.tsx` | ソース | セグメントパラメータ抽出 |
| sortable-routes.test.ts | `packages/next/src/shared/lib/router/utils/sortable-routes.test.ts` | テスト | ルートの優先順位ソート |
