barnesy/strictly-spending

GitHub: barnesy/strictly-spending

一款本地优先的家庭支出看板,支持多银行 CSV 导入、自动分类、周期性扣款检测和支出预测,所有数据完全离线存储。

Stars: 2 | Forks: 0

# Strictly Spending 一款本地优先的家庭支出看板。支持多银行 CSV 导入、基于规则的自动分类、周期性扣款检测、各类别预算以及快速分拣的 **Sort** 视图,全部在浏览器中完成。**无需服务器。无需云端。无需账户凭证。** ![Strictly Spending 看板](https://raw.githubusercontent.com/barnesy/strictly-spending/main/docs/hero.png) ## 功能介绍 - **导入 CSV 导出文件**:支持 Chase、Bank of America(信用卡 + 借记卡)和 Truist。只需拖入文件,或指定一个文件夹,应用即可通过 File System Access API 自动检测新文件。借助 SHA-256 内容哈希,即使账单以不同名称被重新下载,也能实现去重。 - **自动分类**:通过按优先级排序的规则引擎实现自动分类,内置了约 150+ 种常见商户模式(NETFLIX、STARBUCKS、SHELL 等)。当没有规则匹配时,源 CSV 中的类别会通过每个银行专属的查找表进行标准化处理。 - **周期性扣款展示**:通过检测商户历史记录中的一致时间间隔(每月、每两周、每周、每年)来识别并展示周期性扣款。采用最近 3 次扣款的平均值,确保订阅档位的变化能在一个计费周期内同步更新。 - **下月支出预测**:将周期性支出(固定支出)与各类别预算(基于历史移动平均值)分开进行预测。你可以切换具体的周期性扣款或预算条目,从而模拟削减支出的效果。 - **Sort 视图**:将导入后令人头疼的“未分类”数据整理转变为卡片堆叠式的交互体验。只需对每个商户做出一次决定,即可对该商户过去的*所有*及*未来*交易进行批量分类。按 `Enter` 接受建议的类别,按 `1`–`9` 从网格中选择,按 `⌘Z` 撤销操作。 - **JSON 备份与恢复**:方便在不同浏览器间迁移数据,或在执行*清除站点数据*后恢复应用。采用单文件、纯 JSON 格式,无加密(请自行妥善存放)。 - **演示模式**:这是一个“设置”开关,可以隐藏真实数据,并在全应用范围内仅显示 `Demo:` 记录,非常适合用于截屏、演示或屏幕共享会议。 ## 隐私与数据 Strictly Spending 是一款本地优先的桌面应用程序。所有数据都存储在系统标准应用数据目录下的本地 SQLite 数据库(`spending-viz.sqlite`)中。 本应用绝不会使用您的财务数据发起任何网络请求。没有账户、无需登录,也不收集任何遥测数据。所有 CSV 导出文件均在客户端完成解析并直接写入数据库。若要备份数据或在多台设备间迁移数据,请使用导入页面上的 JSON Backup 工具。 ## 架构 Strictly Spending 采用了一种现代化的本地优先混合架构,结合了高性能的原生系统后端与功能丰富的 Web 前端: ``` graph TD subgraph Frontend (Vite + React + TS) UI[React Pages & Hooks] -->|Method Calls| API[API Wrapper] end subgraph IPC Bridge (Tauri v2) API -->|Invoke Command| TAURI[Tauri Command Router] end subgraph Backend (Rust + SQLite) TAURI -->|Invokes| COMMANDS[Rust Commands] COMMANDS -->|Connection Pool| RUSQLITE[rusqlite Database Layer] RUSQLITE -->|Read / Write| SQLITE[(spending-viz.sqlite)] end ``` ### 核心架构亮点: - **原生 Rust 后端**:基于 Tauri v2 构建并由 Rust 驱动。所有的数据库连接池、事务、迁移和数据变更均直接由 Rust 通过 `rusqlite` 处理,并辅以线程安全的连接锁。 - **轻量级 API 封装**:前端组件通过一个轻量且完全类型安全的 API 封装(`src/api.ts`)与后端进行交互,该封装直接映射到 Tauri IPC 命令,从而使前端包体积极为轻巧,且完全摆脱了繁重的 ORM 库。 - **事务安全性**:数据库的变更操作(插入、更新、批量处理)均在 Rust 端的符合 ACID 标准的 SQLite 事务中执行,即使在极高负载下也能确保数据库的一致性。 - **高保真测试**: - **单元测试**:在 Vitest 中针对 mock 配置或模拟的 API 边界运行。 - **E2E 集成测试**:在 Playwright 中使用 Chrome DevTools Protocol (CDP) 模式运行,以在 Windows 上原生测试已编译的 Tauri 应用程序。 ## 技术栈 - **后端**:**Rust** + **Tauri v2** + **rusqlite** (SQLite) - **前端**:**Vite** + **React 19** + **TypeScript** - **UI 与样式**:**MUI v7** + **MUI X Charts**(堆叠柱状图可视化)+ **react-resizable-panels** - **状态管理**:**Zustand**(管理筛选器、预测和 Sort 会话状态) - **解析器**:**PapaParse**(CSV 解析) ## 快速开始 构建并运行该桌面应用程序: ``` # 安装依赖 npm install # 在 Tauri dev mode 下运行 app npm run tauri dev ``` 随后打开 **Settings → Load demo data → Demo mode**,即可在不导入真实 CSV 文件的情况下探索应用各项功能。演示数据集涵盖了 3 个模拟账户在 5 个月内的数据,并包含真实的周期性与变动性支出模式。 ## 脚本命令 | 命令 | 描述 | |---|---| | `npm run dev` | 运行 Vite 开发服务器 | | `npm run build` | 编译 TypeScript 并构建生产环境 Web 资源 | | `npm run tsc` | 运行 TypeScript 类型检查(`tsc --noEmit`) | | `npm run test` | 运行 Vitest 单元测试 | | `npx playwright test` | 运行 Playwright E2E 测试(在 Windows 上使用 CDP 模式) | | `npm run tauri dev` | 以开发者模式运行 Tauri 应用程序 | | `npm run tauri build` | 将 Tauri 应用程序打包为生产环境安装程序 | ### 个人商户规则(私有,不提交至仓库) `src/seed.ts` 中的初始规则包经过了刻意的泛化处理,每个类别都包含许多备选项,因此任何单一品牌的存在都不会暴露规则配置者的个人信息。 如果你想在代码中添加自定义商户(例如特定的房东、健身房或当地餐厅),请复制以下模板: ``` cp src/seed.local.example.ts src/seed.local.ts ``` 编辑 `src/seed.local.ts` 并添加你的规则。该文件已被加入 `.gitignore`,因此仅会保留在你的本地计算机中。构建时,系统会自动将其 `LOCAL_RULES` 数组合并到初始规则包中(Vite 会在构建阶段解析这个可选导入)。 你也可以在运行时通过 **Sort** 或 **Rules** 页面添加商户;这些规则会存储在 SQLite 中。请使用导入页面上的 **Backup** 按钮在不同设备间保留这些配置。 ### 解析器与 E2E 测试 运行单元测试与集成测试: ``` # 运行单元测试 npm run test # 运行 E2E 测试(需要 tauri app 编译并启动) npx playwright test ``` 位于 `src/parsers/parsers.test.ts` 下的 CSV 解析器测试需要真实的银行导出文件作为测试固件。如果固件不存在,这些测试将被自动跳过。要在本地运行这些测试: ``` STRICTLY_SPENDING_FIXTURES=/path/to/bank-csvs npm run test ``` ## 项目结构 ``` strictly-spending/ ├── src-tauri/ Native Rust backend │ ├── Cargo.toml Rust dependencies (tauri, rusqlite, serde) │ └── src/ │ ├── lib.rs App entry point, state initialization, command routing │ ├── db.rs rusqlite schema setup and read-only commands │ ├── db_mut.rs rusqlite transaction-safe mutation commands │ └── db_extra.rs rusqlite auxiliary tables and commands ├── src/ React frontend │ ├── pages/ Top-level routes (Dashboard, Sort, Forecast, Rules, …) │ ├── components/ Reusable UI components (SortCard, SpendChart, …) │ ├── api.ts Tauri command invoke wrapper │ ├── testBridge.ts E2E test bridge for injecting mock data │ ├── main.tsx Frontend bootstrapper │ ├── categorize.ts Rule engine + merchantKey extraction │ ├── recurrence.ts Recurring-charge detection │ ├── forecast.ts Next-month projection (recurring + budgets) │ ├── seed.ts Default categories + rules │ ├── demoData.ts Synthetic demo dataset generator │ └── backup.ts JSON export / restore pipeline ├── e2e/ Playwright E2E specs and setup └── playwright.config.ts Playwright configuration (configured for CDP mode on Windows) ``` ## 许可证 MIT。详见 [LICENSE](LICENSE)。 本项目由 [Claude](https://claude.com/claude-code) 作为工程合作伙伴协助开发。相关开发工作流已在[案例研究](https://barnesy.me/strictly-spending.html)中详细记录。
标签:CSV处理, 个人理财, 可视化界面, 本地优先, 浏览器应用, 特征检测, 财务管理