# 機能設計書 38-REST API

## 概要

本ドキュメントは、外部システム連携用のREST API機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：Actualは単独のアプリケーションとして使用するだけでなく、外部システムやスクリプトからプログラマティックにアクセスしたいというニーズがある。本機能は、予算管理の主要な操作（口座管理、取引管理、カテゴリ管理、予算設定等）を外部から実行可能なAPIとして提供する。これにより、自動化スクリプト、サードパーティ統合、カスタムダッシュボード等の構築が可能になる。

**機能の利用シーン**：
- 外部スクリプトからの取引自動登録
- 銀行同期の自動実行
- カスタムレポートツールからのデータ取得
- CI/CD パイプラインでの予算データ検証
- サードパーティアプリケーションとの連携

**主要な処理内容**：
1. 予算ファイルの読み込み・同期
2. 口座のCRUD操作（作成、取得、更新、削除、クローズ、再開）
3. 取引のCRUD操作（追加、取得、更新、削除、インポート）
4. カテゴリ・カテゴリグループのCRUD操作
5. 支払先のCRUD操作（マージ含む）
6. スケジュールのCRUD操作
7. ルールのCRUD操作
8. 予算データの取得・更新
9. AQLクエリの実行

**関連システム・外部連携**：injectedモジュールを通じてActual内部のハンドラーと通信

**権限による制御**：APIキー認証またはサーバー認証が必要（sync-server経由の場合）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | REST APIは画面を持たない |

## 機能種別

データ連携 / CRUD操作 / 外部インターフェース

## 入力仕様

### 入力パラメータ

各API関数の主要パラメータを以下に示す。

#### 予算管理系

| API関数 | パラメータ名 | 型 | 必須 | 説明 |
|---------|-------------|-----|-----|------|
| loadBudget | budgetId | string | Yes | 予算ファイルID |
| downloadBudget | syncId | string | Yes | 同期ID |
| downloadBudget | password | string | No | 暗号化パスワード |

#### 口座系

| API関数 | パラメータ名 | 型 | 必須 | 説明 |
|---------|-------------|-----|-----|------|
| createAccount | account | Omit<APIAccountEntity, 'id'> | Yes | 口座データ |
| createAccount | initialBalance | number | No | 初期残高 |
| updateAccount | id | string | Yes | 口座ID |
| updateAccount | fields | Partial<APIAccountEntity> | Yes | 更新フィールド |
| closeAccount | id | string | Yes | 口座ID |
| closeAccount | transferAccountId | string | No | 残高移動先口座 |
| closeAccount | transferCategoryId | string | No | 残高移動先カテゴリ |
| getAccountBalance | id | string | Yes | 口座ID |
| getAccountBalance | cutoff | Date | No | 残高計算基準日 |

#### 取引系

| API関数 | パラメータ名 | 型 | 必須 | 説明 |
|---------|-------------|-----|-----|------|
| addTransactions | accountId | string | Yes | 口座ID |
| addTransactions | transactions | ImportTransactionEntity[] | Yes | 取引データ配列 |
| addTransactions | learnCategories | boolean | No | カテゴリ学習 |
| addTransactions | runTransfers | boolean | No | 振替処理実行 |
| getTransactions | accountId | string | Yes | 口座ID |
| getTransactions | startDate | string | Yes | 開始日 |
| getTransactions | endDate | string | Yes | 終了日 |

### 入力データソース

外部システムからのAPI呼び出し

## 出力仕様

### 出力データ

各API関数の戻り値を以下に示す。

| API関数 | 戻り値型 | 説明 |
|--------|---------|------|
| getAccounts | APIAccountEntity[] | 口座一覧 |
| createAccount | string | 作成された口座ID |
| getTransactions | TransactionEntity[] | 取引一覧 |
| addTransactions | { added, updated } | 追加・更新件数 |
| getCategories | APICategoryEntity[] | カテゴリ一覧 |
| getPayees | APIPayeeEntity[] | 支払先一覧 |
| getSchedules | APIScheduleEntity[] | スケジュール一覧 |
| getRules | RuleEntity[] | ルール一覧 |
| getBudgetMonths | string[] | 予算月一覧 |
| getBudgetMonth | BudgetMonth | 月次予算データ |
| aqlQuery | { data, dependencies } | クエリ結果 |

### 出力先

API呼び出し元への戻り値

## 処理フロー

### 処理シーケンス

```
1. API関数呼び出し
   └─ 外部システムからの呼び出しを受け付け
2. パラメータ検証
   └─ 型チェック、必須項目チェック
3. ハンドラー呼び出し
   └─ injected.send()でActual内部ハンドラーを呼び出し
4. 結果返却
   └─ Promise<T>で結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[外部システム] --> B[API関数呼び出し]
    B --> C[injected.send]
    C --> D[内部ハンドラー]
    D --> E[データベース操作]
    E --> F[結果返却]
    F --> G[外部システムへ応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ID自動生成 | 作成系APIではIDは自動生成される | 新規作成時 |
| BR-02 | 予算ロード必須 | 多くのAPIはloadBudgetが先に呼ばれていることが前提 | 予算操作時 |
| BR-03 | 非推奨警告 | runQueryは非推奨、aqlQueryを使用すべき | クエリ実行時 |

### 計算ロジック

特になし。各ハンドラー内で処理。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createAccount | accounts | INSERT | 口座作成 |
| updateAccount | accounts | UPDATE | 口座更新 |
| deleteAccount | accounts | DELETE | 口座削除 |
| closeAccount | accounts | UPDATE | 口座クローズ |
| addTransactions | transactions | INSERT | 取引追加 |
| updateTransaction | transactions | UPDATE | 取引更新 |
| deleteTransaction | transactions | DELETE | 取引削除 |
| createCategory | categories | INSERT | カテゴリ作成 |
| updateCategory | categories | UPDATE | カテゴリ更新 |
| deleteCategory | categories | DELETE | カテゴリ削除 |
| createPayee | payees | INSERT | 支払先作成 |
| updatePayee | payees | UPDATE | 支払先更新 |
| deletePayee | payees | DELETE | 支払先削除 |
| mergePayees | payees | UPDATE/DELETE | 支払先マージ |
| setBudgetAmount | zero_budgets/reflect_budgets | INSERT/UPDATE | 予算設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | 必須パラメータ不足 | エラーメッセージを確認 |
| - | NotFoundError | 指定IDが存在しない | 正しいIDを指定 |
| - | BudgetNotLoadedError | 予算がロードされていない | loadBudgetを先に呼ぶ |

### リトライ仕様

特になし。

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

各API呼び出しは独立したトランザクションとして処理される。batchBudgetUpdatesを使用することで複数の予算更新をバッチ処理可能。

## パフォーマンス要件

- 大量の取引追加は addTransactions でバッチ処理
- 予算更新は batchBudgetUpdates でバッチ処理

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

- API呼び出しには適切な認証が必要
- sync-server経由の場合はAPIキーまたはOAuth認証
- ローカル使用の場合はファイルアクセス権限

## 備考

- 全API関数はPromiseを返す非同期関数
- injectedモジュールを通じて内部ハンドラーと通信
- query builder（q関数）はAQL構築に使用

---

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

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

### 推奨読解順序

#### Step 1: 型定義を理解する

API関連の型定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api-models.ts | `packages/loot-core/src/server/api-models.ts` | APIAccountEntity, APICategoryEntity等の型定義 |

#### Step 2: メインAPI関数を理解する

API関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | methods.ts | `packages/api/methods.ts` | 全API関数の実装 |

**主要処理フロー**:
- **19-26行目**: `send` - 内部ハンドラー呼び出しヘルパー
- **28-40行目**: `runImport` - インポート処理のラッパー
- **42-44行目**: `loadBudget` - 予算ロード
- **57-59行目**: `sync` - 同期実行
- **61-65行目**: `runBankSync` - 銀行同期実行
- **67-74行目**: `batchBudgetUpdates` - 予算一括更新
- **80-86行目**: `runQuery`/`aqlQuery` - クエリ実行
- **88-110行目**: 予算取得・設定系
- **112-166行目**: 取引系CRUD
- **168-208行目**: 口座系CRUD
- **210-252行目**: カテゴリ系CRUD
- **254-282行目**: 支払先系CRUD
- **284-302行目**: ルール系CRUD
- **312-334行目**: スケジュール系CRUD
- **336-341行目**: ユーティリティ系

**読解のコツ**:
- 全関数は`send`ヘルパーを通じて`api/*`ハンドラーを呼び出す
- 戻り値型は`Promise<Awaited<ReturnType<T>>>`パターン
- `Omit<Entity, 'id'>`は作成時にIDを除外するパターン

#### Step 3: ハンドラー実装を理解する

内部ハンドラーの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | main.ts | `packages/loot-core/src/server/main.ts` | api/*ハンドラーの定義 |
| 3-2 | handlers.ts | `packages/loot-core/types/handlers.ts` | ハンドラー型定義 |

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

```
外部システム / クライアント
    │
    └─ API関数（methods.ts）
           │
           ├─ loadBudget
           │      └─ send('api/load-budget', { id })
           │
           ├─ getAccounts
           │      └─ send('api/accounts-get')
           │
           ├─ createAccount
           │      └─ send('api/account-create', { account, initialBalance })
           │
           ├─ addTransactions
           │      └─ send('api/transactions-add', { accountId, transactions, ... })
           │
           ├─ aqlQuery
           │      └─ send('api/query', { query: query.serialize() })
           │
           └─ ... 他のAPI関数
                  │
                  ▼
           injected.send()
                  │
                  ▼
           内部ハンドラー（main.ts）
                  │
                  ▼
           データベース操作
```

### データフロー図

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

外部システム ───▶ API関数 ───▶ send() ───▶ ハンドラー
     │                               │            │
     │                               │            ▼
     │                               │      データベース
     │                               │            │
     │                               │            ▼
     │                               │       結果データ
     │                               │            │
     ◀───────────────────────────────────────────◀┘
         Promise<T>
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| methods.ts | `packages/api/methods.ts` | ソース | API関数定義 |
| injected.ts | `packages/api/injected.ts` | ソース | 内部通信モジュール |
| query.ts | `packages/api/app/query.ts` | ソース | AQLクエリビルダー（q関数） |
| api-models.ts | `packages/loot-core/src/server/api-models.ts` | ソース | API型定義 |
| main.ts | `packages/loot-core/src/server/main.ts` | ソース | 内部ハンドラー定義 |
| handlers.ts | `packages/loot-core/types/handlers.ts` | ソース | ハンドラー型定義 |
