# 通知設計書 25-DevToolsコンフィグ通知

## 概要

本ドキュメントは、Next.js開発サーバーにおけるDevToolsコンフィグ通知の設計を記述する。DevToolsの設定情報（テーマ、インジケーター位置、パネルサイズ等）が変更された際にブラウザクライアントへWebSocket経由で設定情報を送信し、Dev Overlayの表示設定をリアルタイムに同期する仕組みについて定義する。

### 本通知の処理概要

DevToolsの設定がHTTP POSTリクエスト経由で更新された際、およびWebSocket接続確立時のSYNCメッセージの一部として、DevToolsコンフィグ情報をブラウザクライアントへ送信する。

**業務上の目的・背景**：Next.js DevToolsは、テーマ（light/dark/system）、インジケーターの表示位置、パネルサイズ、表示スケールなどの設定をカスタマイズできる。設定変更がリアルタイムに全接続クライアントへ反映されることで、複数ブラウザウィンドウでの一貫した開発体験を提供する。設定はファイルシステム（`{distDir}/cache/next-devtools-config.json`）に永続化される。

**通知の送信タイミング**：(1) `/__nextjs_devtools_config`エンドポイントへのPOSTリクエストで設定が更新された時（`hotReloader.send()`で全クライアントへブロードキャスト）。(2) WebSocket接続確立時のSYNCメッセージの`devToolsConfig`フィールドとして送信。

**通知の受信者**：(1) 設定更新時：全WebSocketクライアント。(2) 接続時：接続した個別クライアント。

**通知内容の概要**：`type: "devtoolsConfig"`と`data: DevToolsConfig`を含むJSONメッセージ。`DevToolsConfig`にはテーマ、インジケーター無効化フラグ、位置情報、パネルサイズ、スケール、ショートカットキー設定が含まれる。

**期待されるアクション**：クライアントの`dispatcher.onDevToolsConfig()`を通じてDev OverlayのUI設定（テーマ、位置、スケール等）を更新する。

## 通知種別

WebSocket（HMR）メッセージ（アプリ内通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（設定変更時にWebSocket push） |
| 優先度 | 低 |
| リトライ | なし（接続時にSYNCメッセージの一部として初期設定が送信される） |

### 送信先決定ロジック

設定更新時は`hotReloader.send()`で全クライアントにブロードキャスト。接続時はSYNCメッセージの一部として個別クライアントへ送信。

## 通知テンプレート

### メール通知の場合

該当なし（WebSocketメッセージのため）

### 本文テンプレート

```json
{
  "type": "devtoolsConfig",
  "data": {
    "theme": "system",
    "disableDevIndicator": false,
    "devToolsPosition": "bottom-left",
    "devToolsPanelPosition": {
      "__nextjs-dev-tools-shared-panel-location": "bottom-left"
    },
    "devToolsPanelSize": {},
    "scale": 1,
    "hideShortcut": null
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージ種別 | 固定値 `"devtoolsConfig"` | Yes |
| data.theme | UIテーマ | `"light"` / `"dark"` / `"system"` | No |
| data.disableDevIndicator | インジケーター無効化フラグ | boolean | No |
| data.devToolsPosition | インジケーター位置 | `"top-left"` / `"top-right"` / `"bottom-left"` / `"bottom-right"` | No |
| data.devToolsPanelPosition | パネル位置マップ | `Record<string, Corners>` | No |
| data.devToolsPanelSize | パネルサイズマップ | `Record<string, { width: number; height: number }>` | No |
| data.scale | 表示スケール | number | No |
| data.hideShortcut | 非表示ショートカットキー | `string \| null` | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| HTTPリクエスト | POST `/__nextjs_devtools_config` | 常に送信（バリデーション成功時） | DevTools設定変更リクエスト |
| サーバーイベント | WebSocket接続確立 | 常に送信 | SYNCメッセージの`devToolsConfig`フィールド |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| POSTリクエストのバリデーション失敗 | `devToolsConfigSchema.safeParse`が失敗した場合は400エラーを返し送信しない |
| HTTPメソッド不正 | POST以外のリクエストは405エラー |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[POST /__nextjs_devtools_config] --> B[リクエストボディ解析]
    B --> C[devToolsConfigSchema.safeParse]
    C -->|成功| D[現在の設定とdeepMerge]
    C -->|失敗| E[400 Bad Request]
    D --> F[設定ファイルに書き込み]
    F --> G[sendUpdateSignal呼び出し]
    G --> H[hotReloader.send DEVTOOLS_CONFIG]
    H --> I[全クライアントへブロードキャスト]
    I --> J[クライアント: dispatcher.onDevToolsConfig]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（ファイルシステムベースの設定管理）

### テーブル別参照項目詳細

#### 設定ファイル

| 参照項目 | 用途 | 取得条件 |
|---------|------|---------|
| `{distDir}/cache/next-devtools-config.json` | 現在のDevTools設定 | ファイル存在時に読み込み |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| `{distDir}/cache/next-devtools-config.json` | 上書き | 新しいマージ済み設定をJSON形式で書き込み |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| JSON解析エラー | POSTボディが不正なJSON | `console.error`出力、400レスポンス返却 |
| バリデーションエラー | 設定値がスキーマに不適合 | `console.error`出力、400レスポンス返却 |
| 設定ファイル読み込みエラー | ファイルが存在しない | 空ファイルを新規作成し、空オブジェクトを返す |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（開発サーバー稼働中は常時送信可能）

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

本通知はローカル開発環境専用。設定値はUI表示に関する情報のみであり、機密情報は含まれない。POSTエンドポイントはZodスキーマによるバリデーションが実施される。

## 備考

- 設定ファイルは`{distDir}/cache/next-devtools-config.json`に永続化される。
- `deepMerge`により既存設定と新しい設定がマージされるため、部分的な設定更新が可能。
- SYNCメッセージ内の`devToolsConfig`フィールドは、接続時の初期設定同期に使用される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | shared.ts | `packages/next/src/next-devtools/dev-overlay/shared.ts` | 11-22行目: `DevToolsConfig`型定義。テーマ、位置、サイズ、スケール等のプロパティを確認 |
| 1-2 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 37行目: `DEVTOOLS_CONFIG = 'devtoolsConfig'`のenum定義。147-150行目: `DevToolsConfigMessage`型 |

#### Step 2: サーバー側ミドルウェアを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | devtools-config-middleware.ts | `packages/next/src/next-devtools/server/devtools-config-middleware.ts` | 15-70行目: `devToolsConfigMiddleware`関数の全体。POSTリクエスト処理、バリデーション、ファイル書き込み、`sendUpdateSignal`呼び出し |
| 2-2 | devtools-config-middleware.ts | `packages/next/src/next-devtools/server/devtools-config-middleware.ts` | 72-84行目: `getDevToolsConfig`関数。ファイルからの設定読み込みと初期化 |

**主要処理フロー**:
1. **29行目**: URLパスの判定（`/__nextjs_devtools_config`）
2. **39行目**: 現在の設定を`getDevToolsConfig`で取得
3. **47-48行目**: POSTボディをJSON解析
4. **54行目**: `devToolsConfigSchema.safeParse`でバリデーション
5. **63行目**: `deepMerge`で既存設定とマージ
6. **64行目**: `writeFile`で設定ファイルに書き込み
7. **66行目**: `sendUpdateSignal(newConfig)`でWebSocket送信をトリガー

#### Step 3: HotReloaderでの送信を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | 776-784行目: `devToolsConfigMiddleware`の登録。`sendUpdateSignal`で`hotReloader.send({ type: DEVTOOLS_CONFIG, data })`を呼び出す構造 |
| 3-2 | hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | 1107-1118行目: SYNCメッセージ内で`devToolsConfig`フィールドを含めて送信 |

#### Step 4: クライアント側受信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 467-469行目: `DEVTOOLS_CONFIG`受信時に`dispatcher.onDevToolsConfig(message.data)`を呼び出し。315-316行目: SYNCメッセージ内の`devToolsConfig`フィールド処理 |
| 4-2 | shared.ts | `packages/next/src/next-devtools/dev-overlay/shared.ts` | 484-509行目: `ACTION_DEVTOOLS_CONFIG`によるreducer処理。各設定値をOverlayStateに反映 |

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

```
[設定更新パス]
POST /__nextjs_devtools_config
    |
    +-- devToolsConfigMiddleware() [devtools-config-middleware.ts:24]
           |
           +-- getDevToolsConfig() [devtools-config-middleware.ts:72]
           +-- safeParse(body)
           +-- deepMerge(currentConfig, validation.data)
           +-- writeFile(configPath, JSON.stringify(newConfig))
           +-- sendUpdateSignal(newConfig) [hot-reloader-turbopack.ts:778]
                  |
                  +-- hotReloader.send({ type: DEVTOOLS_CONFIG, data }) [hot-reloader-turbopack.ts:779]
                         |
                         +-- send(action) [hot-reloader-turbopack.ts:1125]

[接続時同期パス]
onHMR → sendToClient(syncMessage) [hot-reloader-turbopack.ts:1120]
    |
    +-- syncMessage.devToolsConfig [hot-reloader-turbopack.ts:1117]
```

### データフロー図

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

POST リクエスト           ──>  devToolsConfigMiddleware()      ──> WebSocket JSON メッセージ
  { theme: "dark", ... }       バリデーション+マージ                type: "devtoolsConfig"
                               ファイル永続化                      data: { theme: "dark", ... }
                                                                      |
                                                                      v
                                                                 [ブラウザクライアント]
                                                                 dispatcher.onDevToolsConfig()
                                                                 OverlayState更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| shared.ts | `packages/next/src/next-devtools/dev-overlay/shared.ts` | ソース | DevToolsConfig型定義、OverlayState reducer |
| hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | ソース | メッセージ型定義・enum定義 |
| devtools-config-middleware.ts | `packages/next/src/next-devtools/server/devtools-config-middleware.ts` | ソース | 設定更新ミドルウェア |
| hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | ソース | ミドルウェア登録とWebSocket送信 |
| hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | ソース | クライアント側受信処理 |
| devtools-config-schema.ts | `packages/next/src/next-devtools/shared/devtools-config-schema.ts` | ソース | Zodバリデーションスキーマ |
