# 機能設計書 43-unstable_noStore

## 概要

本ドキュメントは、Next.jsの`unstable_noStore`関数の設計を記述する。静的レンダリングを明示的にオプトアウトし、動的レンダリングを強制するための宣言的APIである。

### 本機能の処理概要

**業務上の目的・背景**：Next.jsのApp Routerではデフォルトで静的レンダリングが行われるが、リアルタイムデータや毎回変動するコンテンツを扱う場合には動的レンダリングが必要になる。`unstable_noStore`は特定のコンポーネントやサーバー関数内で呼び出すことで、そのスコープを動的レンダリングとしてマークし、キャッシュを無効化する。

**機能の利用シーン**：リアルタイムデータを表示するコンポーネント、毎回異なるコンテンツを返すAPI、ユーザー固有のデータ表示など、キャッシュが不適切な場面。

**主要な処理内容**：
1. WorkStoreの`isUnstableNoStore`フラグをtrueに設定
2. `markCurrentScopeAsDynamic()`を呼び出して動的レンダリングスコープとしてマーク
3. PPR環境ではpostponeを実行し動的部分としてマーク

**関連システム・外部連携**：WorkStore/WorkUnitStore（AsyncLocalStorage）、動的レンダリングシステム

**権限による制御**：なし。forceStatic設定時は無効化される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面に直接関連しない |

## 機能種別

制御処理 / レンダリング制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| （なし） | - | - | 引数なしの関数 | - |

### 入力データソース

WorkStore（`workAsyncStorage.getStore()`）とWorkUnitStore（`workUnitAsyncStorage.getStore()`）からコンテキストを取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| （なし） | void | 戻り値なし。副作用としてストアの状態を変更 |

### 出力先

WorkStoreの`isUnstableNoStore`フラグを更新。Dynamic I/O prerenderingコンテキストでは処理なし（noop）。

## 処理フロー

### 処理シーケンス

```
1. workAsyncStorage.getStore() でWorkStore取得
2. workUnitAsyncStorage.getStore() でWorkUnitStore取得
3. WorkStoreが存在しない場合 → return（Pages Router等）
4. forceStatic設定の場合 → return
5. store.isUnstableNoStore = true を設定
6. WorkUnitStoreの型に応じた処理:
   - prerender/prerender-client/prerender-runtime → return（Dynamic I/Oではnoop）
   - その他 → markCurrentScopeAsDynamic()を呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[unstable_noStore呼び出し] --> B{WorkStore存在?}
    B -->|No| C[return - 何もしない]
    B -->|Yes| D{forceStatic?}
    D -->|Yes| C
    D -->|No| E[isUnstableNoStore = true]
    E --> F{WorkUnitStoreの型}
    F -->|prerender系| C
    F -->|その他| G[markCurrentScopeAsDynamic]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | Pages Router互換 | WorkStoreが存在しない場合は何もせずreturn | Pages Router環境 |
| BR-43-02 | forceStatic優先 | forceStatic設定時は動的マークを行わない | workStore.forceStatic === true |
| BR-43-03 | Dynamic I/O noop | prerender/prerender-client/prerender-runtimeではnoopとなる | Dynamic I/O環境 |
| BR-43-04 | fetchへの影響 | isUnstableNoStoreフラグにより後続のfetchのキャッシュが無効化される | patch-fetchで参照 |

### 計算ロジック

特になし。

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

本機能はデータベースを操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | - | エラーをスローするケースはない。WorkStore不在時はサイレントにreturn |

### リトライ仕様

不要。

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

不要。

## パフォーマンス要件

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

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

特になし。

## 備考

- `unstable_`プレフィックスが示す通り実験的APIである
- PPR（Partial Prerendering）環境ではpostpone処理により動的ホールとしてマークされる
- `use cache`スコープ内では`markCurrentScopeAsDynamic`のロジックにより適切に処理される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | unstable-no-store.ts | `packages/next/src/server/web/spec-extension/unstable-no-store.ts` | 全体54行の小さなファイル。`unstable_noStore()`関数全体を読む |

**主要処理フロー**:
1. **22行目**: WorkStore取得
2. **23行目**: WorkUnitStore取得
3. **24-28行目**: Store不在時のearly return
4. **29-30行目**: forceStatic時のearly return
5. **32行目**: `isUnstableNoStore = true`設定
6. **33-49行目**: WorkUnitStoreの型別分岐
7. **51行目**: `markCurrentScopeAsDynamic()`呼び出し

#### Step 2: 動的マーク処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dynamic-rendering.ts | `packages/next/src/server/app-render/dynamic-rendering.ts` | `markCurrentScopeAsDynamic()`関数の実装。PPR時のpostpone、レガシーprerender時のエラースロー等 |

#### Step 3: fetchへの影響を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | patch-fetch.ts | `packages/next/src/server/lib/patch-fetch.ts` | 419行目: `isUsingNoStore`の参照。643-645行目: noStoreフラグでfinalRevalidate=0に設定 |

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

```
unstable_noStore()
    │
    ├─ workAsyncStorage.getStore()
    ├─ workUnitAsyncStorage.getStore()
    └─ markCurrentScopeAsDynamic(store, workUnitStore, 'unstable_noStore()')
```

### データフロー図

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

（なし） ───▶ unstable_noStore() ───▶ WorkStore.isUnstableNoStore = true
                     │
                     └─▶ markCurrentScopeAsDynamic()
                            └─▶ 動的レンダリングスコープ化
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| unstable-no-store.ts | `packages/next/src/server/web/spec-extension/unstable-no-store.ts` | ソース | unstable_noStoreの実装 |
| dynamic-rendering.ts | `packages/next/src/server/app-render/dynamic-rendering.ts` | ソース | markCurrentScopeAsDynamic |
| patch-fetch.ts | `packages/next/src/server/lib/patch-fetch.ts` | ソース | isUnstableNoStoreフラグの参照元 |
| work-async-storage.external.ts | `packages/next/src/server/app-render/work-async-storage.external.ts` | ソース | WorkStore |
| work-unit-async-storage.external.ts | `packages/next/src/server/app-render/work-unit-async-storage.external.ts` | ソース | WorkUnitStore |
