# 機能設計書 49-revalidateTag

## 概要

本ドキュメントは、Next.jsの`revalidateTag()`関数および関連する`updateTag()`関数の設計を記述する。タグベースのオンデマンドキャッシュ再検証を提供するAPIであり、特定のタグに紐づくキャッシュエントリを一括で無効化する。

### 本機能の処理概要

**業務上の目的・背景**：fetchやunstable_cache、"use cache"で付与されたキャッシュタグを使って、関連するキャッシュエントリを一括で再検証（無効化）する。データの変更があった場合にServer ActionsやRoute Handlersから呼び出すことで、影響範囲のキャッシュを効率的に更新できる。

**機能の利用シーン**：データベース更新後のキャッシュ無効化、CMSのコンテンツ変更通知、特定カテゴリの商品データ更新など。

**主要な処理内容**：
1. `revalidateTag(tag, profile)`: タグに紐づくキャッシュを無効化。profileで再検証の粒度を制御
2. `updateTag(tag)`: Server Action内からの即時無効化（read-your-own-writes保証）
3. 内部`revalidate()`関数: WorkStoreのpendingRevalidatedTagsにタグを追加し、pathWasRevalidatedフラグを更新

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

**権限による制御**：`updateTag()`はServer Actionsからのみ呼び出し可能。`revalidateTag()`はServer Actions/Route Handlersから呼び出し可能。

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

#### revalidateTag

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tag | string | Yes | 再検証対象のタグ | - |
| profile | string \| CacheLifeConfig | No | 再検証プロファイル。未指定時は非推奨警告 | CacheLifeConfig: { expire?: number } |

#### updateTag

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tag | string | Yes | 再検証対象のタグ | - |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

WorkStoreのpendingRevalidatedTagsとpathWasRevalidatedを更新。後続の処理でIncrementalCache.revalidateTag()が呼び出される。

## 処理フロー

### 処理シーケンス

```
1. revalidateTag(tag, profile) / updateTag(tag) 呼び出し
2. [updateTagの場合] Server Actionコンテキストチェック
3. [revalidateTagの場合] profile未指定時に非推奨警告
4. revalidate(tags, expression, profile) に委譲
5. WorkStore/IncrementalCacheバリデーション
6. WorkUnitStore型チェック:
   - render phase → エラー
   - cache/unstable-cache → エラー
   - prerender → abortAndThrow
   - prerender-ppr → postpone
   - prerender-legacy → DynamicServerError
   - request → usedDynamic設定
7. pendingRevalidatedTagsにタグ追加（重複チェック付き）
8. profileの解決（文字列→cacheLifeProfiles、オブジェクト→そのまま）
9. profile未指定またはcacheLife.expire === 0の場合:
   pathWasRevalidated = ActionDidRevalidate設定
```

### フローチャート

```mermaid
flowchart TD
    A[revalidateTag/updateTag呼び出し] --> B{updateTag?}
    B -->|Yes| C{Server Action内?}
    C -->|No| D[エラースロー]
    C -->|Yes| E[revalidate呼び出し - profile無し]
    B -->|No| F{profile指定?}
    F -->|No| G[非推奨警告]
    G --> H[revalidate呼び出し]
    F -->|Yes| H
    E --> I[WorkStore/WorkUnitStoreバリデーション]
    H --> I
    I --> J{WorkUnitStore型}
    J -->|render/cache| K[エラースロー]
    J -->|request| L[pendingRevalidatedTags追加]
    L --> M{即時無効化?}
    M -->|Yes| N[pathWasRevalidated設定]
    M -->|No| O[stale-while-revalidate更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | 非推奨警告 | revalidateTagの第2引数なし呼び出しは非推奨。"max"を指定するかupdateTagを使用 | profile未指定時 |
| BR-49-02 | updateTag制約 | updateTagはServer Actionsからのみ呼び出し可能（Route Handlers不可） | 常時 |
| BR-49-03 | stale-while-revalidate | profileが指定されexpire > 0の場合、pathWasRevalidatedは設定されない | profile指定 && expire > 0 |
| BR-49-04 | 即時無効化 | profile未指定またはcacheLife.expire === 0の場合、pathWasRevalidated = ActionDidRevalidate | 条件合致時 |
| BR-49-05 | 重複排除 | 同一タグ・同一profileの重複追加を防止 | 常時 |

### 計算ロジック

- profile解決: 文字列 → `store.cacheLifeProfiles[profile]`、オブジェクト → そのまま使用
- pathWasRevalidated設定条件: `!profile || cacheLife?.expire === 0`

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

本機能はRDBを使用しない。IncrementalCacheとCacheHandler.updateTags()を通じてタグマニフェストを更新する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | WorkStore/IncrementalCache不在 | Invariantエラー |
| - | Error | render phase中の呼び出し | エラーメッセージでrender外での使用を案内 |
| - | Error | "use cache"内での呼び出し | エラーメッセージでrender外での使用を案内 |
| - | Error | updateTagをRoute Handlerから呼び出し | エラーメッセージでServer Actionからの使用を案内 |

### リトライ仕様

不要。

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

不要。

## パフォーマンス要件

即座に完了する同期処理のため特に要件なし。

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

- updateTagはServer Actionsからのみ呼び出し可能であり、クライアントからの直接呼び出しは不可
- revalidateTagもServer Actions/Route Handlersからの呼び出しに限定

## 備考

- `revalidateTag`の第2引数は最近追加された機能で、非推奨警告は互換性のために存在
- `updateTag`はread-your-own-writesセマンティクスを提供し、Server Action内でのデータ更新後に即座にキャッシュを無効化
- `refresh()`関数も同ファイルに含まれ、クライアントキャッシュのリフレッシュ（動的データのみ）を行う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | revalidate.ts | `packages/next/src/server/web/spec-extension/revalidate.ts` | `revalidateTag()`関数（29-36行目）、`updateTag()`関数（44-58行目） |

**主要処理フロー**:
1. **29-36行目**: revalidateTag - profile未指定時の非推奨警告、revalidate()への委譲
2. **44-58行目**: updateTag - Server Actionコンテキストチェック、profile未指定でrevalidate()呼び出し
3. **65-85行目**: refresh() - pathWasRevalidated = ActionDidRevalidateDynamicOnlyの設定

#### 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型別分岐
- **197-219行目**: pendingRevalidatedTagsへのタグ追加（重複チェック + profile比較）
- **224-236行目**: profile解決とpathWasRevalidated設定条件判定

#### Step 3: タグ処理の後続を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | use-cache-wrapper.ts | `packages/next/src/server/use-cache/use-cache-wrapper.ts` | `isRecentlyRevalidatedTag()`関数（1888-1909行目）: pendingRevalidatedTagsの参照箇所 |

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

```
revalidateTag(tag, profile) / updateTag(tag)
    │
    └─ revalidate(tags, expression, profile)
           │
           ├─ workAsyncStorage.getStore()
           ├─ workUnitAsyncStorage.getStore()
           ├─ [WorkUnitStore型別分岐]
           ├─ store.pendingRevalidatedTags.push({tag, profile})
           └─ store.pathWasRevalidated = ActionDidRevalidate
                                               │
                                    [後続処理]
                                    incrementalCache.revalidateTag()
                                    cacheHandler.updateTags()
```

### データフロー図

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

tag + profile ───▶ revalidateTag()
                       │
                       └─▶ revalidate()
                              │
                              ├─▶ pendingRevalidatedTags
                              ├─▶ pathWasRevalidated
                              │
                         [後続処理]
                              ├─▶ incrementalCache.revalidateTag(tags)
                              └─▶ cacheHandler.updateTags(tags, {expire})
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| revalidate.ts | `packages/next/src/server/web/spec-extension/revalidate.ts` | ソース | revalidateTag/updateTag/revalidatePathの実装 |
| use-cache-wrapper.ts | `packages/next/src/server/use-cache/use-cache-wrapper.ts` | ソース | isRecentlyRevalidatedTag()での参照 |
| action-revalidation-kind.ts | `packages/next/src/shared/lib/action-revalidation-kind.ts` | ソース | ActionDidRevalidate定数 |
| work-async-storage.external.ts | `packages/next/src/server/app-render/work-async-storage.external.ts` | ソース | WorkStore |
