# 機能設計書 2-予算繰越（Carryover）

## 概要

本ドキュメントは、Actual Budget における未使用予算を翌月に繰り越す機能の設計を記述する。Envelope Budgeting 方式において、カテゴリの残高を次月に持ち越すか、リセットするかを制御する重要な機能である。

### 本機能の処理概要

**業務上の目的・背景**：Envelope Budgeting（封筒予算方式）では、各カテゴリに割り当てた予算は「封筒」として扱われる。月末に封筒に残った金額（未使用予算）を翌月にどう扱うかは、予算管理の重要な判断事項である。本機能は、カテゴリごとに「繰り越す」か「リセットする」かを設定可能にし、柔軟な予算管理を実現する。特に、赤字（オーバースペンディング）が発生した場合の処理が重要で、赤字を翌月に繰り越すか、未割当予算から補填するかを制御できる。

**機能の利用シーン**：
- 貯蓄目標カテゴリで、毎月の積み立てを累積する
- 変動費カテゴリで、余った予算を翌月に持ち越す
- 固定費カテゴリで、オーバースペンディング時の処理方法を設定する
- 年払い費用の準備として、複数月にわたって予算を蓄積する

**主要な処理内容**：
1. カテゴリごとの繰越フラグ（carryover）の設定・解除
2. 月末処理での残高繰り越し計算
3. オーバースペンディング時の To Be Budgeted への影響制御
4. 繰越状態の視覚的インジケーター表示

**関連システム・外部連携**：スプレッドシートエンジンによる残高計算、予算作成・編集機能との連携

**権限による制御**：特別な権限制御なし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | 予算画面（デスクトップ） | 主画面 | 未使用予算の翌月繰越設定 |
| 10 | 予算画面（モバイル） | 主画面 | モバイルでの予算繰越設定 |

## 機能種別

CRUD操作 / 計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| month | string | Yes | 繰越を設定する月（YYYY-MM形式） | 有効な年月形式 |
| categoryId | string | Yes | 対象カテゴリのID | 存在するカテゴリID |
| flag | boolean | Yes | 繰越を有効にするかどうか | true/false |

### 入力データソース

- 画面入力：予算セルの残高部分のコンテキストメニュー
- API経由：`api/budget-set-carryover` ハンドラー

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| carryover | boolean | 繰越が有効かどうか |
| balance | number | カテゴリの残高（繰越含む） |
| toBeBudgeted | number | 未割当予算（繰越設定により変動） |

### 出力先

- 画面表示：残高セルに繰越インジケーター（→矢印）を表示
- データベース：予算テーブルの carryover フィールド

## 処理フロー

### 処理シーケンス

```
1. ユーザーが残高セルのコンテキストメニューを開く
   └─ BalanceMovementMenu または BalanceMenu が表示

2. 「Carryover」オプションを選択/解除
   └─ onBudgetAction('carryover', { category, flag }) が発火

3. applyBudgetAction (Redux) 実行
   └─ api/budget-set-carryover を呼び出し

4. サーバーサイドで carryover フラグを保存
   └─ 該当カテゴリ・月の予算レコードを更新

5. スプレッドシートエンジンが再計算
   └─ To Be Budgeted に影響があれば更新

6. UIが更新
   └─ CarryoverIndicator コンポーネントが表示/非表示
```

### フローチャート

```mermaid
flowchart TD
    A[残高セルをクリック] --> B[BalanceMenu表示]
    B --> C{Carryover選択?}
    C -->|Yes| D[onBudgetAction発火]
    C -->|No| E[メニュー閉じる]
    D --> F[api/budget-set-carryover]
    F --> G[DB更新]
    G --> H{残高が負?}
    H -->|Yes| I[To Be Budgeted調整]
    H -->|No| J[残高をそのまま繰越]
    I --> K[UI更新]
    J --> K
    K --> L[CarryoverIndicator表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 繰越有効時 | カテゴリ残高（正負問わず）が翌月に持ち越される | carryover = true |
| BR-002 | 繰越無効時（赤字） | 赤字額がTo Be Budgetedから差し引かれる | carryover = false & balance < 0 |
| BR-003 | 繰越無効時（黒字） | 残高がTo Be Budgetedに戻される | carryover = false & balance > 0 |
| BR-004 | インジケーター表示 | 繰越有効カテゴリには矢印アイコンを表示 | carryover = true |

### 計算ロジック

```
// 繰越有効時の翌月開始残高
nextMonthBalance = currentMonthBalance + nextMonthBudgeted

// 繰越無効時の To Be Budgeted への影響
if (carryover === false && balance < 0) {
  toBeBudgeted = toBeBudgeted + balance  // 赤字分を差し引き
}

// 繰越無効時の翌月開始残高
nextMonthBalance = nextMonthBudgeted  // 0からスタート
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 繰越設定 | zero_budgets | UPDATE | carryover フラグを更新 |

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

#### zero_budgets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | carryover | 0 (false) または 1 (true) | ブール値を整数で保存 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| CATEGORY_NOT_FOUND | データ不整合 | 存在しないカテゴリID | エラー通知を表示 |
| TRACKING_MODE | モード不適合 | Tracking Budgeting モードで実行 | 操作を無視（Trackingでは繰越なし） |

### リトライ仕様

- 同期エラー時は自動リトライ（CRDT機構による）

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

- 繰越フラグの更新はアトミック操作

## パフォーマンス要件

- 繰越設定の反映は即座（100ms以内）

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

- 予算データはローカルファーストで保存
- クラウド同期時はE2E暗号化オプションあり

## 備考

- Tracking Budgeting モードでは本機能は無効（残高は月ごとにリセット）
- YNAB4からのインポート時に overspendingHandling 設定を繰越フラグに変換

---

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

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

### 推奨読解順序

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

繰越フラグのバインディングと表示コンポーネントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BalanceWithCarryover.tsx | `packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx` | CarryoverIndicator コンポーネントと繰越表示ロジック |

**読解のコツ**: `carryoverValue` が true の場合に `CarryoverIndicator` が表示される（287-291行目）。

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

繰越設定のUIエントリーポイントを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BalanceMovementMenu.tsx | `packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx` | 繰越メニュー項目 |
| 2-2 | BalanceMenu.tsx | `packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx` | 残高メニューの繰越オプション |

**主要処理フロー**:
- 残高セルクリック → BalanceMenu/BalanceMovementMenu 表示
- 「Carryover」選択 → `onBudgetAction(month, 'carryover', { category, flag })` 呼び出し

#### Step 3: API層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | methods.ts | `packages/api/methods.ts` | setBudgetCarryover 関数の定義 |

**主要処理フロー**:
- **104-110行目**: `setBudgetCarryover` 関数が `api/budget-set-carryover` メッセージを送信

#### Step 4: インポート処理での繰越設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ynab4.ts | `packages/loot-core/src/server/importers/ynab4.ts` | YNAB4インポート時の繰越変換ロジック |

**主要処理フロー**:
- **298-302行目**: `overspendingHandling` を `setBudgetCarryover` に変換
- `AffectsBuffer` → carryover = false
- `Confined` → carryover = true

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

```
ExpenseCategoryMonth (EnvelopeBudgetComponents.tsx)
    │
    ├─ BalanceWithCarryover
    │      │
    │      └─ CarryoverIndicator (carryoverValue が true の場合)
    │
    └─ BalanceMovementMenu / BalanceMenu
           │
           └─ onBudgetAction('carryover', { category, flag })
                  │
                  └─ applyBudgetAction (Redux)
                         │
                         └─ send('api/budget-set-carryover')
                                │
                                └─ setBudgetCarryover (methods.ts)
```

### データフロー図

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

メニュー選択              onBudgetAction
(Carryover ON/OFF) ──▶   carryover アクション  ───────▶  Redux dispatch
                              │
                              ▼
                         api/budget-set-carryover ───▶  DB更新
                              │
                              ▼
                         スプレッドシート再計算  ───────▶  残高更新
                              │
                              ▼
                         BalanceWithCarryover    ───────▶  インジケーター表示
                         (carryoverValue binding)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BalanceWithCarryover.tsx | `packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx` | ソース | 繰越インジケーター付き残高表示 |
| CarryoverIndicator | 同上（35-56行目） | コンポーネント | 矢印アイコン表示 |
| BalanceMovementMenu.tsx | `packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx` | ソース | 残高移動メニュー |
| BalanceMenu.tsx | `packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx` | ソース | 残高コンテキストメニュー |
| methods.ts | `packages/api/methods.ts` | ソース | setBudgetCarryover API |
| ynab4.ts | `packages/loot-core/src/server/importers/ynab4.ts` | ソース | YNAB4インポート時の繰越変換 |
| ynab5.ts | `packages/loot-core/src/server/importers/ynab5.ts` | ソース | YNAB5インポート時の繰越変換 |
| bindings.ts | `packages/desktop-client/src/spreadsheet/bindings.ts` | ソース | catCarryover バインディング定義 |
