一个记账小程序,为什么要做出云端 + 本地两条腿
「记账tracker」是一个投资持仓记账与复盘工具,支持 A股/港股/美股等多市场记账,从买入、减仓到平仓统计胜率、最大盈亏、平均持有天数。做到后期,一个问题冒出来:同一套记账逻辑,要不要只做一个云端小程序就完事?最后的答案是"不够"——于是做成了云端小程序 + 开源本地桌面版两个形态,外加一层独立的数据同步服务和一个 MCP 只读分析接口。这篇记录这几个设计决策背后的取舍。
01为什么云端小程序不是唯一形态
持仓记账这类数据,天然比"待办清单"敏感得多——它间接暴露一个人的资产规模和交易行为。云端小程序(微信云开发 + 云函数 + MongoDB)解决的是"多端同步、随时随地记"的需求,但一定会有一部分用户,宁可牺牲多端同步,也要"数据不上云"。这两种需求没有对错,只是取向不同,硬凑成一个产品体验只会两头都不讨好。
所以决定拆成两个独立形态:
- 云端小程序 —— 微信生态内即用即走,数据存在云端,换手机不丢数据
- 本地桌面版 —— Tauri 2.2 + Next.js 15 + Rust 构建,数据存在本地 SQLite,完全离线,开源 MIT 协议
两者记账模型是一致的,但桌面版不依赖任何云端账号体系,装完就能用,卸载就是彻底清除,这条隐私主张对部分用户是刚需。
02云端版不甘心只做"记账本":脱离小程序云环境,接一层独立的数据同步服务
云端小程序跑在微信云开发环境里,数据结构、访问方式、账号体系都是绑定小程序生态的。但后续想做的 AI 辅助分析,需要一个能被 Claude Desktop 这类通用 MCP 客户端直接连接的数据层——如果这层也架在微信云函数上,整个服务就会跟微信生态死死绑在一起,脱离不了。于是选择另起一套独立服务:把数据同步一份出来,让这层分析能力不依赖、不绑定任何单一平台。于是加了一层同步:
每次持仓变动(买入/减仓/平仓)都会生成一条同步事件,推给 Ingest 服务落库。这一层设计上有两个必须解决的问题:
- 身份鉴权 —— 用 HMAC-SHA256 对请求签名,接收端验证签名合法性才接受写入,避免接口被伪造请求打穿
- 幂等与乱序 —— 每条事件带唯一
event_id,重复推送直接去重;同时用业务时间字段(数据在源端的更新时间)而不是网络到达时间做比较,避免网络抖动导致的乱序请求覆盖新数据
03MCP 只读分析:让 AI Agent 看得到数据,动不了数据
Postgres 副本落地之后,上面架了一个远程 MCP Server,对外提供统计类的只读接口——持仓概览、盈亏统计、已平仓交易分析这些。用户可以拿到自己的 API Key,在 Claude Desktop 这类支持 MCP 的客户端里连上,直接用自然语言问"我这个月哪几笔亏得最多""胜率趋势怎么样",不需要自己写 SQL 或者切回小程序里翻数据。
这一层的关键设计原则是只读:MCP 接口不提供任何写入或修改操作,AI Agent 能看到统计结果,但没有能力反向修改持仓记录。分析和记账两件事,权限上必须分开,这也是为什么"分析"要单独接一层 MCP,而不是让小程序云函数直接兼职做这件事——一旦分析接口和记账接口共用一套权限,出问题时排查和收权限都会麻烦得多。
04两个形态、一层同步,分别解决什么
回头看整体架构,四层各自的职责很清楚:
- 微信小程序 —— 日常记账入口,即用即走
- 数据同步(HMAC 鉴权) —— 把云端数据安全地镜像一份到独立的托管服务,供 AI 侧使用
- Postgres 副本 + 远程 MCP —— 面向 AI Agent 的只读分析层
- 本地开源桌面版 —— 完全独立的离线路径,不经过前三层
这套架构没有哪一层是"顺手加的",每一层都是为了回应一个具体的用户诉求:多端同步、AI 辅助复盘、数据隐私。做个人项目最容易犯的错是"技术上能做就都做上",但这里每加一层复杂度之前,都先问了一句:这一层解决的是谁的问题——答案模糊的部分,就先不做。
如果你也在做类似的多端同步、数据架构设计,或者想接 MCP 给自己的产品加 AI 分析能力,可以聊聊。
聊聊你的想法 →