# 通知設計書 48-Failed to reload project

## 概要

本ドキュメントは、OpenCodeアプリケーションにおける「Failed to reload project」トースト通知の設計を記載する。プロジェクトのブートストラップ（初期化/再読み込み）処理が失敗した際に表示されるエラー通知である。

### 本通知の処理概要

プロジェクト固有の初期化処理（`bootstrapDirectory`）が失敗した際にユーザーにエラーを通知し、プロジェクトの状態を部分的にロードした状態として扱う処理を行う。

**業務上の目的・背景**：OpenCodeでは、各プロジェクト（ディレクトリ）ごとに初期化処理が必要であり、プロバイダー情報、エージェント設定、設定ファイルなどを取得する。これらの処理が失敗した場合、プロジェクトの機能が制限される可能性がある。この通知により、ユーザーは初期化の問題を認識し、設定の確認やサーバー状態の確認を行うことができる。

**通知の送信タイミング**：プロジェクトのブートストラップ処理（`bootstrapDirectory`内のblockingRequests）でエラーが発生した場合に表示される。

**通知の受信者**：プロジェクトを開いているユーザー自身。アプリケーションのアクティブウィンドウにトースト通知が表示される。

**通知内容の概要**：タイトル「Failed to reload {project}」と、エラーの詳細メッセージが表示される。

**期待されるアクション**：ユーザーは通知を確認後、以下のアクションを検討する。
1. サーバーの状態を確認する
2. プロジェクトの設定ファイル（opencode.json等）を確認する
3. ページをリロードして再試行する

## 通知種別

トースト通知（アプリ内通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ブートストラップ失敗時に即時表示） |
| 優先度 | 高 |
| リトライ | 無（通知表示自体のリトライは不要） |

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

プロジェクトを開いているユーザー自身のブラウザ/デスクトップアプリ画面に表示される。送信先の判定は不要（ローカル通知のため）。

## 通知テンプレート

### トースト通知

| 項目 | 内容 |
|-----|------|
| アイコン | なし（デフォルト） |
| タイトル | "Failed to reload {project}" |
| 説明 | エラーメッセージ |
| バリアント | デフォルト |

### 本文テンプレート

```
タイトル: Failed to reload {project}
説明: {errorMessage}
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| project | プロジェクト名（ディレクトリ名） | `getFilename(input.directory)` | Yes |
| errorMessage | エラーの詳細メッセージ | Error.messageまたはString変換 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プロジェクト操作 | bootstrapDirectory実行 | blockingRequestsのいずれかが失敗 | プロジェクト初期化失敗時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 初期化成功 | すべてのblockingRequestsが成功した場合は通知しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[プロジェクト選択/初期化] --> B[bootstrapDirectory実行]
    B --> C[blockingRequests並列実行]
    C --> D{すべて成功?}
    D -->|Yes| E[status = partial → complete]
    D -->|No| F[showToast - エラー通知]
    F --> G[status = partial]
    E --> H[追加の初期化処理]
    G --> I[終了]
    H --> I
```

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

### 参照テーブル一覧

本通知はクライアントサイドで完結するため、データベースへの直接参照は行わない。

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| store.status | UPDATE | "partial"に設定（エラー時） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| プロジェクト取得失敗 | project.current API失敗 | エラー通知を表示、status=partial |
| プロバイダー取得失敗 | provider.list API失敗 | エラー通知を表示、status=partial |
| エージェント取得失敗 | app.agents API失敗 | エラー通知を表示、status=partial |
| 設定取得失敗 | config.get API失敗 | エラー通知を表示、status=partial |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 各APIに対してretryユーティリティで複数回 |
| リトライ間隔 | retryユーティリティのデフォルト |
| リトライ対象エラー | すべてのAPIエラー |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（エラー発生時に即時表示）

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

- エラーメッセージにはサーバーからの詳細なスタックトレースは含まれない
- プロジェクトのディレクトリ名のみが通知に含まれる

## 備考

- `retry`ユーティリティによる自動リトライ後に最終的に失敗した場合のみ通知が表示される
- エラー後もアプリケーションは動作を継続し、一部機能が制限された状態（partial）となる
- i18nキーは使用されず、動的にタイトルが構築される（ハードコードされたテンプレート）

---

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

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

### 推奨読解順序

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

ブートストラップの入力パラメータと状態管理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bootstrap.ts | `packages/app/src/context/global-sync/bootstrap.ts` | `bootstrapDirectory`関数の引数構造 |
| 1-2 | types.ts | `packages/app/src/context/global-sync/types.ts`（推定） | State型の`status`フィールド |

**読解のコツ**: `status`が`loading` → `partial` → `complete`と遷移することを理解する。

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

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bootstrap.ts | `packages/app/src/context/global-sync/bootstrap.ts` | L111-199の`bootstrapDirectory`関数 |

**主要処理フロー**:
1. **L119**: status = "loading"に設定
2. **L121-129**: blockingRequestsの定義（project, provider, agent, config）
3. **L131-140**: Promise.all + retryで並列実行、catchでエラー処理

#### Step 3: エラー通知処理を理解する

showToast呼び出しの詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | bootstrap.ts | `packages/app/src/context/global-sync/bootstrap.ts` | L133-139のcatch句 |

**主要処理フロー**:
- **L134**: console.errorでログ出力
- **L135**: プロジェクト名を取得（getFilename）
- **L136**: エラーメッセージを抽出
- **L137**: showToastで通知表示
- **L138**: status = "partial"に設定

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

```
global-sync.tsx bootstrapInstance
    │
    └─ bootstrapDirectory (bootstrap.ts L111)
           │
           ├─ setStore("status", "loading") (L119)
           │
           ├─ blockingRequests定義 (L121-129)
           │      ├─ project.current
           │      ├─ provider.list
           │      ├─ app.agents
           │      └─ config.get
           │
           └─ Promise.all + retry (L131-140)
                  │
                  └─ catch (L133-140)
                         ├─ console.error
                         ├─ getFilename(directory) → project名
                         ├─ err.message → エラーメッセージ
                         ├─ showToast({ title, description })
                         └─ setStore("status", "partial")
```

### データフロー図

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

プロジェクト選択 ───▶ bootstrapDirectory ───▶ トースト通知表示
                          │                    │
                          ▼                    ├─ "Failed to reload {project}"
                 blockingRequests              └─ エラーメッセージ
                          │
                          ▼
                   [失敗時] catch
                          │
                          ▼
                    status = "partial"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bootstrap.ts | `packages/app/src/context/global-sync/bootstrap.ts` | ソース | bootstrapDirectory関数（L111-199） |
| global-sync.tsx | `packages/app/src/context/global-sync.tsx` | ソース | bootstrapInstanceからの呼び出し元 |
| types.ts | `packages/app/src/context/global-sync/types.ts` | ソース | State型定義（推定） |
| path.ts | `packages/util/src/path.ts`（推定） | ソース | getFilename関数 |
