# 機能設計書 32-Actualフォーマットインポート

## 概要

本ドキュメントは、Actual独自フォーマットのバックアップファイルからデータをインポートする機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：Actualは独自のバックアップ形式を持っており、ユーザーが作成したバックアップファイルを復元したり、他のActualインスタンスからデータを移行する際に本機能が必要となる。他のインポート機能（YNAB4、YNAB5）と異なり、Actual形式はデータ変換が不要で、直接ファイルとして書き込むことができるため、高速かつ完全なデータ復元が可能である。

**機能の利用シーン**：
- バックアップファイルからの予算データ復元
- 別のActualインスタンス間でのデータ移行
- テスト環境へのデータ投入
- クラウド同期の初回セットアップ時のデータインポート

**主要な処理内容**：
1. 現在開いている予算をクローズする
2. バックアップファイルをクラウドストレージ形式でインポート
3. インポートされたデータベースのキャッシュをクリアする
4. 新しい予算ファイルをロードする
5. 予算の境界（開始・終了日）を計算する
6. スプレッドシートの計算完了を待機する
7. クラウドへのアップロードを試行する

**関連システム・外部連携**：クラウドストレージ機能（cloud-storage）、SQLiteデータベース、スプレッドシートエンジン

**権限による制御**：ファイルシステムへの読み書き権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | ウェルカム画面 | 遷移先機能 | Actualバックアップからのインポート画面への遷移 |

## 機能種別

データ連携 / ファイル操作 / データベース操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filepath | string | Yes | インポートファイルのパス（未使用だが引数として受け取る） | - |
| buffer | Buffer | Yes | Actual形式のバックアップデータを含むバッファ | Actual形式であること |

### 入力データソース

Actual形式のバックアップファイル（ZIP形式）。以下を含む：
- `db.sqlite`: 予算データベース
- `metadata.json`: ファイルメタデータ
- その他の設定ファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| error | string | エラー発生時のエラー理由（FileDownloadError時） |
| id | string | インポートされた予算ファイルのID |

### 出力先

- ファイルシステム（予算ディレクトリ）
- SQLiteデータベース
- クラウドストレージ（オプション）

## 処理フロー

### 処理シーケンス

```
1. 予算クローズ（close-budget）
   └─ 現在開いている予算ファイルをクローズ
2. バッファインポート（cloudStorage.importBuffer）
   └─ バックアップファイルを展開してローカルに保存
3. キャッシュクリア
   └─ SQLiteを開いてkvcache, kvcache_keyテーブルをクリア
4. 予算ロード（load-budget）
   └─ インポートした予算ファイルを開く
5. 境界計算（get-budget-bounds）
   └─ 予算の日付範囲を計算
6. スプレッドシート待機（waitOnSpreadsheet）
   └─ 計算の完了を待機
7. クラウドアップロード（cloudStorage.upload）
   └─ 同期サーバーへのアップロード（エラーは無視）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[close-budget: 現在の予算をクローズ]
    B --> C[cloudStorage.importBuffer: バッファインポート]
    C --> D{インポート成功?}
    D -->|No| E[FileDownloadError]
    E --> F[エラーを返却]
    D -->|Yes| G[SQLite: キャッシュクリア]
    G --> H[load-budget: 予算ロード]
    H --> I[get-budget-bounds: 境界計算]
    I --> J[waitOnSpreadsheet: スプレッドシート待機]
    J --> K[cloudStorage.upload: クラウドアップロード]
    K --> L[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 事前クローズ | インポート前に現在開いている予算をクローズする | 常時 |
| BR-02 | キャッシュクリア | インポートしたファイルのキャッシュは使用しない | 常時 |
| BR-03 | クラウドアップロードエラー無視 | アップロード失敗時もインポート自体は成功とする | 常時 |

### 計算ロジック

特になし（データ変換は行わない）

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| キャッシュクリア | kvcache | DELETE | 全レコード削除 |
| キャッシュクリア | kvcache_key | DELETE | 全レコード削除 |

### テーブル別操作詳細

#### kvcache / kvcache_key

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | * | 全レコード | キャッシュの完全クリア |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FileDownloadError | ファイルエラー | バッファのインポートに失敗 | エラー理由を返却 |

### リトライ仕様

リトライは行わない。クラウドアップロードの失敗は無視される。

## トランザクション仕様

SQLiteのキャッシュクリアは単一のexecQuery呼び出しで実行される。予算のロードとスプレッドシート計算は非同期で順次実行される。

## パフォーマンス要件

- Actual形式はデータ変換が不要なため、他のインポート形式より高速に処理される
- スプレッドシートの計算待機は予算サイズに依存する

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

- インポートファイルはユーザーのローカルファイルシステムから読み込む
- キャッシュをクリアすることで、前回の状態が新しいインポートに影響しないようにする

## 備考

- 本機能はActual APIレイヤーを経由せず、直接ファイルを書き込むため、他のインポート機能とは処理フローが異なる
- `cloudFileId: null, groupId: null` を指定することで、新規ファイルとしてインポートされる

---

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

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

### 推奨読解順序

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

メインのインポート処理を行うファイルを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | actual.ts | `packages/loot-core/src/server/importers/actual.ts` | インポート処理の全体フローを理解する |

**主要処理フロー**:
- **8-49行目**: `importActual` - メインのインポート関数
- **12行目**: `handlers['close-budget']()` - 現在の予算をクローズ
- **14-19行目**: `cloudStorage.importBuffer` - バッファのインポート処理
- **20-23行目**: `FileDownloadError` - エラーハンドリング
- **29-38行目**: SQLiteキャッシュクリア処理
- **43行目**: `handlers['load-budget']({ id })` - 予算のロード
- **44行目**: `handlers['get-budget-bounds']()` - 境界計算
- **45行目**: `waitOnSpreadsheet()` - スプレッドシート待機
- **46-48行目**: `cloudStorage.upload()` - クラウドアップロード（エラー無視）

#### Step 2: 依存モジュールを理解する

インポート処理で使用される各モジュールを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cloud-storage.ts | `packages/loot-core/src/server/cloud-storage.ts` | importBuffer関数の実装を理解する |
| 2-2 | main.ts | `packages/loot-core/src/server/main.ts` | handlersオブジェクトの定義を確認する |
| 2-3 | sheet.ts | `packages/loot-core/src/server/sheet.ts` | waitOnSpreadsheet関数の実装を理解する |

#### Step 3: SQLite操作を理解する

データベース操作の詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sqlite.ts | `packages/loot-core/src/platform/server/sqlite/index.ts` | openDatabase, execQuery, closeDatabase関数を理解する |
| 3-2 | fs.ts | `packages/loot-core/src/platform/server/fs/index.ts` | getBudgetDir, join関数を理解する |

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

```
importActual (actual.ts:8)
    │
    ├─ handlers['close-budget']() (main.ts)
    │
    ├─ cloudStorage.importBuffer() (cloud-storage.ts)
    │      └─ { id } を返却
    │
    ├─ sqlite.openDatabase() (sqlite.ts)
    │      └─ fs.join(fs.getBudgetDir(id), 'db.sqlite')
    │
    ├─ sqlite.execQuery() (sqlite.ts)
    │      └─ DELETE FROM kvcache; DELETE FROM kvcache_key;
    │
    ├─ sqlite.closeDatabase() (sqlite.ts)
    │
    ├─ handlers['load-budget']({ id }) (main.ts)
    │
    ├─ handlers['get-budget-bounds']() (main.ts)
    │
    ├─ waitOnSpreadsheet() (sheet.ts)
    │
    └─ cloudStorage.upload() (cloud-storage.ts)
           └─ catch: エラーを無視
```

### データフロー図

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

Actual ZIP ───▶ cloudStorage.importBuffer() ───▶ ファイルシステム
バッファ                    │                     (予算ディレクトリ)
                           │
                           ▼
                    sqlite.execQuery() ───▶ キャッシュクリア
                           │
                           ▼
                    handlers['load-budget'] ───▶ メモリ上の予算データ
                           │
                           ▼
                    waitOnSpreadsheet() ───▶ 計算完了
                           │
                           ▼
                    cloudStorage.upload() ───▶ クラウドストレージ
                                              (オプション)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| actual.ts | `packages/loot-core/src/server/importers/actual.ts` | ソース | Actualインポートのメイン処理 |
| cloud-storage.ts | `packages/loot-core/src/server/cloud-storage.ts` | ソース | クラウドストレージ操作 |
| main.ts | `packages/loot-core/src/server/main.ts` | ソース | ハンドラー定義 |
| sheet.ts | `packages/loot-core/src/server/sheet.ts` | ソース | スプレッドシート管理 |
| sqlite.ts | `packages/loot-core/src/platform/server/sqlite/index.ts` | ソース | SQLite操作 |
| fs.ts | `packages/loot-core/src/platform/server/fs/index.ts` | ソース | ファイルシステム操作 |
