# 機能設計書 48-revalidatePath

## 概要

本ドキュメントは、Next.jsの`revalidatePath()`関数の設計を記述する。指定されたパスに関連するキャッシュデータをオンデマンドで再検証（無効化）するためのAPIである。

### 本機能の処理概要

**業務上の目的・背景**：ISR（Incremental Static Regeneration）やキャッシュされたデータを、管理画面からの操作やWebhook経由で即座に更新したいケースがある。`revalidatePath()`はServer ActionsやRoute Handlers内から呼び出すことで、特定のパスに紐づくキャッシュを無効化し、次回アクセス時に最新データでページを再生成する。

**機能の利用シーン**：CMS更新時の特定ページ再生成、管理画面からのコンテンツ更新、Webhookによるページ無効化。

**主要な処理内容**：
1. パスの正規化（末尾スラッシュ除去、暗黙タグIDプレフィックス付与）
2. typeパラメータによるlayout/page種別の付与
3. 正規化されたパスをタグとして`revalidate()`内部関数に委譲
4. WorkStoreのpendingRevalidatedTagsにタグを追加
5. `pathWasRevalidated`フラグを更新

**関連システム・外部連携**：WorkStore、IncrementalCache

**権限による制御**：render phaseでの呼び出しは禁止（エラースロー）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面に直接関連しない。Server Actions/Route Handlersから呼び出す |

## 機能種別

キャッシュ制御 / データ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| originalPath | string | Yes | 再検証対象のパス | NEXT_CACHE_SOFT_TAG_MAX_LENGTH以下 |
| type | 'layout' \| 'page' | No | ルートの種別。動的ルートでは指定推奨 | 'layout'または'page'のみ |

### 入力データソース

関数の引数から直接取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| （なし） | void | 戻り値なし。副作用としてWorkStoreを更新 |

### 出力先

WorkStoreのpendingRevalidatedTagsとpathWasRevalidatedを更新。

## 処理フロー

### 処理シーケンス

```
1. revalidatePath(originalPath, type) 呼び出し
2. パス長チェック（NEXT_CACHE_SOFT_TAG_MAX_LENGTH以下）
3. パス正規化:
   a. NEXT_CACHE_IMPLICIT_TAG_IDプレフィックス付与
   b. 末尾スラッシュ除去（removeTrailingSlash）
4. typeが指定されている場合 → パスに'/layout'または'/page'を付与
5. typeが未指定かつ動的ルートの場合 → 警告出力
6. ルートパス('/')の場合は'/index'も追加
7. revalidate(tags, expression) 内部関数に委譲
8. WorkUnitStoreの型チェック:
   - render phase → エラー
   - cache/unstable-cache → エラー
   - prerender → abortAndThrow
   - prerender-ppr → postpone
   - prerender-legacy → DynamicServerError
   - request → usedDynamic設定
9. pendingRevalidatedTagsにタグ追加
10. pathWasRevalidated = ActionDidRevalidate設定
```

### フローチャート

```mermaid
flowchart TD
    A[revalidatePath呼び出し] --> B{パス長チェック}
    B -->|超過| C[警告 + return]
    B -->|OK| D[パス正規化]
    D --> E{type指定?}
    E -->|Yes| F[パスに/layout or /page追加]
    E -->|No| G{動的ルート?}
    G -->|Yes| H[警告出力]
    G -->|No| I[処理継続]
    F --> J[revalidate内部関数]
    H --> J
    I --> J
    J --> K{WorkUnitStore型}
    K -->|render| L[エラースロー]
    K -->|cache| L
    K -->|request| M[pendingRevalidatedTags追加]
    M --> N[pathWasRevalidated設定]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-48-01 | レンダリング中禁止 | render phase中のrevalidatePathはエラー | workUnitStore.phase === 'render' |
| BR-48-02 | キャッシュ関数内禁止 | "use cache"およびunstable_cache内でのrevalidatePathはエラー | cache/unstable-cacheスコープ |
| BR-48-03 | 動的ルート警告 | 動的ルート（[param]等）にtype未指定の場合は効果がないことを警告 | isDynamicRoute && !type |
| BR-48-04 | ルートパス正規化 | '/'は'/index'も同時にタグ追加 | normalizedPath === NEXT_CACHE_IMPLICIT_TAG_ID + '/' |
| BR-48-05 | パス長制限 | NEXT_CACHE_SOFT_TAG_MAX_LENGTHを超えるパスは警告して無視 | パス長超過時 |

### 計算ロジック

- normalizedPath: `${NEXT_CACHE_IMPLICIT_TAG_ID}${removeTrailingSlash(originalPath)}` + (type ? `/${type}` : '')

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

本機能はRDBを使用しない。WorkStoreの状態を更新し、後続のIncrementalCacheの再検証処理に委譲する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | WorkStore/IncrementalCache不在 | Invariantエラー |
| - | Error | render phase中の呼び出し | エラーメッセージでrender外での使用を案内 |
| - | Error | "use cache"内での呼び出し | エラーメッセージでrender外での使用を案内 |
| - | DynamicServerError | prerender-legacy中の呼び出し | 静的レンダリング不可通知 |

### リトライ仕様

不要。

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

不要。

## パフォーマンス要件

即座に完了する同期処理のため特に要件なし。実際のキャッシュ無効化は非同期で処理される。

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

- Server ActionsやRoute Handlersからのみ呼び出し可能（クライアントサイドからは直接呼び出せない）
- render phase中の呼び出しを禁止することで、レンダリングの予測可能性を確保

## 備考

- 内部的にはパスを暗黙タグに変換してrevalidateTag相当の処理を行う
- `NEXT_CACHE_IMPLICIT_TAG_ID`は`_N_T_`プレフィックス
- revalidatePathはprofileパラメータなし（即時無効化）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | revalidate.ts | `packages/next/src/server/web/spec-extension/revalidate.ts` | `revalidatePath()`関数（92-118行目） |

**主要処理フロー**:
1. **93-98行目**: パス長チェック
2. **100行目**: パス正規化（暗黙タグID + removeTrailingSlash）
3. **102-108行目**: type追加と動的ルート警告
4. **110-115行目**: ルートパスの'/index'追加
5. **117行目**: revalidate()に委譲

#### Step 2: revalidate内部関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | revalidate.ts | `packages/next/src/server/web/spec-extension/revalidate.ts` | `revalidate()`関数（120-237行目） |

**主要処理フロー**:
- **125-130行目**: WorkStore/IncrementalCacheバリデーション
- **133-194行目**: WorkUnitStore型別分岐（render禁止、cache禁止等）
- **197-219行目**: pendingRevalidatedTagsへのタグ追加（重複チェック付き）
- **233-236行目**: pathWasRevalidated = ActionDidRevalidate設定

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

```
revalidatePath(originalPath, type)
    │
    ├─ removeTrailingSlash(originalPath)
    ├─ isDynamicRoute(originalPath)
    └─ revalidate(tags, expression)
           │
           ├─ workAsyncStorage.getStore()
           ├─ workUnitAsyncStorage.getStore()
           ├─ [WorkUnitStore型別分岐]
           │      ├─ render → Error
           │      ├─ cache → Error
           │      ├─ prerender → abortAndThrow
           │      └─ request → usedDynamic
           ├─ store.pendingRevalidatedTags.push({tag, profile})
           └─ store.pathWasRevalidated = ActionDidRevalidate
```

### データフロー図

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

originalPath ───▶ 正規化
+ type              │
                    ├─▶ NEXT_CACHE_IMPLICIT_TAG_ID + path
                    ├─▶ + /layout or /page
                    └─▶ revalidate()
                           │
                           ├─▶ pendingRevalidatedTags
                           └─▶ pathWasRevalidated
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| revalidate.ts | `packages/next/src/server/web/spec-extension/revalidate.ts` | ソース | revalidatePath/revalidateTag/updateTagの実装 |
| constants.ts | `packages/next/src/lib/constants.ts` | ソース | NEXT_CACHE_IMPLICIT_TAG_ID, NEXT_CACHE_SOFT_TAG_MAX_LENGTH |
| dynamic-rendering.ts | `packages/next/src/server/app-render/dynamic-rendering.ts` | ソース | abortAndThrowOnSynchronousRequestDataAccess, postponeWithTracking |
| work-async-storage.external.ts | `packages/next/src/server/app-render/work-async-storage.external.ts` | ソース | WorkStore |
