# 機能設計書 62-ノート機能

## 概要

本ドキュメントは、Actualアプリケーションにおけるノート機能の設計仕様を記載したものである。取引や口座、カテゴリなどにメモ・ノートを追加する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：家計簿管理において、取引や口座に関する補足情報を記録しておきたいニーズがある。ノート機能は、各種エンティティ（取引、口座、カテゴリなど）にテキスト形式のメモを付与することで、後から確認しやすい記録を可能にする。Markdown形式をサポートしており、リンクや書式付きテキストも記述可能。

**機能の利用シーン**：
- 取引の詳細情報（購入理由、関連するイベントなど）を記録したい場合
- 口座に関する補足情報（口座の用途、契約情報など）を残したい場合
- カテゴリの運用ルールや説明をメモしたい場合
- 予算設定に関するメモを残したい場合

**主要な処理内容**：
1. ノートの作成・編集（Markdown形式対応）
2. ノートの表示（Markdownレンダリング）
3. ノートの保存（自動保存）
4. ノートのツールチップ表示
5. ノートの削除（空文字での保存）

**関連システム・外部連携**：
- Markdownパーサー（react-markdown、remark-gfm）
- Undo/Redo機能との連携

**権限による制御**：特別な権限制御はなく、予算ファイルにアクセス可能なユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | 予算画面（デスクトップ） | 主画面 | カテゴリへのメモ追加機能 |
| 12 | 口座一覧画面（デスクトップ） | 主画面 | 取引・口座へのノート追加 |
| 14 | 口座詳細画面（モバイル） | 参照画面 | モバイルでの取引ノート表示 |

## 機能種別

CRUD操作 / テキスト処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | ノート対象のエンティティID | 有効なUUID |
| note | string | Yes | ノート内容（Markdown形式可） | 空文字可（削除扱い） |

### 入力データソース

- 画面入力（Notes/NotesButtonコンポーネント経由）
- useNotes Hook経由での既存ノート取得

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| note | string | 保存されたノート内容 |
| renderedContent | ReactNode | Markdownレンダリングされたノート |

### 出力先

- ローカルストレージ（notesテーブル）
- 画面表示（Notesコンポーネント、ツールチップ）

## 処理フロー

### 処理シーケンス

```
1. ユーザーがノートボタンをクリック
   └─ NotesButtonコンポーネントがPopoverを開く

2. 既存ノートがあれば読み込み
   └─ useNotes Hookでノートを取得

3. ユーザーがノートを編集
   └─ textareaでMarkdown形式のテキストを入力

4. Popoverを閉じる際に自動保存
   └─ onOpenChange callbackでnotes-save APIを呼び出し

5. ノート表示（読み取りモード）
   └─ react-markdownでMarkdownをレンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ノートボタンクリック]
    B --> C{既存ノートあり?}
    C -->|Yes| D[useNotesで取得]
    C -->|No| E[空文字を初期値に]
    D --> F[Popover表示]
    E --> F
    F --> G[textarea表示（編集モード）]
    G --> H{ユーザー入力}
    H --> I[tempNotes状態更新]
    I --> J{Popover閉じる?}
    J -->|No| H
    J -->|Yes| K{内容変更あり?}
    K -->|Yes| L[notes-save API呼び出し]
    K -->|No| M[Popover閉じる]
    L --> M
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-62-001 | 自動保存 | Popoverを閉じる際に自動保存 | ノート内容に変更がある場合 |
| BR-62-002 | Markdownサポート | GitHub Flavored Markdown（GFM）をサポート | 表示時 |
| BR-62-003 | 外部リンク処理 | 外部リンクは新しいタブで開く（target="_blank"） | リンククリック時 |
| BR-62-004 | 空ノート処理 | 空文字はnullとして扱い、ノートなし状態となる | 保存時 |
| BR-62-005 | プレースホルダー表示 | 編集時は「Notes (markdown supported)」を表示 | 編集モード時 |

### 計算ロジック

特になし（テキスト保存・表示のみ）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ノート保存 | notes | UPDATE | ノート内容の保存・更新 |
| ノート取得 | notes | SELECT | IDに紐づくノートの取得 |

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

#### notes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | id | 対象エンティティID | 主キー |
| UPDATE | note | ノート内容（Markdown） | null可 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR-62-001 | 保存失敗 | データベース書き込みエラー | エラーログ出力、ユーザー通知 |

### リトライ仕様

リトライは実装されていない。エラー発生時はユーザーに通知。

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

ノートの保存は単一トランザクションで処理される。notes-save APIはmutatorでラップされ、Undo対応版（notes-save-undoable）も提供される。

## パフォーマンス要件

- ノート表示: 100ms以内
- ノート保存: 500ms以内
- Markdownレンダリング: 200ms以内

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

- ノートデータはローカルファイルに保存され、E2E暗号化の対象となる
- 外部リンクにはrel="noopener noreferrer"を付与してセキュリティ対策
- クラウド同期時は暗号化されて転送される

## 備考

- remarkGfm、remarkBreaks、sequentialNewlinesPluginプラグインを使用
- rehypeExternalLinksで外部リンクの安全な処理を実装

---

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

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

### 推奨読解順序

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

まず、ノートエンティティの型定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.ts | `loot-core/types/models/index.ts` | NoteEntity型の定義（id, note） |

**読解のコツ**: ノートはシンプルなid-noteペアのエンティティ。idは対象エンティティ（取引、口座、カテゴリなど）のIDを参照する。

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

処理の起点となるコンポーネントを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NotesButton.tsx | `packages/desktop-client/src/components/NotesButton.tsx` | ノートボタンコンポーネント、Popover制御 |

**主要処理フロー**:
1. **34-42行目**: NotesButtonPropsの定義（id, width, height, defaultColor等）
2. **44-46行目**: useRef, useState, useNotesの初期化
3. **49-50行目**: tempNotesの状態管理とuseEffectでの同期
4. **52-64行目**: onOpenChange - Popover閉じる際の保存処理
5. **67-73行目**: Tooltipでの既存ノート表示
6. **75-99行目**: Buttonのレンダリング（ノートアイコン表示）
7. **101-109行目**: Popoverでの編集UI

#### Step 3: 表示コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Notes.tsx | `packages/desktop-client/src/components/Notes.tsx` | ノート表示・編集コンポーネント |

**主要処理フロー（Notes.tsx）**:
- **14-20行目**: remarkPlugins設定（sequentialNewlinesPlugin, remarkGfm, remarkBreaks）
- **22-26行目**: markdownStylesのCSS定義
- **28-35行目**: NotesProps型定義
- **37-44行目**: Notesコンポーネント関数シグネチャ
- **50-54行目**: focused && editableの場合にfocus設定
- **56-72行目**: editable時のtextareaレンダリング
- **73-87行目**: 非editable時のReactMarkdownレンダリング

#### Step 4: サーバーサイド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | app.ts | `packages/loot-core/src/server/notes/app.ts` | ノートAPI実装 |

**主要処理フロー（app.ts）**:
- **7-10行目**: NotesHandlers型定義
- **12-14行目**: アプリケーション作成とメソッド登録
- **16-18行目**: updateNotes関数 - db.updateでnotesテーブルを更新

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

```
NotesButton (エントリーポイント)
    │
    ├─ useNotes(id) ──────────────┐
    │                             │
    ├─ useState(tempNotes)        │
    │                             ▼
    ├─ onOpenChange ───▶ send('notes-save', {id, note})
    │                             │
    │                             ▼
    │                    packages/loot-core/src/server/notes/app.ts
    │                             │
    │                             └─ db.update('notes', {id, note})
    │
    ├─ Tooltip
    │      └─ Notes (読み取りモード)
    │             └─ ReactMarkdown
    │
    └─ Popover
           └─ Notes (編集モード)
                  └─ textarea
```

### データフロー図

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

ユーザー操作 ─────────┐
(ノートボタンクリック) │
                     ▼
              ┌─────────────────┐
              │ NotesButton     │
              │ - useNotes(id)  │
              └────────┬────────┘
                       │
         ┌─────────────┴─────────────┐
         ▼                           ▼
┌─────────────────┐         ┌─────────────────┐
│ Tooltip表示     │         │ Popover表示     │
│ (読み取り専用)  │         │ (編集モード)    │
└────────┬────────┘         └────────┬────────┘
         │                           │
         ▼                           ▼
┌─────────────────┐         ┌─────────────────┐
│ Notes           │         │ Notes           │
│ (ReactMarkdown) │         │ (textarea)      │
└─────────────────┘         └────────┬────────┘
                                     │
                            ユーザー入力
                                     │
                                     ▼
                            ┌─────────────────┐
                            │ tempNotes更新   │
                            └────────┬────────┘
                                     │
                            Popover閉じる
                                     │
                                     ▼
                            ┌─────────────────┐
                            │ send('notes-save')│
                            └────────┬────────┘
                                     │
                                     ▼
                            ┌─────────────────┐
                            │ db.update       │
                            │ ('notes', ...)  │
                            └─────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Notes.tsx | `packages/desktop-client/src/components/Notes.tsx` | ソース | ノート表示・編集コンポーネント |
| NotesButton.tsx | `packages/desktop-client/src/components/NotesButton.tsx` | ソース | ノートボタン、Popover制御 |
| app.ts | `packages/loot-core/src/server/notes/app.ts` | ソース | ノートAPI実装 |
| useNotes.ts | `packages/desktop-client/src/hooks/useNotes.ts` | ソース | ノート取得Hook |
| markdown.ts | `packages/desktop-client/src/util/markdown.ts` | ソース | Markdownユーティリティ |
| models.ts | `loot-core/types/models/index.ts` | 型定義 | NoteEntity型 |
