# 画面設計書 10-予算画面（モバイル）

## 概要

本ドキュメントは、Actual Budget アプリケーションのモバイル向け予算画面の設計仕様を記述したものである。

### 本画面の処理概要

モバイル予算画面は、狭い画面幅のデバイス向けに最適化された予算管理画面である。デスクトップ版と同様に月別の予算を表示・編集できるが、タッチ操作に最適化されたUIと、モバイル専用のバナー表示、モーダル操作を提供する。1ヶ月分の予算をスクロール形式で表示し、未分類取引や超過予算の警告バナーを画面上部に表示する。

**業務上の目的・背景**：スマートフォンやタブレットでも予算管理を行いたいユーザー向けに、タッチ操作に適したUIを提供する。外出先での予算確認、取引の分類、簡易的な予算調整を可能にし、いつでもどこでも家計管理ができる環境を実現する。デスクトップ版の機能をベースに、モバイルでの使いやすさを優先した設計となっている。

**画面へのアクセス方法**：以下の条件でこの画面にアクセスする：
- 狭い画面幅（モバイル）で `/budget` にアクセス
- モバイルナビゲーションタブの「Budget」をタップ
- 予算ファイルを開いた直後（モバイル環境）

**主要な操作・処理内容**：
1. 月別予算の表示・ナビゲーション（前月/次月/今月）
2. カテゴリ別予算額の表示・編集（モーダル経由）
3. 予算サマリーの表示（モーダル）
4. カテゴリ/カテゴリグループの管理（メニュー経由）
5. 未分類取引・超過予算バナーの表示と対応
6. プルリフレッシュによる同期

**画面遷移**：
- 遷移元：予算ファイル選択後、モバイルナビゲーション、他の画面からの戻り
- 遷移先：カテゴリ画面（カテゴリタップ時）、未分類取引画面、各種モーダル

**権限による表示制御**：予算タイプ（封筒/追跡）によってサマリー内容と一部操作が変わる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | 予算作成・編集 | 主機能 | モバイルでの月次予算表示・編集処理 |
| 2 | 予算繰越（Carryover） | 補助機能 | モバイルでの予算繰越設定 |
| 60 | レスポンシブUI | 補助機能 | モバイル画面に最適化されたレスポンシブ表示 |

## 画面種別

一覧・編集画面（モバイル専用）

## URL/ルーティング

`/budget`（狭い画面幅で表示）

## 入出力項目

| 項目名 | 項目ID | 入出力 | 必須 | データ型 | 最大長 | 備考 |
|--------|--------|--------|------|----------|--------|------|
| 月選択 | startMonth | 入力 | 必須 | string | - | "YYYY-MM"形式 |
| 予算額 | budgeted | 入力 | 任意 | number | - | モーダル経由で編集 |

## 表示項目

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| ヘッダー | 月セレクターと前月/次月ボタン | MobilePageHeader |
| ロゴメニュー | Actualロゴ + メニューアイコン | 左上 |
| 今月ボタン | カレンダーアイコン | 現在月以外で表示 |
| バナー領域 | 未分類取引/超過予算/予算超過バナー | 条件付き表示 |
| 予算テーブル | カテゴリグループとカテゴリの一覧 | BudgetTable |

## イベント仕様

### 1-月ナビゲーション（前月/次月ボタンタップ）

1. `onPrevMonth` または `onNextMonth` 関数を実行
2. 新しい月のデータをprewarm
3. `setStartMonthPref` で表示月を更新
4. UIが新しい月のデータで再レンダリング

### 2-今月に移動（カレンダーアイコンタップ）

1. `onCurrentMonth` 関数を実行
2. 現在月のデータをprewarm
3. 表示月を現在月に更新

### 3-予算サマリー表示（タップ）

1. `onShowBudgetSummary` 関数を実行
2. 予算タイプに応じたサマリーモーダルを表示:
   - 封筒予算: `envelope-budget-summary` モーダル
   - 追跡予算: `tracking-budget-summary` モーダル

### 4-カテゴリグループメニュー（グループタップ）

1. `onOpenCategoryGroupMenuModal` 関数を実行
2. `category-group-menu` モーダルを表示
3. 操作選択: 名前変更/カテゴリ追加/ノート編集/削除/表示切替/テンプレート適用

### 5-カテゴリメニュー（カテゴリタップ）

1. `onOpenCategoryMenuModal` 関数を実行
2. `category-menu` モーダルを表示
3. 操作選択: 名前変更/ノート編集/削除/表示切替

### 6-予算ページメニュー（ロゴアイコンタップ）

1. `onOpenBudgetPageMenu` 関数を実行
2. `budget-page-menu` モーダルを表示
3. 操作選択: カテゴリグループ追加/非表示カテゴリ表示切替/予算ファイル切替

### 7-未分類取引バナータップ

1. `/categories/uncategorized` に遷移
2. 未分類取引の一覧を表示

### 8-超過予算バナー（Coverタップ）

1. `cover` モーダルを表示
2. カバー元カテゴリを選択
3. 予算アクション `cover-overspending` または `cover-overbudgeted` を実行

### 9-プルリフレッシュ

1. 画面を下に引っ張る操作を検出
2. `dispatch(sync())` を実行
3. サーバーと同期して最新データを取得

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 予算額編集 | budget_data | INSERT/UPDATE | カテゴリ・月ごとの予算額を更新 |
| カテゴリ作成 | categories | INSERT | 新規カテゴリを追加 |
| カテゴリ編集 | categories | UPDATE | カテゴリ名・設定を更新 |
| カテゴリ削除 | categories, transactions | DELETE/UPDATE | カテゴリ削除、取引の移行 |
| グループ作成 | category_groups | INSERT | 新規グループを追加 |
| 超過カバー | budget_data | UPDATE | 複数カテゴリの予算を調整 |

### テーブル別更新項目詳細

#### budget_data

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | category_id | 対象カテゴリID | 予算対象カテゴリ |
| INSERT/UPDATE | month | 対象月（YYYY-MM） | 予算対象月 |
| INSERT/UPDATE | amount | 入力された予算額 | 予算額（整数、セント単位） |

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 表示条件 |
|-------------|---------------|------|----------|
| uncategorized-banner | "You have {count} uncategorized transactions ({amount})" | 警告 | 未分類取引がある場合 |
| overspent-banner | "You have {count} overspent categories ({amount})" | 警告 | 超過カテゴリがある場合 |
| overbudgeted-banner | "You have budgeted more than your available funds" | 警告 | 予算超過時（封筒予算） |

## 例外処理

| 例外ケース | 処理内容 |
|------------|----------|
| データロード中 | AnimatedLoading を中央に表示 |
| カテゴリグループ未取得 | ローディング表示を継続 |
| 同期エラー | エラー通知を表示（Notifications経由） |

## 備考

- デスクトップ版と同じ `/budget` URLだが、画面幅に応じてコンポーネントが切り替わる
- SyncRefresh コンポーネントでプルリフレッシュを実装
- バナーは GridList で実装され、条件に応じて動的に表示
- numberFormat / hideFraction 設定変更時にテーブル全体が再レンダリング

---

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

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

### 推奨読解順序

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

予算データとカテゴリの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models/category.d.ts | `loot-core/types/models/category.d.ts` | CategoryEntity, CategoryGroupEntityの型定義 |
| 1-2 | bindings.ts | `packages/desktop-client/src/spreadsheet/bindings.ts` | envelopeBudget.toBudget 等のバインディング |

**読解のコツ**: useSheetValue で使用されるバインディング名を理解する

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

メインコンポーネントの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BudgetPage.tsx | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` | BudgetPage関数コンポーネントの実装 |

**主要処理フロー**:
1. **73-93行目**: BudgetPage関数の初期化、状態管理
2. **95-106行目**: useEffect で予算境界取得とprewarm
3. **108-113行目**: onBudgetAction で予算操作
4. **115-140行目**: onShowBudgetSummary でサマリーモーダル表示
5. **320-339行目**: onPrevMonth / onNextMonth / onCurrentMonth
6. **550-639行目**: レンダリング（Page, MobilePageHeader, Banners, BudgetTable）

#### Step 3: バナーコンポーネントを理解する

警告バナーの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Banners | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` (643-663行目) | バナー領域の実装 |
| 3-2 | UncategorizedTransactionsBanner | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` (687-749行目) | 未分類取引バナー |
| 3-3 | OverspendingBanner | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` (837-983行目) | 超過予算バナー |
| 3-4 | OverbudgetedBanner | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` (751-835行目) | 予算超過バナー（封筒予算） |

#### Step 4: モバイル予算テーブルを理解する

テーブルコンポーネントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BudgetTable.tsx | `packages/desktop-client/src/components/mobile/budget/BudgetTable.tsx` | モバイル版予算テーブル |

#### Step 5: 月セレクターを理解する

月ナビゲーションの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | MonthSelector | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` (985-1047行目) | 月選択コンポーネント |

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

```
BudgetPage (BudgetPage.tsx)
    │
    ├─ Page + MobilePageHeader
    │      ├─ ロゴメニュー → onOpenBudgetPageMenu
    │      │      └─ pushModal('budget-page-menu')
    │      │
    │      ├─ MonthSelector
    │      │      ├─ onPrevMonth → prewarmMonth + setStartMonthPref
    │      │      ├─ onNextMonth → prewarmMonth + setStartMonthPref
    │      │      └─ onOpenMonthMenu → pushModal('budget-month-menu')
    │      │
    │      └─ 今月ボタン → onCurrentMonth
    │
    ├─ Banners (GridList)
    │      ├─ UncategorizedTransactionsBanner
    │      │      └─ navigate('/categories/uncategorized')
    │      │
    │      ├─ OverspendingBanner
    │      │      └─ pushModal('cover') → onBudgetAction('cover-overspending')
    │      │
    │      └─ OverbudgetedBanner (封筒予算のみ)
    │             └─ pushModal('cover') → onBudgetAction('cover-overbudgeted')
    │
    └─ BudgetTable
           ├─ onShowBudgetSummary
           │      └─ pushModal('envelope/tracking-budget-summary')
           │
           ├─ onEditCategoryGroup
           │      └─ onOpenCategoryGroupMenuModal
           │             └─ pushModal('category-group-menu')
           │
           └─ onEditCategory
                  └─ onOpenCategoryMenuModal
                         └─ pushModal('category-menu')
```

### データフロー図

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

月選択 ─────────────────▶ MonthSelector ─────────────────▶ onPrevMonth/onNextMonth
                              │
                              ▼
                        prewarmMonth()
                              │
                              ▼
                    setStartMonthPref(month)
                              │
                              ▼
                    useLocalPref 更新
                              │
                              ▼
                    BudgetTable 再レンダリング ──────────▶ 月別予算表示

---

カテゴリタップ ─────────▶ BudgetTable ───────────────────▶ onOpenCategoryMenuModal
                              │
                              ▼
                    pushModal('category-menu')
                              │
                              ▼
                    [モーダル: 操作選択]
                              │
                              ▼
                    updateCategory / deleteCategory
                              │
                              ▼
                    Redux state + DB 更新 ──────────────▶ UI再レンダリング
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BudgetPage.tsx | `packages/desktop-client/src/components/mobile/budget/BudgetPage.tsx` | ソース | メインコンポーネント |
| BudgetTable.tsx | `packages/desktop-client/src/components/mobile/budget/BudgetTable.tsx` | ソース | モバイル予算テーブル |
| Page.tsx | `packages/desktop-client/src/components/Page.tsx` | ソース | ページレイアウト |
| SyncRefresh.tsx | `packages/desktop-client/src/components/SyncRefresh.tsx` | ソース | プルリフレッシュ |
| budgetSlice.ts | `packages/desktop-client/src/budget/budgetSlice.ts` | ソース | 予算Redux スライス |
| modalsSlice.ts | `packages/desktop-client/src/modals/modalsSlice.ts` | ソース | モーダル管理 |
| util.ts | `packages/desktop-client/src/components/budget/util.ts` | ソース | prewarmMonth ユーティリティ |
| bindings.ts | `packages/desktop-client/src/spreadsheet/bindings.ts` | ソース | スプレッドシートバインディング |
