# 通知設計書 52-Update Downloaded

## 概要

本ドキュメントは、OpenCodeデスクトップアプリケーションにおけるアップデートダウンロード完了時の確認ダイアログ（Update Downloaded）の設計について記載する。

### 本通知の処理概要

本通知は、OpenCodeデスクトップアプリケーション（Tauri製）において、自動アップデートのダウンロードが正常に完了した際にユーザーに対して確認ダイアログを表示し、インストールと再起動の実行可否を問い合わせる機能である。

**業務上の目的・背景**：OpenCodeは継続的なアップデートを提供しており、ダウンロード完了後にユーザーの意思確認を行うことで、作業中断のリスクを軽減し、ユーザー体験を向上させる。インストールにはアプリケーションの再起動が必要となるため、ユーザーが適切なタイミングで更新を適用できるよう、確認ダイアログによる意思決定の機会を提供する。

**通知の送信タイミング**：Tauriのupdaterプラグインを使用したアップデートダウンロード処理（`update.download()`）が正常に完了した直後に、確認ダイアログが表示される。この処理はアップデートチェック後のダウンロード成功時に自動的に発動する。

**通知の受信者**：OpenCodeデスクトップアプリケーションを使用中のユーザー本人。ダイアログはアプリケーションのメインウィンドウに対してモーダルで表示される。

**通知内容の概要**：ダイアログには「Update Downloaded」というタイトル（i18nキー: `desktop.updater.downloaded.title`）と「Version {{version}} of OpenCode has been downloaded, would you like to install it and relaunch?」というメッセージ（i18nキー: `desktop.updater.downloaded.prompt`）が表示される。メッセージには動的にバージョン番号が埋め込まれ、ユーザーに具体的なバージョン情報を提示する。

**期待されるアクション**：ユーザーは「Yes」をクリックしてインストール・再起動を実行するか、「No」をクリックして後で手動更新を行うかを選択する。「Yes」選択時はアプリケーションが自動的に更新を適用し再起動する。

## 通知種別

デスクトップダイアログ（Tauri Dialog API - `ask`関数：Yes/No確認ダイアログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（await） |
| 優先度 | 高 |
| リトライ | なし |

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

- アプリケーションを操作中のユーザーに対して、Tauriのダイアログプラグインを通じてネイティブOSの確認ダイアログとして表示される
- ダウンロード成功後に自動的に表示される（条件分岐なし）

## 通知テンプレート

### デスクトップダイアログの場合

| 項目 | 内容 |
|-----|------|
| ダイアログタイプ | ask（Yes/No確認ダイアログ） |
| タイトル | `desktop.updater.downloaded.title` |
| メッセージ | `desktop.updater.downloaded.prompt` |
| ボタン | Yes / No |

### 本文テンプレート

**英語（en）:**
```
Title: Update Downloaded
Message: Version {{version}} of OpenCode has been downloaded, would you like to install it and relaunch?
```

**日本語（ja）:**
```
Title: アップデートをダウンロードしました
Message: OpenCode のバージョン {{version}} がダウンロードされました。インストールして再起動しますか？
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `{{version}}` | ダウンロードされた新バージョン番号 | `update.version`（Tauri Updaterから取得） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| システムイベント | `update.download()`成功 | ダウンロード例外なし | アップデートのダウンロードが正常に完了した場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ダウンロード失敗 | `update.download()`が例外をスローした場合は別のダイアログ（Update Failed）を表示 |
| アップデートなし | 利用可能なアップデートがない場合はこのダイアログに到達しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[runUpdater関数呼び出し] --> B[i18n初期化]
    B --> C[アップデートチェック check]
    C --> D{アップデート存在?}
    D -->|Yes| E[update.download実行]
    D -->|No| F[No Update Availableダイアログ/終了]
    E --> G{ダウンロード成功?}
    G -->|Yes| H[Update Downloadedダイアログ表示 ask]
    G -->|No| I[Update Failedダイアログ表示]
    H --> J{ユーザー選択}
    J -->|Yes| K[インストール実行 update.install]
    J -->|No| L[処理終了 return]
    K --> M{インストール成功?}
    M -->|Yes| N[サイドカー終了 + アプリ再起動]
    M -->|No| O[Update Failed installダイアログ表示]
    O --> L
    N --> P[アプリ再起動完了]
```

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

### 参照テーブル一覧

該当なし（本機能はデータベースを使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ユーザーがNoを選択 | ユーザーがインストールを拒否 | `return`で処理終了、次回起動時に再度確認 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- バージョン番号のみを動的変数として使用しており、ユーザー入力によるインジェクションリスクはない
- `update.version`はTauriのupdaterプラグインから取得される信頼できる値
- Tauriのセキュアなダイアログプラグインを使用

## 備考

- 本ダイアログはTauri専用機能であり、Web版OpenCodeでは利用不可
- `@tauri-apps/plugin-dialog`の`ask`関数を使用してネイティブOSの確認ダイアログを表示
- ユーザーが「Yes」を選択した場合のみ、インストールと再起動が実行される
- Windows環境では`update.install()`実行前に`commands.killSidecar()`でサイドカープロセスを終了する

---

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

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

### 推奨読解順序

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

i18n辞書の構造とテンプレート変数の使用方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | en.ts | `packages/desktop/src/i18n/en.ts` | `desktop.updater.downloaded.title`と`.prompt`の定義。`{{version}}`プレースホルダーの使用 |
| 1-2 | ja.ts | `packages/desktop/src/i18n/ja.ts` | 日本語翻訳での`{{version}}`プレースホルダーの使用確認 |

**読解のコツ**: `{{version}}`はi18nライブラリの変数展開構文であり、`t()`関数の第2引数でオブジェクトを渡すことで展開される。

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

アップデート処理の起点となるファイルを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | updater.ts | `packages/desktop/src/updater.ts` | `runUpdater`関数内でのダウンロード成功後の処理フロー |

**主要処理フロー**:
1. **28-29行目**: `update.download()`でダウンロード実行
2. **36-38行目**: `ask()`関数で確認ダイアログ表示、`update.version`を変数として渡す
3. **39行目**: `shouldUpdate`がfalseの場合は`return`で終了
4. **41-43行目**: Windows環境でのサイドカー終了と`update.install()`実行
5. **49-50行目**: サイドカー終了と`relaunch()`でアプリ再起動

#### Step 3: Tauri Dialog APIを理解する

`ask`関数の使用方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | updater.ts | `packages/desktop/src/updater.ts` | `@tauri-apps/plugin-dialog`からの`ask`関数インポート（3行目） |

**主要処理フロー**:
- **3行目**: `import { ask, message } from "@tauri-apps/plugin-dialog"`
- **36-38行目**: `const shouldUpdate = await ask(t("desktop.updater.downloaded.prompt", { version: update.version }), { title: t("desktop.updater.downloaded.title") })`

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

```
メニュー: Check for Updates... / 自動アップデートチェック
    │
    └─ runUpdater()
           │
           ├─ initI18n()
           │
           ├─ check() [Tauri Updater Plugin]
           │
           ├─ update.download() [Tauri Updater Plugin]
           │      │
           │      └─ [成功時]
           │             │
           │             └─ ask() [Tauri Dialog Plugin]
           │                    │
           │                    ├─ t("desktop.updater.downloaded.prompt", { version })
           │                    └─ t("desktop.updater.downloaded.title")
           │
           ├─ [Yes選択時]
           │      │
           │      ├─ commands.killSidecar() [Windows only]
           │      │
           │      ├─ update.install() [Tauri Updater Plugin]
           │      │
           │      ├─ commands.killSidecar()
           │      │
           │      └─ relaunch() [Tauri Process Plugin]
           │
           └─ [No選択時] return (処理終了)
```

### データフロー図

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

メニュー操作     ───▶  runUpdater()
                              │
                              ▼
                       check() - アップデート確認
                              │
                              ▼
                       download() - ダウンロード実行
                              │
                              ▼
                       [成功]
                              │
                              ▼
update.version   ───▶  i18n翻訳取得(t関数)    ───▶  確認ダイアログ
                       + 変数展開                       (ask関数)
                              │
                              ▼
                       [Yes選択]
                              │
                              ▼
                       install() + relaunch()  ───▶  アプリ再起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| updater.ts | `packages/desktop/src/updater.ts` | ソース | アップデート処理のメインロジック |
| en.ts | `packages/desktop/src/i18n/en.ts` | 設定 | 英語メッセージ定義（テンプレート変数含む） |
| ja.ts | `packages/desktop/src/i18n/ja.ts` | 設定 | 日本語メッセージ定義 |
| index.ts (i18n) | `packages/desktop/src/i18n/index.ts` | ソース | i18n初期化・翻訳関数(t)の提供 |
| bindings.ts | `packages/desktop/src/bindings.ts` | ソース | Rustバインディング（commands.killSidecar等） |
