# 画面設計書 3-エラー画面

## 概要

本ドキュメントは、OpenCodeデスクトップアプリケーションのエラー画面の設計仕様を定義する。エラー画面はアプリケーションで予期しないエラーが発生した際に表示されるフォールバック画面である。

### 本画面の処理概要

エラー画面は、アプリケーション実行中に発生した予期しないエラーをユーザーに通知し、復旧オプションを提供するための専用インターフェースである。ErrorBoundaryのフォールバックとして機能し、エラーの詳細表示、アプリ再起動、アップデート確認機能を提供する。

**業務上の目的・背景**：アプリケーションでクラッシュや重大なエラーが発生した場合、ユーザーが状況を理解し、適切な対処を行えるようにする必要がある。この画面は、エラー情報の可視化と復旧手段の提供により、ユーザー体験の低下を最小限に抑える役割を担う。

**画面へのアクセス方法**：ErrorBoundaryがエラーをキャッチした際に自動的に表示される。ユーザーが意図的にアクセスすることはできない。

**主要な操作・処理内容**：
1. エラー詳細情報の表示（エラー名、メッセージ、スタックトレース）
2. エラー情報のクリップボードへのコピー
3. アプリケーションの再起動
4. アップデートの確認とインストール
5. フィードバックリンクへの誘導

**画面遷移**：
- 遷移元：任意の画面（エラー発生時にErrorBoundaryがキャッチ）
- 遷移先：再起動後のホーム画面、外部リンク（Discordフィードバック）

**権限による表示制御**：特になし。ただし、プラットフォーム機能（checkUpdate, restart等）の有無により表示されるボタンが変化する。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 56 | 国際化 | 主機能 | エラーメッセージの多言語表示、翻訳キーによるエラー説明 |

## 画面種別

エラー表示

## URL/ルーティング

N/A（ErrorBoundaryのフォールバックとして表示されるため、特定のURLは持たない）

## 入出力項目

| 項目名 | 入力/出力 | 型 | 必須 | 説明 |
|--------|----------|------|------|------|
| error | 入力 | unknown | ○ | ErrorBoundaryがキャッチしたエラーオブジェクト |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|------|------|
| OpenCodeロゴ | 画像 | アプリケーションロゴ（薄い透過表示） |
| エラータイトル | テキスト | "問題が発生しました"などのタイトル |
| エラー説明 | テキスト | エラーについての説明文 |
| エラー詳細テキストフィールド | テキストエリア | エラーの詳細情報（コピー可能） |
| 再起動ボタン | ボタン | アプリケーションを再起動 |
| アップデート確認ボタン | ボタン | 更新の確認を実行 |
| アップデートインストールボタン | ボタン | 利用可能な更新をインストール（条件付き表示） |
| フィードバックリンク | リンク | Discord経由でフィードバックを送信 |
| バージョン情報 | テキスト | 現在のアプリバージョン |
| アクションエラーメッセージ | テキスト | 操作失敗時のエラーメッセージ |

## イベント仕様

### 1-再起動

ユーザーが「再起動」ボタンをクリックした際の処理。

処理フロー：
1. `platform.restart()` を呼び出し
2. アプリケーションが再起動される

### 2-アップデート確認

ユーザーが「アップデートを確認」ボタンをクリックした際の処理。

処理フロー：
1. `setStore("checking", true)` でローディング状態に
2. `platform.checkUpdate()` を呼び出し
3. 更新が利用可能な場合、`store.version` に新バージョンを設定
4. エラー発生時は `store.actionError` にエラーメッセージを設定
5. `setStore("checking", false)` でローディング解除

### 3-アップデートインストール

ユーザーが「v{version}にアップデート」ボタンをクリックした際の処理。

処理フロー：
1. `platform.update()` でアップデートをダウンロード・インストール
2. `platform.restart()` でアプリを再起動
3. エラー発生時は `store.actionError` にエラーメッセージを設定

### 4-エラー詳細コピー

TextFieldのコピー機能を使用してエラー詳細をクリップボードにコピー。

処理フロー：
1. TextFieldの `copyable` プロパティによりコピーボタンが表示
2. クリックでエラー詳細全文がクリップボードにコピーされる

### 5-フィードバック送信

Discordリンクをクリックしてフィードバックを送信。

処理フロー：
1. `platform.openLink("https://opencode.ai/desktop-feedback")` で外部ブラウザを開く

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | この画面ではデータベース更新は行わない |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| error.page.title | エラー | 問題が発生しました | 常時 |
| error.page.description | 情報 | 予期しないエラーが発生しました | 常時 |
| error.page.details.label | ラベル | エラー詳細 | 常時 |
| error.page.action.restart | アクション | 再起動 | 常時 |
| error.page.action.checkUpdates | アクション | アップデートを確認 | platform.checkUpdate存在時 |
| error.page.action.checking | 情報 | 確認中... | アップデート確認中 |
| error.page.action.updateTo | アクション | v{version}にアップデート | 更新利用可能時 |
| error.page.report.prefix | 情報 | 問題を報告する | 常時 |
| error.page.report.discord | リンク | Discord | 常時 |
| error.page.version | 情報 | バージョン: {version} | platform.version存在時 |
| error.chain.causedBy | 情報 | 原因: | エラーチェーン表示時 |
| error.chain.mcpFailed | エラー | MCPサーバー '{name}' の接続に失敗しました | MCPエラー時 |
| error.chain.providerAuthFailed | エラー | プロバイダー '{provider}' の認証に失敗しました: {message} | プロバイダー認証エラー時 |
| error.chain.apiError | エラー | APIエラーが発生しました | APIエラー時 |
| error.chain.modelNotFound | エラー | モデル '{model}' がプロバイダー '{provider}' で見つかりません | モデル未検出時 |
| error.chain.checkConfig | 情報 | 設定を確認してください | 設定エラー時 |
| error.chain.providerInitFailed | エラー | プロバイダー '{provider}' の初期化に失敗しました | プロバイダー初期化エラー時 |
| error.chain.configJsonInvalid | エラー | 設定ファイル '{path}' が無効です | JSON設定エラー時 |
| error.chain.configDirectoryTypo | エラー | ディレクトリ '{dir}' が見つかりません。'{suggestion}' ですか？ | ディレクトリTypoエラー時 |
| error.chain.configFrontmatterError | エラー | フロントマターエラー: {message} | フロントマターエラー時 |
| error.chain.configInvalid | エラー | 設定が無効です | 設定検証エラー時 |
| error.chain.unknown | エラー | 不明なエラーが発生しました | 不明エラー時 |

## 例外処理

| 状況 | 処理内容 |
|------|---------|
| アップデート確認失敗 | actionErrorにエラーメッセージを設定して表示 |
| アップデートインストール失敗 | actionErrorにエラーメッセージを設定して表示 |
| 再起動失敗 | プラットフォーム依存のエラーハンドリング |

## 備考

- エラーはチェーン形式で表示され、cause（原因）がある場合は再帰的に展開される
- 特定のエラータイプ（InitError）には専用のフォーマット関数がある
- エラー詳細は読み取り専用のテキストフィールドとして表示され、最大高さ384pxに制限
- プラットフォーム機能（checkUpdate, update, restart）はオプションであり、存在しない場合は該当ボタンが非表示
- エラーオブジェクトのJSON変換時、BigIntやCircular参照に対応

---

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

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

### 推奨読解順序

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

エラー型とInitError型の構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | error.tsx | `packages/app/src/pages/error.tsx` | InitError型の定義（10-13行目） |

**読解のコツ**: InitErrorは`name`と`data`プロパティを持つ特殊なエラー形式。

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

エラー画面のメインコンポーネントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | error.tsx | `packages/app/src/pages/error.tsx` | ErrorPageコンポーネント（218-317行目） |

**主要処理フロー**:
1. **219-220行目**: プラットフォームと言語コンテキストの取得
2. **221-225行目**: ローカルストアの初期化（checking, version, actionError）
3. **227-242行目**: `checkForUpdates`関数 - アップデート確認処理
4. **244-253行目**: `installUpdate`関数 - アップデートインストール処理
5. **255-317行目**: JSXレンダリング

#### Step 3: エラーフォーマット処理を理解する

エラーの整形・表示処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | error.tsx | `packages/app/src/pages/error.tsx` | formatInitError関数（55-143行目） |
| 3-2 | error.tsx | `packages/app/src/pages/error.tsx` | formatErrorChain関数（145-208行目） |
| 3-3 | error.tsx | `packages/app/src/pages/error.tsx` | formatError関数（210-212行目） |

**主要処理フロー**:
- **formatInitError**: InitError型のエラーを人間が読める形式に変換
- **formatErrorChain**: エラーチェーン（cause）を再帰的に展開
- **safeJson**: BigIntやCircular参照を安全にJSON化

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

```
ErrorPage (error.tsx)
    │
    ├─ usePlatform() ───────────> PlatformContext
    │      ├─ platform.restart() (再起動)
    │      ├─ platform.checkUpdate() (アップデート確認)
    │      ├─ platform.update() (アップデートインストール)
    │      ├─ platform.openLink() (外部リンク)
    │      └─ platform.version (バージョン情報)
    │
    ├─ useLanguage() ───────────> LanguageContext
    │      └─ language.t() (翻訳)
    │
    ├─ formatError() ───────────> エラーフォーマット
    │      └─ formatErrorChain()
    │             ├─ formatInitError() (InitError用)
    │             └─ 再帰呼び出し (causeチェーン)
    │
    └─ TextField ───────────────> UIコンポーネント
           └─ copyable (コピー機能)
```

### データフロー図

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

ErrorBoundary              props.error                     エラー画面表示
(エラーキャッチ) ─────────▶ ErrorPage ────────────────────▶ formatError()
                                │                              │
                                │                              ▼
                                │                          TextField
                                │                          (エラー詳細)
                                │
                                ├─▶ checkForUpdates() ───▶ store.version
                                │
                                ├─▶ installUpdate() ─────▶ platform.restart()
                                │
                                └─▶ platform.restart() ──▶ アプリ再起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| error.tsx | `packages/app/src/pages/error.tsx` | ソース | エラー画面コンポーネント |
| platform.tsx | `packages/app/src/context/platform.tsx` | ソース | プラットフォーム機能コンテキスト |
| language.tsx | `packages/app/src/context/language.tsx` | ソース | 国際化コンテキスト |
| text-field.tsx | `packages/ui/src/text-field.tsx` | ソース | テキストフィールドコンポーネント |
| button.tsx | `packages/ui/src/button.tsx` | ソース | ボタンコンポーネント |
| logo.tsx | `packages/ui/src/logo.tsx` | ソース | ロゴコンポーネント |
| icon.tsx | `packages/ui/src/icon.tsx` | ソース | アイコンコンポーネント |
