# 通知設計書 43-Go to session

## 概要

本ドキュメントは、OpenCodeアプリケーションにおける「Go to session」トースト通知アクションの設計を記載する。これは独立した通知ではなく、パーミッション要求や質問発生時のトースト通知に付与されるアクションボタンである。

### 本通知の処理概要

パーミッション要求（permission.asked）や質問発生（question.asked）時に表示されるトースト通知に「Go to session」アクションボタンを追加し、ユーザーが該当セッションに即座に移動できる機能を提供する。

**業務上の目的・背景**：OpenCodeでは、AIエージェントがファイル編集やコマンド実行などの権限を必要とする場合にパーミッション要求が発生し、ユーザーへの確認が必要な場合に質問が発生する。ユーザーは複数のプロジェクトやセッションを同時に使用している可能性があり、別のセッションで発生したこれらのイベントに迅速に対応できる必要がある。「Go to session」アクションにより、通知からワンクリックで該当セッションに移動し、即座に対応できる。

**通知の送信タイミング**：SDKイベント（`permission.asked`または`question.asked`）が発生し、かつ現在のセッションが該当セッションでない場合に、アクション付きのトースト通知が表示される。

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

**通知内容の概要**：パーミッション要求または質問のタイトル、説明、そして「Go to session」と「Dismiss」の2つのアクションボタンが表示される。

**期待されるアクション**：ユーザーは「Go to session」ボタンをクリックして該当セッションに移動し、パーミッションの許可/拒否または質問への回答を行う。または「Dismiss」で通知を閉じる。

## 通知種別

トースト通知のアクションボタン（パーミッション/質問通知の一部）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（SDKイベント受信時に即時表示） |
| 優先度 | 高 |
| リトライ | 無 |
| 持続性 | persistent（自動消去なし） |

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

- SDKイベントのdirectory（プロジェクトディレクトリ）とsessionIDを基に、セッションへのナビゲーションURLを構築する
- 現在表示中のセッションが該当セッションの場合はトースト通知を表示しない
- 子セッション（parentIDが現在のセッション）の場合もトースト通知を表示しない

## 通知テンプレート

### トースト通知（パーミッション要求時）

| 項目 | 内容 |
|-----|------|
| アイコン | checklist |
| タイトル | `notification.permission.title`（"Permission required"） |
| 説明 | `notification.permission.description`（"{{sessionTitle}} in {{projectName}} needs permission"） |
| 持続性 | persistent |

### トースト通知（質問発生時）

| 項目 | 内容 |
|-----|------|
| アイコン | bubble-5 |
| タイトル | `notification.question.title`（"Question"） |
| 説明 | `notification.question.description`（"{{sessionTitle}} in {{projectName}} has a question"） |
| 持続性 | persistent |

### アクションボタン

| アクション | ラベル | 動作 |
|----------|-------|------|
| Go to session | `notification.action.goToSession` | 該当セッションへナビゲート |
| Dismiss | `common.dismiss` | 通知を閉じる |

### 本文テンプレート

```
パーミッション要求時:
タイトル: Permission required
説明: {sessionTitle} in {projectName} needs permission
アクション: [Go to session] [Dismiss]

質問発生時:
タイトル: Question
説明: {sessionTitle} in {projectName} has a question
アクション: [Go to session] [Dismiss]
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| sessionTitle | セッションのタイトル | session.title または "New session" | Yes |
| projectName | プロジェクト名 | `getFilename(directory)` | Yes |
| directory | プロジェクトディレクトリパス | SDKイベントの`e.name` | Yes |
| sessionID | セッションID | SDKイベントの`props.sessionID` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| SDKイベント | permission.asked | 現在のセッションでない場合 | パーミッション要求時 |
| SDKイベント | question.asked | 現在のセッションでない場合 | 質問発生時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 現在のセッションで発生 | 該当セッションを表示中の場合は通知を表示しない |
| 子セッションで発生 | parentIDが現在のセッションの場合は通知を表示しない |
| 自動応答有効 | permission.askedでautoResponds設定がtrueの場合は通知を表示しない |
| クールダウン期間中 | 同一セッションで5秒以内に再度イベントが発生した場合は抑止 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[SDKイベント受信] --> B{permission.asked または question.asked?}
    B -->|No| C[終了]
    B -->|Yes| D{現在のセッション?}
    D -->|Yes| C
    D -->|No| E{子セッション?}
    E -->|Yes| C
    E -->|No| F{自動応答対象?}
    F -->|Yes| C
    F -->|No| G{クールダウン期間中?}
    G -->|Yes| C
    G -->|No| H[既存の同一セッション通知を閉じる]
    H --> I[showToast - アクション付き通知表示]
    I --> J[通知IDをMapに保存]
    J --> C
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| session | セッションタイトル取得 | globalSync.child経由でstore.sessionを参照 |

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

#### session

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| title | 通知の説明文に使用 | `s.id === props.sessionID` |
| parentID | 子セッション判定 | `s.parentID === currentSession` |

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| セッション情報取得失敗 | storeにセッションがない | デフォルトタイトル「New session」を使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1セッションあたりクールダウン | 5秒 |
| 1分あたり上限 | 制限なし |

### 配信時間帯

制限なし（イベント発生時に即時表示）

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

- ナビゲーション先のURLはプロジェクトディレクトリとセッションIDからクライアント側で構築
- Base64エンコードされたディレクトリパスを使用

## 備考

- システム通知（OSネイティブ通知）も同時に発生する可能性がある（設定による）
- パーミッション要求時はサウンド再生も行われる可能性がある（設定による）
- 通知は持続的（persistent）であり、ユーザーが明示的に閉じるまで表示され続ける

---

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

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

### 推奨読解順序

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

SDKイベントの構造とセッション情報の管理方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | layout.tsx | `packages/app/src/pages/layout.tsx` | `useSDKNotificationToasts`フック内のイベント構造 |

**読解のコツ**: SDKイベントの`e.details.type`と`e.details.properties`の構造を理解する。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | layout.tsx | `packages/app/src/pages/layout.tsx` | L334-440の`useSDKNotificationToasts`関数 |

**主要処理フロー**:
1. **L336-337**: 通知管理用のMap初期化
2. **L348-426**: SDKイベントリスナーの登録
3. **L361-370**: permission.asked/question.askedの判定
4. **L409-425**: showToastでアクション付き通知を表示

#### Step 3: アクション処理を理解する

「Go to session」アクションの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | layout.tsx | `packages/app/src/pages/layout.tsx` | L414-418のactionsプロパティ |
| 3-2 | en.ts | `packages/app/src/i18n/en.ts` | L479のnotification.action.goToSession定義 |

**主要処理フロー**:
- **L415-417**: 「Go to session」アクション - `navigate(href)`でセッションに移動
- **L418-421**: 「Dismiss」アクション - `"dismiss"`で通知を閉じる

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

```
useSDKNotificationToasts (layout.tsx L334)
    │
    ├─ globalSDK.event.listen (L348)
    │      └─ SDKイベント受信
    │
    ├─ イベント判定 (L361-370)
    │      ├─ permission.asked
    │      └─ question.asked
    │
    ├─ 抑止条件チェック (L369-405)
    │      ├─ autoResponds判定
    │      ├─ 現在セッション判定
    │      └─ クールダウン判定
    │
    └─ showToast (L409-425)
           ├─ title: notification.permission/question.title
           ├─ description: notification.permission/question.description
           └─ actions:
                  ├─ "Go to session" → navigate(href)
                  └─ "Dismiss" → dismiss
```

### データフロー図

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

SDKイベント ───▶ useSDKNotificationToasts ───▶ トースト通知表示
(permission.asked/      │                         │
 question.asked)        │                         └─ アクションボタン
                        ▼                              ├─ Go to session
                 セッション情報取得                     │     → navigate
                 (globalSync.child)                    └─ Dismiss
                                                            → toaster.dismiss
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| layout.tsx | `packages/app/src/pages/layout.tsx` | ソース | useSDKNotificationToastsフックの定義 |
| en.ts | `packages/app/src/i18n/en.ts` | 設定 | 英語メッセージ定義（L475-479） |
| ja.ts | `packages/app/src/i18n/ja.ts` | 設定 | 日本語メッセージ定義 |
| global-sdk.tsx | `packages/app/src/context/global-sdk.tsx` | ソース | SDKイベントリスナー管理 |
