# 通知設計書 12-抽出後ファイル不在通知

## 概要

本ドキュメントは、StaxRipアプリケーションにおける「抽出後ファイル不在通知（File missing after extraction.）」の設計仕様を記述する。

### 本通知の処理概要

この通知は、ツール更新処理においてダウンロードしたアーカイブファイルの抽出が完了したにもかかわらず、期待されるツールファイルが抽出先ディレクトリに存在しない場合に、ユーザーに対してエラー情報を表示する機能を提供する。

**業務上の目的・背景**：StaxRipでは外部ツールの更新時に、アーカイブをダウンロード・抽出してツールを配置する。抽出処理自体が成功（終了コード0）しても、期待するファイル（Package.Filename）が見つからない場合がある。これはアーカイブの構造がStaxRipの想定と異なる場合や、アーカイブ内容が不正な場合に発生する。ユーザーがこの問題を認識し、手動で対処できるようにするために本通知が必要である。

**通知の送信タイミング**：ToolUpdate.Extractメソッドにおいて、7-Zipによる抽出処理が正常終了（ExitCode=0）した後、抽出先ディレクトリにPackage.Filenameで指定されたファイルが存在するかをチェックし、存在しない場合に通知が発生する。サブディレクトリ検索後も見つからない場合が対象となる。

**通知の受信者**：StaxRipアプリケーションを操作している現在のユーザー（エンドユーザー）。モーダルダイアログとして表示されるため、ユーザーは必ず通知を確認することになる。

**通知内容の概要**：固定のエラーメッセージ「File missing after extraction.」が表示される。これにより、抽出処理は成功したがファイルが見つからないという特定の問題状況をユーザーに伝える。

**期待されるアクション**：ユーザーはエラーメッセージを確認し、以下のような対処を行うことが期待される。(1) アーカイブファイルの内容を手動で確認する、(2) 正しいダウンロードURLが使用されているか確認する、(3) 手動でツールをダウンロード・配置する、(4) Package設定（Filename、Include、Exclude）を確認する。

## 通知種別

アプリ内通知（モーダルダイアログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無 |

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

現在StaxRipアプリケーションを操作しているユーザーに対して、モーダルダイアログとして直接表示される。

## 通知テンプレート

### ダイアログ通知の場合

| 項目 | 内容 |
|-----|------|
| タイトル | Error |
| アイコン | Error |
| ボタン | OK |

### 本文テンプレート

```
File missing after extraction.
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| なし | 固定メッセージのため変数なし | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ツール更新実行 | Not (Path.Combine(ExtractDir, Package.Filename)).FileExists | 抽出後に期待されるファイルが存在しない場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ファイルが存在する | 抽出先にPackage.Filenameが存在する場合は通知しない |
| サブディレクトリで見つかった | サブディレクトリ検索でファイルが見つかった場合は通知しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[7-Zip抽出完了 ExitCode=0] --> B{ExtractDir に Package.Filename が存在?}
    B -->|存在する| C[DeleteOldFiles処理へ]
    B -->|存在しない| D[サブディレクトリ検索]
    D --> E{サブディレクトリで発見?}
    E -->|1つ発見| F[ExtractDir を更新]
    E -->|複数発見| G[ユーザーに選択ダイアログ表示]
    E -->|見つからない| H[UpdatePackageDialog呼び出し]
    F --> I{ファイル存在再確認}
    G --> I
    I -->|存在する| C
    I -->|存在しない| H
    H --> J[MsgError表示]
    J --> K[処理中断]
```

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

### 参照テーブル一覧

データベースは使用しない。

### 更新テーブル一覧

データベースは使用しない。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ファイル不在 | 抽出後にPackage.Filenameが見つからない | MsgErrorでユーザーに通知し、処理を中断 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（ユーザー操作に応じて随時表示）

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

- ファイルパス情報は含まれないため、ディレクトリ構造の漏洩リスクは低い
- 固定メッセージのみのため、機密情報漏洩のリスクなし

## 備考

- この通知は抽出処理自体は成功したケースで発生する点が「抽出失敗通知（No.11）」と異なる
- サブディレクトリ検索機能があり、ネストされたアーカイブ構造にも対応している
- Package.Exclude設定によりIgnore関数でフィルタリングされるサブディレクトリは検索対象外

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ToolUpdate.vb | `Source/General/ToolUpdate.vb` | Package.Filenameプロパティが期待されるファイル名を保持することを理解 |

**読解のコツ**: PackageクラスのFilenameプロパティがツールの実行ファイル名を定義していることを把握する。

#### Step 2: 抽出処理とファイル検証を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ToolUpdate.vb | `Source/General/ToolUpdate.vb` | Extract()メソッド（行68-125）、特に行89-122のファイル存在確認ロジック |

**主要処理フロー**:
1. **行89**: 抽出先にPackage.Filenameが存在するかチェック
2. **行90-116**: サブディレクトリ検索（複数候補の場合はユーザーに選択させる）
3. **行118-122**: **通知発生箇所** - 最終的にファイルが見つからない場合にMsgError呼び出し

#### Step 3: サブディレクトリ検索ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ToolUpdate.vb | `Source/General/ToolUpdate.vb` | 行92-96のサブディレクトリ検索とIgnore関数によるフィルタリング |

**主要処理フロー**:
- **行92-96**: Directory.GetDirectoriesで全サブディレクトリを検索し、Package.Filenameが存在するものをリストアップ
- **行98-112**: 複数候補がある場合はTaskDialogで選択させる
- **行113-114**: 1つだけの場合は自動選択

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

```
ToolUpdate.Extract()
    │
    ├─ [7-Zip抽出完了後]
    │      │
    │      ├─ File.Exists(Path.Combine(ExtractDir, Package.Filename))
    │      │      │
    │      │      └─ [存在しない場合]
    │      │             │
    │      │             └─ Directory.GetDirectories() [サブディレクトリ検索]
    │      │                    │
    │      │                    ├─ [複数候補] TaskDialog表示
    │      │                    └─ [1候補] 自動選択
    │      │
    │      └─ [最終チェック: ファイルが存在しない場合]
    │             ├─ UpdatePackageDialog()
    │             └─ MsgError("File missing after extraction.")
    │
    └─ [ファイルが存在する場合]
           └─ DeleteOldFiles()
```

### データフロー図

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

ExtractDir ─────────────▶ Path.Combine(ExtractDir, Package.Filename)
        │                     │
        │                     ├─ [存在する] ──────────▶ DeleteOldFiles()へ
        │                     │
        │                     └─ [存在しない]
        │                            │
        ▼                            ▼
Package.Filename ───────▶ サブディレクトリ検索 ────────▶ ExtractDir更新
        │                     │
        │                     └─ [見つからない] ──────▶ MsgError表示
        ▼
Package.Exclude ────────▶ Ignore()フィルタ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ToolUpdate.vb | `Source/General/ToolUpdate.vb` | ソース | ツール更新処理のメインロジック（行118-122が通知発生箇所） |
| Msg.vb | `Source/UI/Msg.vb` | ソース | MsgError関数の定義 |
| Package.vb | `Source/General/Package.vb` | ソース | Packageクラスの定義（Filename, Exclude等） |
