# 通知設計書 35-Terminal connection lost

## 概要

本ドキュメントは、OpenCodeアプリケーションにおける「Terminal connection lost（ターミナル接続切断）」トースト通知の設計仕様を定義する。

### 本通知の処理概要

ターミナルのWebSocket接続が異常終了した際に、ユーザーに対して接続状態の問題を通知するトースト表示を行う機能である。

**業務上の目的・背景**：OpenCodeはターミナル機能を提供しており、ユーザーはアプリ内でコマンドを実行できる。このターミナルはWebSocket接続を通じてバックエンドのPTY（疑似端末）と通信している。サーバーの再起動、ネットワーク障害、タイムアウトなどにより接続が予期せず切断された場合、ユーザーはターミナルが使用できなくなるため、その状態を明確に通知する必要がある。この通知により、ユーザーは接続の問題を認識し、ターミナルの再接続やページのリロードなど適切な対処を行うことができる。

**通知の送信タイミング**：WebSocket接続が異常終了した時点（closeイベントでcode !== 1000の場合、またはerrorイベント発生時、またはrun()関数がエラーをスローした場合）で通知が発生する。正常終了（code 1000）の場合は通知されない。

**通知の受信者**：ターミナルを使用しているユーザー本人のみが受信する。アプリ内のトースト通知であり、外部への送信は行わない。

**通知内容の概要**：タイトルとして「Connection Lost」（日本語：「接続が失われました」）が表示され、説明文としてエラーメッセージ（Errorオブジェクトのmessage）または「The terminal connection was interrupted. This can happen when the server restarts.」（日本語：「ターミナル接続が中断されました。これはサーバーの再起動時に発生する場合があります。」）が表示される。

**期待されるアクション**：ユーザーは接続の問題を認識し、必要に応じてターミナルの再接続を試みるか、ページをリロードする。サーバー再起動が原因の場合は、サーバーの準備が完了するまで待機する。

## 通知種別

トースト通知（アプリ内通知）- エラーバリアント

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（UIスレッド上で即時表示） |
| 優先度 | 高 |
| リトライ | 無し（UIトーストのため） |

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

ターミナルコンポーネントを表示しているユーザーのブラウザ/デスクトップアプリ画面に表示される。特別な送信先決定ロジックは不要。

## 通知テンプレート

### トースト通知の場合

| 項目 | 内容 |
|-----|------|
| バリアント | **error** |
| アイコン | なし |
| 持続性 | 非持続（自動消去） |

### 本文テンプレート

```
タイトル: Connection Lost
説明: {エラーメッセージ} または "The terminal connection was interrupted. This can happen when the server restarts."
```

日本語の場合:
```
タイトル: 接続が失われました
説明: {エラーメッセージ} または "ターミナル接続が中断されました。これはサーバーの再起動時に発生する場合があります。"
```

### 添付ファイル

なし（トースト通知のため添付ファイルは非対応）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | i18n: `terminal.connectionLost.title` | Yes |
| description | エラー詳細 | Error.message または i18n: `terminal.connectionLost.description` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| WebSocketイベント | closeイベント（code !== 1000） | 異常終了時 | 正常終了（code 1000）以外のclose時にエラーハンドラが呼ばれる |
| WebSocketイベント | errorイベント | エラー発生時 | WebSocketエラー発生時にエラーハンドラが呼ばれる |
| 非同期処理 | run()関数のcatch | 接続処理失敗時 | 接続確立中のエラーをキャッチ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| disposed === true | コンポーネントがアンマウント済みの場合は通知しない |
| once.value === true | 同一接続で既にエラーが報告されている場合は重複通知しない |
| closing === true | 正常な切断処理中の場合は通知しない |
| close code === 1000 | 正常終了の場合は通知しない（PTYプロセスの正常終了） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[WebSocket接続確立] --> B[通信中]
    B --> C{接続終了イベント}
    C -->|close code === 1000| D[正常終了・通知なし]
    C -->|close code !== 1000| E{disposed?}
    C -->|error| E
    E -->|Yes| F[処理中断・通知なし]
    E -->|No| G{closing?}
    G -->|Yes| F
    G -->|No| H{once.value?}
    H -->|Yes| F
    H -->|No| I[once.value = true]
    I --> J[showToast - エラー通知表示]
    J --> K[onConnectError コールバック呼び出し]
    K --> L[終了]
    D --> L
    F --> L
```

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

### 参照テーブル一覧

本通知はフロントエンド側のUI通知であり、直接的なデータベース参照は行わない。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | - | WebSocket接続状態の監視のため |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| N/A | - | 通知表示自体はデータベース更新を伴わない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ネットワーク障害 | インターネット接続の問題 | エラーメッセージを表示、再接続を促す |
| サーバー再起動 | バックエンドサーバーの再起動 | 説明文でサーバー再起動の可能性を通知 |
| WebSocket異常終了 | code !== 1000のclose | closeコードをエラーメッセージに含める |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回（自動リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | once.valueによる重複抑止 |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（WebSocketイベントに応じて即時表示）

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

- WebSocketのエラーコードや接続URL情報が含まれる可能性があるが、ユーザー本人のセッション情報のため問題なし
- サーバー内部の詳細なエラー情報は表示しない

## 備考

- `variant: "error"` が設定されており、通常のトーストとは異なるエラースタイルで表示される
- `once.value` フラグにより、同一接続での重複通知が防止される
- PTYプロセスの正常終了（code 1000）は通知対象外

---

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

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

### 推奨読解順序

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

ターミナルコンポーネントのpropsとトースト通知のバリアントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | terminal.tsx | `packages/app/src/components/terminal.tsx` | TerminalProps インターフェース（18-24行目）の `onConnectError` コールバック |
| 1-2 | toast.tsx | `packages/ui/src/components/toast.tsx` | ToastVariant 型（101行目）の "error" バリアント |
| 1-3 | en.ts | `packages/app/src/i18n/en.ts` | 559-561行目の `terminal.connectionLost.*` キーを確認 |

**読解のコツ**: `variant: "error"` を指定するとトーストがエラースタイルで表示される。

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

ターミナルコンポーネントのWebSocket接続処理を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | terminal.tsx | `packages/app/src/components/terminal.tsx` | onMount内のrun()関数（450-526行目） |

**主要処理フロー**:
1. **450-456行目**: WebSocket URL構築と接続
2. **495-503行目**: handleError - WebSocketエラーハンドリング
3. **505-516行目**: handleClose - 異常終了時のエラーハンドリング（code !== 1000）
4. **528-536行目**: **run().catch() - 接続エラー時のshowToast呼び出し（本通知の発生箇所）**

#### Step 3: 重複通知防止ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | terminal.tsx | `packages/app/src/components/terminal.tsx` | once変数とdisposed変数の使用箇所 |

**主要処理フロー**:
- once.valueフラグで同一接続での重複通知を防止
- disposedフラグでコンポーネントアンマウント後の通知を防止
- closingフラグで正常切断処理中の通知を防止

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

```
terminal.tsx::Terminal コンポーネント
    │
    ├─ onMount()
    │      │
    │      └─ run() - WebSocket接続処理
    │             │
    │             ├─ WebSocket.addEventListener("error", handleError)
    │             │      └─ [once.value = false] → onConnectError()
    │             │
    │             ├─ WebSocket.addEventListener("close", handleClose)
    │             │      └─ [code !== 1000 && once.value = false] → onConnectError()
    │             │
    │             └─ catch(err)
    │                    └─ [disposed = false] → showToast({ variant: "error" })
    │                                                  └─ onConnectError()
```

### データフロー図

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

WebSocket           terminal.tsx コンポーネント          エラートースト通知
異常終了 ─────────▶    run().catch() ──────────────▶   「Connection Lost」表示
    │                       │                              (variant: error)
    │                       ▼
    │               showToast({
    │                 variant: "error",
    │                 title: "...",
    │                 description: err.message || "..."
    │               })
    │
    └─ close/error  handleError/handleClose
       イベント ───▶  onConnectError() コールバック
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| terminal.tsx | `packages/app/src/components/terminal.tsx` | ソース | ターミナルコンポーネントとWebSocket接続処理 |
| toast.tsx | `packages/ui/src/components/toast.tsx` | ソース | showToast関数とToastVariant |
| en.ts | `packages/app/src/i18n/en.ts` | 設定 | 英語の国際化メッセージ定義 |
| ja.ts | `packages/app/src/i18n/ja.ts` | 設定 | 日本語の国際化メッセージ定義 |
