你好,我是测试蔡坨坨。
上一篇文章里,我介绍了 Claude Code 的基本使用方式 :从安装、对话,到让 AI 直接在终端里修改代码。同时,还做了一个简单的记账软件作为 demo,不过当时更多只是演示流程,记的是“流水账”。
这篇文章,我们来做一次更 真实、更完整的实践 :
用 Claude Code 从零搭建一个服务于 Beancount 的个人记账 Web 应用 。
在开始之前,其实还有几篇背景文章可以一起看看,算是这篇实践的基础铺垫:
为什么要记账?
什么是复式记账?
Beancount 复式记账的基本概念和账本结构
如何用 Python 自动解析微信、支付宝账单 CSV,并生成 Beancount 格式的交易记录
有了这些基础之后,一个新的问题就出现了:
在日常记账时,如何更方便地录入和维护 Beancount 的账务数据?
这篇文章,我们就用 Claude Code,一步一步把这个问题变成一个可以真正使用的 Web 工具。
背景
Beancount 是一套基于 纯文本文件 的复式记账系统。它的核心理念很简单:所有账务数据都保存在普通文本中,每一笔交易都必须满足严格的借贷平衡原则 。
相比 Excel 或各种商业记账 App,Beancount 有几个很明显的优势:
数据自主 :账本就是本地文件,不依赖任何云服务
版本控制友好 :天然适合用 Git 管理,所有修改历史都清晰可追溯
可编程 :由于是纯文本结构,可以用 Python、Shell 等任何语言进行处理和自动化
复式记账模型 :每笔交易都包含借方和贷方,财务结构更严谨,也更容易做统计分析
不过,Beancount 本身其实只是一个 命令行工具 ,主要负责解析账本、校验借贷是否平衡,以及生成各种报表,并没有自带完整的图形界面。
官方提供的 Web 界面工具叫 Fava ,可以用来浏览账本、查看报表和分析资产变化。
Fava 的局限性
Fava 提供了相当完善的报表和可视化能力,但在日常使用中,还是会遇到一些不太顺手的地方:
移动端体验不佳
Fava 的界面主要是为桌面端设计的,在手机上操作时,页面布局会显得拥挤,录入和修改数据都比较麻烦。
新增交易不够友好
添加一笔交易时,需要手动编写完整的 Beancount 语法,没有表单式的引导,对于日常快速记账来说不太方便。
无法直接编辑余额断言
balance 断言(用于记录账户在某一时间点的余额)通常分散在不同文件中。每次对账时,都需要手动找到对应文件并修改内容,过程比较繁琐。
理财记录管理不方便
像基金收益、利息收入这类周期性或重复性记录,在 Fava 中没有专门的录入方式,往往还是需要手动编辑账本文件。
账单导入工具与界面割裂
比如账单解压密码、对账日期等信息,通常写在独立的 Python 脚本里,与 Fava 的界面没有任何关联,整个流程比较分散。
这些痛点让日常记账的摩擦成本变高 。
于是我决定用 Claude Code 从零做一个 专门服务于 Beancount 数据文件的轻量级 Web 应用 ,把这些高频操作集中到一个简单的界面里,让日常记账变得更顺手。
技术选型
核心挑战:浏览器如何读写本地文件?
传统的 Web 应用如果需要访问本地文件,通常必须通过后端服务来完成。但这样一来,就会引入服务器部署、接口维护等额外复杂度,这和 Beancount 本地账本的理念其实是相违背的 。
好在现代浏览器已经提供了 File System Access API ,允许网页在用户授权后,直接读写本地文件系统,这正好契合我们的使用场景。// 用户授权选择目录 const handle = await window.showDirectoryPicker({ mode: 'readwrite' }); // 读取文件 const fileHandle = await dirHandle.getFileHandle('2.bean'); const file = await fileHandle.getFile(); const content = await file.text(); 复制代码 用户只需要 首次选择账本所在目录并授权 ,页面就可以直接读取和修改其中的 .bean 文件。
为了避免每次打开页面都重新授权,可以把目录句柄(FileSystemDirectoryHandle)保存到 IndexedDB 中。这样在下次访问页面时就可以自动恢复权限,无需重复选择目录。
技术栈
整体技术方案尽量保持 简单、轻量、本地优先 :
层级选型框架React 18 + TypeScript构建工具Vite图表Chart.js样式原生 CSS(CSS Variables)本地存储File System Access API + IndexedDB整个应用 没有后端、没有数据库、也没有任何云服务依赖 。
所有数据都直接存储在本地的 Beancount 账本文件 中,Web 应用只负责读取、解析和编辑这些文件。
这也意味着:
只要有浏览器,就能随时打开账本进行管理。
功能介绍
1. 目录管理与权限持久化
首次使用时,用户需要通过文件选择器授权 Beancount 账本所在的目录 。应用会将获得的目录句柄保存到 IndexedDB 中,之后再次打开页面时即可自动恢复权限,无需每次重新授权。
同时也支持 随时切换目录 ,如果有多套账本(例如个人账本、家庭账本等),可以在不同目录之间自由切换。
2. 记账流水查看
应用会按照 年月维度 展示当月的所有交易记录,并支持在不同月份之间快速切换。
为了让流水一眼可读,每条记录都会根据账户类型显示不同颜色:
蓝色 :转账(Assets → Assets)
红色 :支出(Expenses)
绿色 :收入(Income)或退款
其中 退款 是一个特殊场景:当贷方账户以 Expenses: 开头时,会被识别为退款,而不是收入。这样处理后,退款金额会 从支出中扣除,而不会被统计为收入 。
3. 新增交易(引导式表单)
针对 Beancount 复式记账 的特点,新增交易时设计成分层引导的方式,减少手写语法的成本。
第一层:交易分类预设
提供四种常见类型:
选择后会自动填充借贷方账户的默认结构。
第二层:模板快捷选择
在分类下会显示常用模板,例如:支出类:餐饮、交通、购物、娱乐... 收入类:工资、公积金、年终奖... 转账类:微信转账、支付宝转账... 还款类:信用卡还款... 复制代码 选择模板后,付款账户、借贷账户以及备注信息都会自动填充,大幅减少重复输入。
为了方便后续精确删除,每一笔交易写入文件时都会附带一个 内联 ID :2026-03-10 * "XXX有限公司" "三月工资" ; id: abc123xyz Assets:Current:Wechat:Wallet 3000.00 CNY Income:Salary -3000.00 CNY 复制代码
4. 会计恒等式展示
页面 Header 中常驻展示经典的 会计恒等式 :资产 + 费用 = 负债 + 所有者权益 + 收入 复制代码 这是 Beancount 复式记账的核心约束,通过持续展示这个公式,也在提醒账务结构始终保持逻辑闭环。
5. 余额断言编辑( assert.bean)
balance 断言是 Beancount 的重要对账机制,用于记录某一天各账户的真实余额,例如:2026-03-04 balance Assets:Current:Wechat:Wallet 0.00 CNY ;微信钱包 2026-03-04 balance Assets:Current:Wechat:MiniFund 153061.40 CNY ;零钱通 2026-03-04 balance Assets:Current:Bank:CMB8721 1678.37 CNY ;招商银行卡 2026-03-04 balance Liabilities:JDBaitiao -0.00 CNY ;京东白条 复制代码 应用为此提供了专门的编辑界面:
统一日期 :所有断言共享同一个对账日期,一处修改即可全部更新
逐行金额编辑 :每个账户都有独立输入框,资产类与负债类用不同颜色区分
符号保护 :负债账户的 - 前缀是 Beancount 的借贷约定,无法修改,只允许编辑数值部分
保存时会 精确保留原文件的列对齐格式 ,避免破坏账本结构。
6. 理财收益管理(Investments.bean)
针对定期收益类记录(例如货币基金或银行活期理财),应用提供了单独的管理界面。内置常见模板,例如:
微信零钱通收益 2026-03-03 * "零钱通收益" "202603" Assets:Current:Wechat:MiniFund 00.00 CNY Income:Investments -00.00 CNY 复制代码 主要功能包括:
按收益类型分组展示,清晰区分不同来源
新增记录时,账单期默认填入当月(例如 202603)
支持 年份切换 ,方便查看历史收益
为了避免误操作,这个界面 不提供删除功能 。如果确实需要删除,可以直接编辑原始文件。
7. 账单导入工具集成
配套提供了一个 Python 脚本,用于从 QQ 邮箱自动下载支付宝和微信账单 ZIP 文件并解压 。Web 应用也为这个脚本提供了辅助管理界面。
密码管理
支付宝和微信账单的解压密码会定期更换,因此可以直接在界面中修改。应用会通过正则替换 Python 文件中的对应变量:self.alipay_zip_password = '' self.wechat_zip_password = '' 复制代码 已对账日期
应用会自动扫描 data/bank_statements/ 目录中的支付宝账单文件名,例如:支付宝交易明细(20260304-20260311).csv 复制代码 并解析出最新对账日期,展示为:运行脚本
提供一键复制命令到剪贴板:cd /path/to/beancount-importer && python -m src.main 复制代码 由于浏览器的安全限制,网页无法直接执行本地进程,因此采用 复制命令 → 用户在终端执行 的方式作为中转。
8. 自定义 Toast 通知
应用统一替换了浏览器原生的 alert / confirm 弹窗,改为自定义 Toast 通知组件 :
支持 info / success / error / confirm 四种类型
全局单例,通过函数式调用:toast('操作成功', 'success')
删除等敏感操作使用 toastConfirm,避免原生对话框打断页面体验
这样既保持了交互的一致性,也让整体 UI 更加流畅自然。
小结
整个应用 没有任何后端,也没有数据库 ,所有数据都直接存储在本地的 Beancount 账本文件 中。
其中:
File System Access API 解决了浏览器读写本地文件的问题
IndexedDB 用于持久化目录句柄,避免每次都重新授权
通过这两项能力,就可以在浏览器里实现一个真正 本地优先(local-first) 的 Web 应用。
对于有一定技术背景、同时使用 Beancount 管理个人财务 的人来说,这套工具链提供了一种比 Fava 更贴近日常操作习惯的方式。它并不是要取代 Fava 强大的报表与分析能力 ,而是作为一个 专注于数据录入和维护的前端工具 ,与 Fava 形成互补。
而 Beancount 最迷人的地方依然没有改变:
所有数据始终是纯文本。
这意味着:
任何时候都可以直接打开文件查看或修改
可以用 Git 进行版本管理
可以用任何编程语言进行自动化处理
数据不会被锁在某个应用或平台里,这正是 纯文本记账最大的魅力 。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
相关推荐