# 帳票設計書 28-fetch-metrics.json

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `fetch-metrics.json` の設計仕様を定義する。このファイルは静的生成時に収集されたfetchメトリクス（URL・ステータスコード・所要時間等）をパスごとに記録するJSONレポートである。

### 本帳票の処理概要

`fetch-metrics.json` は、Next.jsのプロダクションビルドにおける静的ページ生成（SSG/ISR）フェーズで行われたfetchリクエストの詳細メトリクスを、ページパスごとに集計・記録するファイルである。デバッグ出力モードまたは環境変数 `NEXT_SSG_FETCH_METRICS=1` が設定されている場合にのみ生成される。

**業務上の目的・背景**：静的生成時に外部APIやデータソースへのfetchリクエストが行われる場合、そのパフォーマンス（レスポンス時間、キャッシュヒット率等）がビルド時間に直接影響する。このメトリクスファイルにより、どのページのどのfetchリクエストがボトルネックになっているかを特定でき、ビルドパフォーマンスの最適化に活用できる。

**帳票の利用シーン**：ビルドパフォーマンス分析時、fetchキャッシュ戦略の最適化時、外部API依存の診断時。

**主要な出力内容**：
1. ページパスをキーとしたfetchメトリクスの配列（各メトリクスにはURL、HTTPメソッド、ステータスコード、所要時間、キャッシュ状態等を含む）

**帳票の出力タイミング**：`next build` コマンドの静的生成フェーズ完了後、デバッグ出力モードまたは `NEXT_SSG_FETCH_METRICS=1` 環境変数が設定されている場合に生成される。

**帳票の利用者**：開発者（パフォーマンス分析時）、CI/CDシステム（ビルドメトリクス収集時）

## 帳票種別

診断レポート（JSONファイル）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `next build`（デバッグモードまたはNEXT_SSG_FETCH_METRICS=1時） | 静的生成完了後に条件付き生成 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（整形出力、インデント2スペース） |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | fetch-metrics.json |
| 出力方法 | ファイルシステムへの書き込み |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

ページパスをキーとし、各パスに対応するfetchメトリクスの配列を値とするJSONオブジェクト。

```json
{
  "/page1": [
    {
      "url": "https://api.example.com/data",
      "idx": 0,
      "end": 1706000100,
      "start": 1706000000,
      "method": "GET",
      "status": 200,
      "cacheReason": "",
      "cacheStatus": "miss"
    }
  ],
  "/page2": [...]
}
```

### ヘッダー部

N/A（トップレベルはページパスをキーとするオブジェクト）

### 明細部（FetchMetric型の各項目）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | url | fetchリクエストのURL | FetchMetric.url | 文字列 |
| 2 | idx | fetchリクエストのインデックス（順序番号） | FetchMetric.idx | 整数 |
| 3 | end | fetchリクエスト完了時刻 | FetchMetric.end | 数値（ミリ秒タイムスタンプ） |
| 4 | start | fetchリクエスト開始時刻 | FetchMetric.start | 数値（ミリ秒タイムスタンプ） |
| 5 | method | HTTPメソッド | FetchMetric.method | 文字列（GET, POST等） |
| 6 | status | HTTPレスポンスステータスコード | FetchMetric.status | 整数 |
| 7 | cacheReason | キャッシュ判定理由 | FetchMetric.cacheReason | 文字列 |
| 8 | cacheStatus | キャッシュヒット状態 | FetchMetric.cacheStatus | 'hit' / 'miss' / 'skip' / 'hmr' |
| 9 | cacheWarning | キャッシュ警告（オプショナル） | FetchMetric.cacheWarning | 文字列 |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| プロダクションビルド | `next build` コマンドが実行されていること | Yes |
| デバッグ出力有効 | `debugOutput` が true、または `NEXT_SSG_FETCH_METRICS=1` 環境変数が設定されていること | Yes |
| fetchメトリクス存在 | 静的生成時にfetchリクエストが発生していること | Yes |

### ソート順

N/A（ページパスの自然順序）

### 改ページ条件

N/A

## データベース参照仕様

N/A（データベースを使用しない。エクスポート結果オブジェクトからデータを取得する）

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| fetchMetricsByPath | exportResult.byPathの各エントリからfetchMetricsを抽出し、パスをキーとしたRecord型に変換 | N/A | fetchMetricsがundefinedのパスは除外 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[静的生成フェーズ完了] --> B{debugOutput or NEXT_SSG_FETCH_METRICS=1?}
    B -->|Yes| C[recordFetchMetrics呼び出し]
    B -->|No| D[スキップ]
    C --> E[getDiagnosticsDir でディレクトリ作成]
    E --> F[exportResult.byPathからfetchMetrics抽出]
    F --> G[パスごとにfetchMetricsをマッピング]
    G --> H[JSON.stringify null,2 で整形]
    H --> I[diagnostics/fetch-metrics.jsonに書き込み]
    I --> J[終了]
    D --> J
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 書き込み失敗 | diagnosticsディレクトリへの書き込み権限なし | ファイルシステムエラー | distDirのパーミッション確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ページ数 x 各ページのfetchリクエスト数（数十件〜数万件） |
| 目標出力時間 | 秒オーダー（大量のメトリクス時） |
| 同時出力数上限 | 1（ビルドプロセスにつき1回） |

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

- fetchリクエストのURL一覧が含まれるため、内部APIエンドポイントやクエリパラメータ（APIキー等）が露出する可能性がある
- デバッグ目的のファイルであるため、本番デプロイ時には含めないことを推奨

## 備考

- 出力先: `.next/diagnostics/fetch-metrics.json`
- 条件付き生成：`debugOutput || process.env.NEXT_SSG_FETCH_METRICS === '1'` の場合のみ
- FetchMetric型は `packages/next/src/server/base-http/index.ts` L14-24で定義
- FetchMetrics型はFetchMetricの配列型（`Array<FetchMetric>`）
- JSON.stringify(fetchMetricsByPath, null, 2) で整形出力

---

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

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

### 推奨読解順序

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

FetchMetric型の定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/next/src/server/base-http/index.ts` | L14-24: `FetchMetric` 型定義。url, idx, end, start, method, status, cacheReason, cacheStatus, cacheWarningの9フィールド |
| 1-2 | index.ts | `packages/next/src/server/base-http/index.ts` | L26: `FetchMetrics` 型定義。`Array<FetchMetric>` |

**読解のコツ**: `cacheStatus` は `'hit' | 'miss' | 'skip' | 'hmr'` のユニオン型。'hmr' はHot Module Replacement時のfetchを示す。

#### Step 2: 生成処理を理解する

recordFetchMetrics関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | build-diagnostics.ts | `packages/next/src/diagnostics/build-diagnostics.ts` | L9: `FETCH_METRICS_FILE = 'fetch-metrics.json'` 定数定義 |
| 2-2 | build-diagnostics.ts | `packages/next/src/diagnostics/build-diagnostics.ts` | L72-86: `recordFetchMetrics` 関数。ExportAppResultからfetchMetricsを抽出し、パスごとにマッピングして書き込み |

**主要処理フロー**:
1. **L75**: `getDiagnosticsDir()` - diagnosticsディレクトリのパス取得・作成
2. **L76**: diagnosticsFileパス生成
3. **L77**: `fetchMetricsByPath` 空オブジェクト初期化
4. **L79-83**: `exportResult.byPath` をイテレートし、fetchMetricsが存在するパスのみマッピング
5. **L85**: `writeFile(diagnosticsFile, JSON.stringify(fetchMetricsByPath, null, 2))` - 整形出力で書き込み

#### Step 3: 呼び出し箇所を理解する

ビルドメインフローからの呼び出しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/next/src/build/index.ts` | L188: `recordFetchMetrics` インポート |
| 3-2 | index.ts | `packages/next/src/build/index.ts` | L3164-3166: `if (debugOutput || process.env.NEXT_SSG_FETCH_METRICS === '1') { recordFetchMetrics(exportResult) }` 条件付き呼び出し |

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

```
next build (CLI)
    |
    +-- build/index.ts (メインビルドフロー)
           |
           +-- 静的生成フェーズ (exportApp)
           |      |
           |      +-- exportResult (fetchMetrics含む)
           |
           +-- if (debugOutput || NEXT_SSG_FETCH_METRICS=1)
                  |
                  +-- recordFetchMetrics(exportResult)
                         |
                         +-- getDiagnosticsDir()
                         +-- exportResult.byPath イテレーション
                         +-- fetchMetricsByPath マッピング構築
                         +-- writeFile(fetch-metrics.json)
```

### データフロー図

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

静的生成フェーズ
  exportResult.byPath --------->  diagnostics/build-diagnostics.ts
    Map<path, {                   recordFetchMetrics()
      fetchMetrics?:              (1) byPathイテレーション
        FetchMetric[]             (2) fetchMetrics抽出      -------->  .next/diagnostics/
    }>                            (3) パスごとマッピング                  fetch-metrics.json
                                  (4) JSON.stringify(null,2)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| build-diagnostics.ts | `packages/next/src/diagnostics/build-diagnostics.ts` | ソース | recordFetchMetrics関数定義（L72-86） |
| index.ts | `packages/next/src/server/base-http/index.ts` | ソース | FetchMetric/FetchMetrics型定義（L14-26） |
| index.ts | `packages/next/src/build/index.ts` | ソース | recordFetchMetricsの呼び出し元（L3164-3166） |
