# 非機能要件定義書

## 概要

本ドキュメントは、Actual Budget（ローカルファースト個人財務管理システム）の非機能要件を定義したものです。デスクトップアプリケーション（Electron）、Webクライアント、同期サーバーの3つのコンポーネントで構成されるシステムにおける性能、可用性、セキュリティ、拡張性、保守性、運用・監視に関する要件を記載しています。

## 性能要件

### レスポンスタイム

| 処理種別 | 目標値 | 備考 |
| --- | --- | --- |
| 画面表示 | 3秒以内 | 開発モードでは3秒の待機後にロード開始 |
| API応答 | 1秒以内 | 同期サーバーのレートリミット内での応答 |
| 同期サーバー起動 | 20秒以内 | `SYNC_SERVER_WAIT_TIMEOUT`で定義 |
| OpenID認証タイムアウト | 20秒以内 | `custom.setHttpOptionsDefaults`で設定 |
| OpenID認証リクエスト有効期限 | 5分（300秒） | `pending_openid_requests`のexpiry_time |

### スループット

| 項目 | 目標値 | 備考 |
| --- | --- | --- |
| レートリミット | 500リクエスト/分 | 本番環境のみ適用（`rateLimit`設定） |
| ファイルアップロード上限（JSON） | 20MB | `upload.fileSizeLimitMB`デフォルト値 |
| 同期ファイル上限 | 20MB | `upload.fileSizeSyncLimitMB`デフォルト値 |
| 暗号化同期ファイル上限 | 50MB | `upload.syncEncryptedFileSizeLimitMB`デフォルト値 |

### リトライ設定

| 項目 | 設定値 | 備考 |
| --- | --- | --- |
| 開発サーバー接続 | 自動リトライ | `promiseRetry`使用、3秒後に開始 |
| ディレクトリ移動クリーンアップ | 最小200ms、最大500ms、係数1.25 | `promiseRetry`設定 |

## 可用性要件

| 項目 | 目標値 | 備考 |
| --- | --- | --- |
| 稼働率 | 明示的な定義なし | ローカルファーストアーキテクチャによりオフライン動作可能 |
| 計画停止時間 | 明示的な定義なし | ローカルで動作するため停止時間の影響は限定的 |
| 障害復旧時間（RTO） | 明示的な定義なし | ローカルデータによる即時復旧が可能 |
| 目標復旧時点（RPO） | 明示的な定義なし | 同期機能により最新の同期時点まで復旧可能 |
| ヘルスチェック | `/health`エンドポイント | ステータス"UP"を返却 |
| メトリクス | `/metrics`エンドポイント | メモリ使用量、アップタイムを返却 |

### 冗長構成

- ローカルファーストアーキテクチャ：オフラインでの動作をサポート
- 同期サーバーはオプション：クライアント単独で動作可能
- デスクトップアプリ内蔵同期サーバー：`syncServerConfig.autoStart`で自動起動可能

## セキュリティ要件

### 認証・認可

| 項目 | 設定値 | 備考 |
| --- | --- | --- |
| サポート認証方式 | password, header, openid | `allowedLoginMethods`で設定 |
| パスワードハッシュ | bcrypt（コストファクタ12） | `bcrypt.hashSync(password, 12)` |
| トークン有効期限 | never / openid-provider / 数値（分） | `token_expiration`で設定 |
| OpenIDデフォルト有効期限 | 10分 | プロバイダ未指定時のデフォルト |
| セッション管理 | DBベースのセッショントークン | UUIDv4で生成 |
| PKCE対応 | S256チャレンジ方式 | OpenID認証で使用 |

### Electronセキュリティ

| 項目 | 設定 | 備考 |
| --- | --- | --- |
| Node Integration | 無効 | `nodeIntegration: false` |
| Context Isolation | 有効 | `contextIsolation: true` |
| Web Security | 有効 | `webSecurity: true` |
| 実験的機能 | 無効 | `experimentalFeatures: false` |
| 安全でないコンテンツ実行 | 禁止 | `allowRunningInsecureContent: false` |
| WebView | 完全無効化 | `event.preventDefault()`で阻止 |
| ナビゲーション | 制限 | 外部URLは外部ブラウザで開く |
| パーミッション | file://のみ許可 | `setPermissionRequestHandler`で制御 |
| ディレクトリトラバーサル対策 | パス検証 | `startsWith(clientBuildPath)`チェック |

### HTTPS対応

| 項目 | 設定 | 備考 |
| --- | --- | --- |
| HTTPS証明書 | 環境変数で設定可能 | `ACTUAL_HTTPS_KEY`, `ACTUAL_HTTPS_CERT` |
| 自己署名証明書 | サポート | `NODE_EXTRA_CA_CERTS`経由で設定 |

### セキュリティヘッダー

| ヘッダー | 値 | 備考 |
| --- | --- | --- |
| X-Powered-By | 無効 | `app.disable('x-powered-by')` |
| Cross-Origin-Opener-Policy | same-origin | WebフロントエンドのCOOP |
| Cross-Origin-Embedder-Policy | require-corp | WebフロントエンドのCOEP |

### プロキシ信頼設定

| 項目 | デフォルト値 |
| --- | --- |
| 信頼されたプロキシ | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7, ::1/128 |
| 認証用信頼プロキシ | 空（設定時はtrustedProxiesにフォールバック） |

### リダイレクトURL検証

- サーバーホスト名またはlocalhostのみ許可
- `isValidRedirectUrl`関数で検証

## 拡張性要件

### モジュラーアーキテクチャ

- **monorepoワークスペース構造**：packages配下に複数パッケージ
  - `@actual-app/api`：外部API
  - `@actual-app/web`：Webフロントエンド
  - `@actual-app/sync-server`：同期サーバー
  - `loot-core`：コアビジネスロジック
  - `desktop-electron`：デスクトップアプリ
  - `component-library`：UIコンポーネント
  - `crdt`：CRDT同期プロトコル

### プラグインアーキテクチャ

- `plugins-service`パッケージによるプラグイン管理
- CORSプロキシによるフロントエンドプラグイン対応（`corsProxy.enabled`）

### 設定の外部化

- 環境変数による設定（`convict`ライブラリ使用）
- `config.json`ファイルによる設定
- 設定スキーマによるバリデーション（`validate({ allowed: 'strict' })`）

### ビルド設定

- ビルドメモリ上限：8GB（`NODE_OPTIONS=--max_old_space_size=8192`）

## 保守性要件

### コード品質

| 項目 | ツール/設定 |
| --- | --- |
| リンター | oxlint（ESLint代替） |
| フォーマッター | oxfmt |
| 型チェック | TypeScript（strict mode対応） |
| pre-commit | husky + lint-staged |
| テストフレームワーク | vitest, playwright |

### TypeScript設定

- 複数ビルドターゲット（browser, desktop, api）
- 厳格モードプラグイン（`typescript-strict-plugin`）

### データベースマイグレーション

- `migrate`ライブラリによるマイグレーション管理
- up/downコマンドによる双方向マイグレーション

### ロギング

- `winston`によるサーバーロギング
- `express-winston`による自動リクエストロギング
- `debug`モジュールによる開発時デバッグログ
- 機密情報用の分離デバッグログ（`actual-sensitive:config`）

## 運用・監視要件

### エンドポイント

| エンドポイント | 用途 | レスポンス |
| --- | --- | --- |
| `/health` | ヘルスチェック | `{ "status": "UP" }` |
| `/metrics` | メトリクス取得 | `{ "mem": {...}, "uptime": ... }` |
| `/mode` | 動作モード確認 | "test" または "development" |
| `/info` | アプリ情報 | パッケージ名、説明、バージョン |

### プロセス管理

- Docker環境でtiniを使用（シグナル処理の適正化）
- 非rootユーザーでの実行（UID/GID: 1001）
- unhandledRejectionのキャプチャとログ出力

### 開発環境

- `nodemon`による自動再起動（`start-monitor`）
- 開発モードでのレートリミット無効化

### デスクトップアプリ監視

- 電源管理イベント（suspend）のログ記録
- ウィンドウ状態（unresponsive）の検出
- サーバープロセスの標準出力/エラー出力のキャプチャ

### コンテナ設定

| 項目 | 値 |
| --- | --- |
| ベースイメージ | node:22-bookworm（ビルド）、node:22-bookworm-slim（実行） |
| 公開ポート | 5006 |
| 実行ユーザー | actual (UID 1001) |
| データディレクトリ | /data |

## 備考

### 動作環境要件

| 項目 | 要件 |
| --- | --- |
| Node.js | >=22 |
| Yarn | ^4.9.1 |
| Electron | >=35.0 |
| ブラウザ | defaults（browserlistによる） |

### ローカルファースト特性

- すべてのデータはローカルに保存
- 同期サーバーはオプション機能
- オフライン動作が完全にサポートされている
- CRDTベースの同期による競合解決
