Releases: NotWizard/HouseholdBalanceSheet
Release list
v0.6.0: 导入体验、更新稳定、数据修复
一次聚焦「数据录入体验」与「更新链路稳定性」的版本。
🎉 新功能
- CSV 导入预检结果新增「名称」列:行号、名称、动作、错误四列一目了然,解析失败的行也能看到名字,快速定位问题行
- 提交导入后出现明确的结果横幅:全部成功为绿色;部分失败为黄色并附错误明细下载入口;失败则显示红色原因提示
- 录入页删除条目新增二次确认弹窗:展示名称与金额并警示不可撤销,防止误点丢数据
✨ 改进
- 桌面更新链路全面加固:检查或下载中断后重启不再卡死;下载写盘失败不再可能打崩应用;网络挂死有超时兜底;安装更新时窗口不再冻结数秒
- 退出应用时后台服务会真正退出,不再残留进程占用数据库
- 应用日志文件自动截断在 5MB 以内
- 所有弹窗支持 Escape 键关闭
🐛 修复
- 修复周末或节假日的汇率被误标为当天精确值:汇率现在按数据的真实交易日记录
- 修复切换基准币种后历史汇总数据与新口径不一致的问题
- 修复同一 CSV 文件内重复条目会被重复导入的问题
- 修复风险分析页再平衡金额符号可能错标为 ¥ 的问题
- 修复录入表单「期望占比」按提示留空却被报错的问题
- 本版本还包含约 30 项稳定性与一致性修复,完整清单见 CHANGELOG
A release focused on data-entry experience and updater reliability.
🎉 New features
- The CSV import preview now shows a Name column: row, name, action, and error at a glance — even rows that failed parsing show their name so you can locate them fast
- After submitting an import, an explicit result banner appears: green on full success, amber with a downloadable error report on partial failure, and red with the failure reason on errors
- Deleting an entry now asks for confirmation first, showing its name and amount with an irreversibility warning to prevent accidental data loss
✨ Improvements
- The desktop updater is hardened end to end: interrupted checks or downloads no longer deadlock after a restart; download write failures can no longer crash the app; stalled networks now hit timeouts; and the window no longer freezes for seconds while installing
- The background service now truly quits when the app quits, leaving no orphan processes holding the database
- Application logs are automatically capped at 5MB
- All dialogs can be closed with the Escape key
🐛 Bug fixes
- Fixed weekend and holiday exchange rates being mislabeled as exact same-day values: rates are now recorded under their actual trading date
- Fix switching the base currency leaving historical summary data inconsistent with the new unit
- Fix duplicate entries within one CSV file being imported twice
- Fix rebalance amounts on the risk view potentially showing the wrong currency symbol
- Fix the entry form rejecting an empty target ratio despite the hint saying it is allowed
- This release also includes around 30 additional stability and consistency fixes; see the CHANGELOG for the full list
v0.5.0:手动更新、可靠安装、完整提醒
现在可以在应用内主动掌握更新时间,同时保留原有的自动更新保障。
🎉 新功能
- 设置页新增“软件更新”板块。可以随时检查正式版更新,查看最新版本、发布日期和官方发布说明,再自行决定何时下载。
- 检查到新版本后,更新流程会按“下载更新 → 安装并重启”分步进行。下载进度会持续显示,安装前仍会再次确认,避免误触导致应用突然退出。
- 自动更新继续在后台提供兜底。如果更新已经由后台开始下载,设置页会直接显示同一份进度,不会重复下载。
✨ 改进
- 主动检查现在会明确显示“已是最新版”或网络暂时不可用,并记录最近检查时间。
- 下载、校验和安装失败会提供对应的重试入口,已下载好的有效更新不会因再次检查而丢失。
🐛 Bug 修复
- 修复 macOS 上旧更新暂存目录包含特殊应用文件时,点击“立即升级并重启”没有反应的问题。现在会可靠清理旧暂存内容;清理失败时也会明确提示,而不是静默停住。
- 再平衡提醒继续使用 5% 偏离阈值,但不再只展示前六项。所有超过阈值的项目都会完整显示。
You can now choose when to check, download, and install updates while keeping the existing automatic-update safety net.
🎉 New features
- Settings now includes a Software Update section. You can check for stable releases at any time, review the latest version, publication date, and official release notes, then decide when to download.
- Available updates follow a clear “Download update → Install and restart” flow. Download progress remains visible, and installation still requires confirmation so an accidental click will not suddenly close the app.
- Automatic updates continue to work in the background. If a background download is already running, Settings shows the same progress instead of starting a duplicate download.
✨ Improvements
- Manual checks clearly report whether the app is current or the update service is temporarily unavailable, together with the most recent check time.
- Download, validation, and installation failures now provide the appropriate retry action, and a valid downloaded update is preserved across later checks.
🐛 Bug fixes
- Fixed “Install and restart” appearing unresponsive on macOS when an older update staging folder contained special application files. The app now clears stale staging content reliably and shows an actionable error if cleanup fails.
- The rebalance threshold remains 5%, but the Overview no longer stops after six alerts. Every item beyond the threshold is now displayed.
v0.4.1: 圆环图标签优化 / Donut chart label improvement
Patch release fixing label overlap in analytics donut charts.
🐛 Bug fixes
分析看板币种总览圆环图标签重叠:当某币种下资产或负债构成包含多个小占比项目时,原有标签和引导线会彼此重叠。现在布局引擎会先尝试纵向错开标签,空间仍不足时自动隐藏重叠的标签——完整数据不出现在图表标签上,但始终可通过图例和 Tooltip 查看。
Analytics currency donut chart label overlap: when a currency's asset or liability breakdown includes many small-share items, the previous layout let labels and guide lines collide. The improved layout now shifts labels vertically first, then hides remaining overlaps — data not shown on chart labels is always accessible via the legend and tooltip.
v0.4.0: 再平衡建议、清晰提示、可靠汇总 / Rebalance Guidance, Clear Tooltips, Reliable Totals
本次更新让再平衡建议更可执行,并修复录入提示和迁移后总览数据的显示问题。
🎉 新功能
- 再平衡提醒现在会显示当前金额、目标金额,以及建议增持或减持的金额,方便直接判断下一步操作。
- 目标占比为
0%或未设置的资产不会影响其他资产的建议;当某位成员的目标占比合计不是100%时,界面会明确提示差额并暂停给出调仓金额,避免误导。 - 总览页和分析看板都会展示新的金额建议;“一键归一化”只调整已设置正目标占比的资产。
[📷 Screenshot: 总览页中的再平衡金额建议]
🐛 Bug 修复
- 修复新增资产或负债时,分类、金额和期望占比说明在弹窗边缘被截断的问题;提示现在会自动调整方向并保持完整可见。
- 修复导入迁移包后,资产明细已经恢复,但总览净资产、总资产、总负债和趋势仍显示为零的问题。
This update makes rebalance guidance directly actionable and fixes clipped entry guidance and incorrect Overview totals after migration imports.
🎉 New features
- Rebalance alerts now show current amounts, target amounts, and suggested buy or sell amounts so the next action is clear.
- Assets with a
0%or unset target no longer distort guidance for other assets. If a member's targets do not total100%, the app shows the gap and pauses adjustment amounts instead of presenting misleading advice. - The new amount guidance appears on both Overview and Analytics, while one-click normalization only adjusts assets with positive targets.
[📷 Screenshot: Rebalance amount guidance on Overview]
🐛 Bug fixes
- Fixed category, amount, and target-ratio guidance being clipped near the edges of the asset and liability entry dialog. Tooltips now reposition automatically and remain fully visible.
- Fixed Overview net assets, total assets, total liabilities, and trend values remaining at zero after a migration import restored the holdings.
v0.3.3: 外币录入、清晰图表、稳定体验 / Currency Entry, Clear Charts, Stable Experience
本次更新集中修复外币录入、家庭资产负债图展示,以及总览页网络波动时的提示。
🐛 Bug 修复
- 新建美元等外币资产时,汇率优先从中国外汇交易中心获取,并在主来源不可用时自动切换备用来源,改善中国大陆网络环境下的可用性。
- 所有汇率来源暂时不可用时,界面现在显示明确的网络错误,不再出现无法理解的 JSON 解析提示。
- 家庭资产负债桑基图现在完整显示末级分类名称,并让同一父分类的子项保持相邻,减少交叉连线。
- 总览页后台刷新失败但仍有历史数据时,会继续展示最近一次成功结果并明确提示当前状态。
This update focuses on foreign-currency entry, clearer household balance-sheet charts, and better feedback during network interruptions.
🐛 Bug fixes
- Creating USD and other foreign-currency assets now uses China Foreign Exchange Trade System data first and automatically falls back to a secondary source, improving availability for users in mainland China.
- When every exchange-rate source is temporarily unavailable, the app now shows a clear network error instead of an obscure JSON parsing message.
- The household balance-sheet Sankey chart now shows complete final-category labels and keeps children of the same parent together, reducing crossing flows.
- If an Overview refresh fails while previous data is available, the app keeps the last successful result visible and clearly explains its status.
v0.3.2
Fixed
- 修复桌面端左下角在 GitHub API 限速(HTTP 403)或网络抖动时误显"更新失败,重试"按钮。当前已是最新版本时,网络类检查失败会静默降级到上一次成功结论,不再把错误状态持久化到
state.json反复打扰用户;下载 / 校验 / 安装阶段的真实失败仍保留显眼重试入口,并按失败类型细分文案(下载失败 / 校验失败 / 安装失败)。同时加入陈年 error 状态 1 小时 TTL 自动复位、连续失败 4h/24h 退避轮询、旧 state.json 字段向后兼容推断,避免重启后旧错误残留。 - Fix the desktop update notice incorrectly showing "更新失败,重试" in the bottom-left when GitHub Releases API is rate-limited (HTTP 403) or the network is flaky. When the app is already on the latest version, network-class check failures now silently fall back to the last successful conclusion instead of persisting an error state in
state.jsonand pestering the user across restarts. Real failures in the download / validation / install stages still surface a prominent retry entry with error-kind-specific labels (download / validation / install). Also added: 1-hour TTL auto-reset for stale error states, 4h/24h backoff polling on consecutive failures, and backward-compatible inference of new fields in oldstate.jsonfiles so stale errors don't linger after upgrade.
v0.3.1: 桌面更稳、首屏更快、安装更顺
距上次发版四个月,重点修掉了 macOS 安装与启动的一连串卡点,并把分析看板和后端常用操作都跑得更快。
⚠️ Heads-up
- v0.3.1 此前发布过一个无法启动的版本,已被本版覆盖。如已安装旧版,请先把 Applications 里的旧版拖到废纸篓再装新版,否则单实例锁会让新版直接退出。
- macOS 首次启动会被 Gatekeeper 拦「未知开发者」。在 Applications 中右键 → 打开即可放行,或执行一次
xattr -cr /Applications/HouseholdBalanceSheet.app清掉隔离属性。 - 升级不会影响已录入的资产负债数据,本地数据库位置保持不变。
🎉 New features
- 桌面端会记住主窗口上次关闭时的位置和尺寸,下次启动自动还原;外接屏拔掉或窗口落到屏幕外时回退到默认居中。
- macOS 休眠唤醒后自动探活本地服务,若已退出会静默重启,不再需要手动关掉重开。
- 启动失败页面新增「打开日志目录」按钮,一键拿到 main 与后端日志反馈给开发者。
- 分析看板的时间段、视图模式、选中币种现在跨刷新和重启都会保留。
✨ Improvements
- 分析看板首屏明显更快:长表格滚动不再卡顿、图表按需加载、常用数据缓存命中率提升。
- 千行 CSV 导入预检从约 10 秒降到半秒内,汇率刷新和每日快照写入也都更快。
- 桌面端启动更顺滑:消除首次打开的白屏闪烁,加载页出现更早。
- DMG 安装包更小(约减少 8–15 MB),下载和安装时间都缩短。
🐛 Bug fixes
- 修复 macOS DMG 安装后双击启动直接崩溃的问题,现在装好即可正常打开。
- 修复打开几秒后弹出黄色「正在连接本地服务」、随后变成红色 401 报错的连环误报;总览页没有数据时改为友好的灰色「暂无总览数据」占位卡。
- 修复 DMG 安装窗口布局杂乱:去掉侧栏和系统隐藏文件,呈现干净的背景图 + 应用图标 + Applications 快捷方式。
- 修复按
Cmd+R刷新后变成ERR_FILE_NOT_FOUND白屏的问题,现在能正常刷新并停在当前页面。 - 修复更新包下载中断后被误判为「已下完」反复重下的问题,现在校验通过才会替换旧版本。
- 修复成员管理与录入页空状态文案在卡片中未居中的小瑕疵。
下载
HouseholdBalanceSheet-0.3.1-macos-arm64.dmg(Apple Silicon)HouseholdBalanceSheet-0.3.1-macos-x64.dmg(Intel)
v0.3.0
概述
v0.3.0 是一次全栈性能批次升级:照着 docs/plans/2026-05-22-performance-improvement-plan.md 三档 21 条全部落地,主线四件事:
- 前端首屏与渲染:bundle 从 227 KB 拆到 37 KB(vendor chunk 独立 + 首页换轻量 SVG),编辑录入页不再每键全树重渲染
- 后端 hot path:snapshot 构建 N+1 消除、FX 同步阻塞 30 s 改异步、分析端点加进程级缓存
- 桌面冷启动:daily snapshot 改 daemon 线程不再卡
/health,loading 页接真实 backend stage - 数据模型清理:新增
daily_totalsslim 表为未来轻量端点铺路,去掉无消费方的 event snapshot 双写让单次编辑后端 IO 减半
每条改动独立 commit 独立测试,共 22 个 commit。后端 98/101 通过、前端 76/76 全过、桌面 67/67 全过(3 个 fail 全部在 v0.2.0 baseline 同样 fail,与本次性能改动无关)。
主要变更
1. 前端首屏与 bundle 体积
index.js从 227 KB 缩到 37 KB(gzip 73 → 13):vite.config.ts拆出react-vendor(react + react-dom + react-router-dom + @tanstack/react-query)+icons-vendor(lucide-react)两个独立 chunk。业务代码迭代时 vendor 不变,用户增量下载只命中差量- 首屏 LCP 路径剥离 ~600 KB echarts:
OverviewPage趋势图换成新写的纯 SVGSparklineTrend(~120 行,含三条折线 / 端点圆点 / 渐变面 / 图例 / 起止日期),不再触发echarts-core(436 KB) +zrender(173 KB) +echarts-react(17 KB) 链下载。分析看板仍用完整 ECharts - ECharts 增量 setOption:去掉
notMerge: true(之前每次 option 引用变化都重建实例),6 个 chart 组件补全useMemo包buildXxxOption,ResizeObserver加requestAnimationFrame合批。切换 analytics 日期范围 / 滚动 / 勾选 / 输入不再触发图表抖动
2. React Query 缓存与 re-render
- 拆 holding mutate invalidate 范围:原一条编辑触发 8 个 query key 失效,分析 6 个重端点并发雪崩。缩到核心 2 个 key(
holdings.all()+analyticsDateBounds.all()),分析端点统一加staleTime: 30s,用户切回分析页才自然 stale 重 fetch;新增invalidateAllHoldingDependentQueries给 CSV import / bulk delete 等真正大批量场景 - 合并 settings 缓存 key:原 OverviewPage / AnalyticsPage / EntryPage 三处用
settings.scope('xxx')切成 3 份独立缓存,跨页切换重复 fetch;统一改settings.all()共享一份 - AnalyticsPage 加
placeholderData: keepPreviousData:5 个 date-range 分析 query 在日期切换时不再回退 Skeleton 闪屏,旧数据占位过渡到新数据 - EntryPage / EntryHoldingsTable 渲染重做:模块级
EMPTY_HOLDINGS/EMPTY_MEMBERS常量替代?? []稳定引用;buildGroups加useMemo;GroupBlock包React.memo;handler 全部useCallback锁;keyword 输入用useDeferredValue让 input 立即响应,过滤计算延后
3. 后端 hot path
- snapshot 构建消除 N+1:
_build_snapshot_payload原每条 holding 跑 3 次session.get(Category)= 40 条 holding 120 次单查;改一次SELECT ... WHERE id IN (...)批量预取,DB 往返 -90%+。被 trend / sankey / rebalance / currency-overview 与每次 holding 写路径反复调用 - FX
resolve_rate_for_pair同步阻塞 30 s 改异步:原汇率缺失时同步调refresh_rates()(httpx 5s × 3 retries × 2 providers = 最长 30 s 阻塞);改为「exact → 历史 fallback(is_estimated)+ 后台 daemon 线程 refresh → 真冷启动才同步」三段。录入新币种 P99 延迟从 30 s 降到 ~100 ms build_daily_series进程级缓存:trend / volatility / correlation 三端点同 cold load 反序列化 N 天 payload 3 次;现共享 LRU cache(max 32 entries),版本指纹由(MAX(snapshot_date), COUNT, MAX(holdings.updated_at))自动失效- currency-overview 改读 latest snapshot:跟 sankey / rebalance 一致,不再调
build_current_payload重新跑全表 SELECT + N+1 get_default_family+ tz + sankey member name 三处合并优化:前两者加Session.info级缓存(请求生命周期内复用),sankey member 改单条 IN(...) batch 替代 N 次get_scoped_member
4. 桌面冷启动与运行时
- daily snapshot 改 daemon 线程异步执行:原
bootstrap_runtime同步跑create_daily_snapshot,/health在快照写完前不返回 200,Electron loading 页要等这一步。改异步后桌面冷启动 -1 ~ -3 s - loading 页接真实 backend stage:原 1700 ms fake 轮播假进度,跟 backend ready 节奏脱钩。现在主进程通过
webContents.executeJavaScript推送真实文案(「正在等待本地服务就绪」/「正在加载主界面」),fake 仅作为兜底 - 更新下载进度节流 250 ms:原每个 chunk 都触发
state.jsonfsync + IPC 广播,100 MB 包对应 20-1600+ 次写盘;节流后写盘 -95%+,更新期间 UI 流畅 BackgroundScheduler1 worker + lazy 实例化:APScheduler 默认 10 worker,常驻 ~20 MB 内存白付;本项目只有两个 job 互不并发,限到 1 worker;模块 import 时不再立即实例化
5. 数据模型清理
- 新增
daily_totalsslim 表:alembic migration 创建 + 一次性回填存量snapshot_daily.payload_json.totals;create_daily_snapshot双写。snapshot_daily 仍是 holding 粒度真理源,新表给未来 totals-only 端点(如轻量净资产趋势)提供不必反序列化的快路径 - 去掉 holding mutate 时的 event snapshot 双写:grep 全仓库无任何前端 / 脚本消费
/api/v1/snapshots/events,是写而不读的纯历史记录。_refresh_snapshots改为只刷 daily snapshot;高价值事件(CSV import / settings 改 base_currency)仍由 import_service / settings_service 显式写。单条 holding mutate 后端 IO -50% - 新增 metadata-only summary 端点:
/api/v1/snapshots/events/summary与/snapshots/daily/summary不反序列化 payload_json(events 返 4 个 metadata 字段、daily 直接读daily_totals新表),相同 limit 下响应体积 -95%。旧端点保留向后兼容
6. 构建与打包
- PyInstaller bundle 瘦身:
backend/build_desktop.py加--exclude-module列表(watchfiles / tkinter / unittest / test / pytest / _pytest / setuptools),DMG 估计 -10 ~ -30 MB,冷启动 import -0.5 ~ -1.5 s
收益对照表(可验证)
| 指标 | Before | After | 验证点 |
|---|---|---|---|
Bundle index.js |
227 KB / 73 KB gzip | 37 KB / 13 KB gzip | M5 build 输出 |
| 首屏 LCP 必下载 | ~860 KB / ~230 KB gzip | ~250 KB / ~80 KB gzip | M6 OverviewPage 不再 import echarts |
| 单条 holding 编辑后端 IO | 2× JSON + 2× INSERT | 1× JSON + 1× INSERT | L3 _refresh_snapshots 去 event 写 |
| 单条 holding 编辑前端请求 | 8 个 query invalidate | 2 个(holdings + dateBounds) | Q2 拆 invalidate 范围 |
_build_snapshot_payload DB 往返 |
3N 次 | 1 次 IN 预取 | Q5 N+1 修复 |
| FX 新币种 P99 | 最长 ~30 s | ~100 ms | Q6 异步化 |
桌面冷启动 /health |
含 1-3 s 同步 daily snapshot | 不卡 | Q7 异步化 |
| 更新下载 IO/IPC | 每 chunk 1× fsync + 1× IPC | 每 250 ms ≤1 次 | Q8 节流 |
| Snapshots list 响应 | 几 MB(含全 payload) | summary 端点 -95% | L5 metadata-only |
| Scheduler 常驻 worker | 10 | 1 | M8 |
升级说明
- 存量用户:alembic migration 自动创建
daily_totals新表 + 回填存量数据;event snapshot 表保留不动,老数据完整可读;分类与 holdings schema 完全不变。无需手动操作 - 开发期:删
backend/data/app.db不再必要(migration 自动升级);如需重建,bootstrap仍会写入方案 D 树 - 桌面端:v0.2.0 用户启动后自动检测、后台静默下载,点击通知确认即可升级(流程跟 v0.2.0 一致,无需 Gatekeeper 二次授权)
构建产物
- macOS arm64:
HouseholdBalanceSheet-0.3.0-macos-arm64.dmg - macOS arm64:
HouseholdBalanceSheet-0.3.0-macos-arm64.zip
Overview
v0.3.0 is a full-stack performance batch: every one of the 21 items in docs/plans/2026-05-22-performance-improvement-plan.md lands across all three tiers (Quick Wins / Medium / Large). Four main threads:
- Front-end first-paint and render: the bundle's
index.jsdrops from 227 KB to 37 KB (vendor chunks split off, the home page replaces ECharts with a lightweight SVG), and the entry page no longer re-renders the whole tree on every keystroke - Backend hot paths: snapshot N+1 elimination, FX 30-second sync block turned async, analytics endpoints get a process-level cache
- Desktop cold start: the daily snapshot moves off the lifespan thread so
/healthno longer waits for it; the loading page now reflects real backend stages - Data-model cleanup: a new
daily_totalsslim table prepares for future lightweight endpoints, and the no-consumer event-snapshot dual-write is removed, halving the backend IO per holding mutation
Every item lands as its own commit with its own tests — 22 commits in total. Backend tests 98/101 pass, frontend 76/76, desktop 67/67 (the three failures all reproduce on v0.2.0 main and are unrelated to this batch).
Highlights
1. Front-end first-paint and bundle size
index.jsfrom 227 KB to 37 KB (gzip 73 → 13):vite.config.tscarves outreact-vendor(react + react-dom + react-router-dom + @tanstack/react-query) andicons-vendor(lucide-react) into independent chunks. On subsequent releases vendors stay cached and users only download the diff- First-paint LCP path sheds ~600 KB of ECharts:
OverviewPage's trend chart is replaced by a hand-rolledSparklineTrendSVG (~120 lines: three lines, endpoint dots, gradient area fill, legend, date range), no longer pulling inecharts-core(436 KB) +zrender(173 KB) +echarts-react(17 KB). The analytics dashboard still uses the full ECharts - ECharts switches to incremental
setOption: dropsnotMerge: true(which forced a fresh instance on every option reference change); the six chart components all gainuseMemoaroundbuildXxxOption; theResizeObservercallback is now batched throughrequestAnimationFrame. Switching analytics date ranges, scrolling, toggling checkboxes and typing no longer cause chart redraw jitter
2. React Query cache and re-render
- Shrink holding-mutation invalidate scope: each single-row edit used to invalidate 8 query keys, firing 6 heavy analytics endpoints in parallel. Now invalidates only the two essentials (
holdings.all()+analyticsDateBounds.all()); analytics queries share a 30 sstaleTimeso they re-fetch naturally on next mount. A newinvalidateAllHoldingDependentQueriescovers genuinely wholesale paths (CSV import, bulk delete) - Unify the
settingscache key: previously three pages usedsettings.scope('xxx')and split the same response into three caches, repeating the fetch on every page switch. Now all three sharesettings.all() - AnalyticsPage uses
placeholderData: keepPreviousData: the five date-range driven queries no longer fall back to Skeleton on every range change; the previous response stays visible until the new one arrives - EntryPage / EntryHoldingsTable render overhaul: module-level
EMPTY_HOLDINGS/EMPTY_MEMBERSconstants replace?? []for reference stability;buildGroupsis memoised;GroupBlockis wrapped inReact.memo; handlers areuseCallback-stable; keyword input flows throughuseDeferredValueso typing stays smooth
3. Backend hot paths
_build_snapshot_payloadN+1 fix: previously calledsession.get(Category)three times per holding — 40 holdings = 120 single-row lookups. Now oneSELECT ... WHERE id IN (...)batch prefetch, ~90% fewer DB round-trips. Ca...
v0.2.0
概述
v0.2.0 是面向「易用性 + 数据模型」的一次较大升级,主线四件事:
- 资产负债分类体系整体换上方案 D(10 资产 + 6 负债,三层扁平),删除会计余孽,独立出「数字资产 / 退休与长期账户 / 保险账户」三大类
- 资产负债录入对话框换上全新
CategoryTreePicker,把原「类型 + 三级分类路径」两个字段合并为「tab + 面包屑 + 搜索 + 自动穿透」的渐进式选择 - 修了一批长期视觉 / 交互瑕疵(弹窗遮罩漏顶、Select 箭头贴边、分类面板被 viewport 裁等)
- 新增 GitHub Actions release workflow,往后
git push tag v*即可自动构建并发布 release
主要变更
1. 资产负债分类体系(方案 D)
- 资产从原 7 大类(现金与存款 / 稳健投资 / 权益投资 / 保障与储备 / 不动产 / 实物资产 / 经营与往来)重组为 10 大类:现金存款类 / 固定收益类 / 权益与另类 / 数字资产 / 退休与长期账户 / 保险账户 / 不动产 / 车辆 / 其他实物 / 经营资产
- 负债从原 6 大类(房屋相关负债 / 消费负债 / 车辆及耐用品负债 / 经营负债 / 投资杠杆负债 / 往来及其他负债)重组为 6 大类:住房负债 / 经营负债 / 消费负债 / 车辆与耐用品负债 / 投资杠杆负债 / 亲友借款
- 删除家庭场景用不上的「应收资产 / 其他应付款」等会计概念
- 黄金账户型走「权益与另类 / 另类投资 / 贵金属账户」,金条实物走「其他实物 / 贵金属与珠宝 / 黄金实物」,资产形态清晰分流
2. 录入对话框 CategoryTreePicker
- 合并原「类型(资产/负债)+ 三级分类路径」为一个控件,dialog 内只占一行
- 点开后含:顶部
资产 (10) / 负债 (6)tab → 面包屑「全部 › L1 › L2 ›」(每段可点回退)→ 搜索框(输入即跳出面包屑模式,L1/L2/L3 任一段命中均出)→ 当前层列表(每次只面对 ≤10 项) - 二级若只含 1 个三级会自动穿透到三级,少一击
- 面板展开时自动
scrollIntoView,让「分类」label 紧贴 dialog 头部,最大化展示组件全貌
3. Dialog / Select 视觉与交互修复
Dialog改用createPortal渲染到document.body,修了遮罩没遮全侧边栏 + 主内容顶部 padding 区的 bugDialog改为flex max-h-[85vh] flex-col+ 内部overflow-y-auto+ footer 固定底部,长内容自身可滚、操作按钮始终可见Select箭头全系统统一:appearance-none隐藏浏览器默认箭头 + 自绘 lucideChevronDown绝对定位,告别 Chrome/Safari 紧贴右边缘的丑陋默认样式
4. 分析看板视觉收紧
- 各图表 ECharts grid 内边距收紧,消除卡片左 / 底 / 桑基两侧的大块灰白留白
- 「风险与配置」tab 三卡片重排:波动率 + 相关性矩阵同行(两者高度都有上限),再平衡提醒独占下排全宽
- 相关性矩阵加方阵守卫(
max-width = height + 160),N×N 单元格在两个方向接近正方形
5. 录入页「目标占比配平」面板
- 改为按需折叠的紧凑信号面板:全部成员达标的稳态下整块零高度,出现未达标 / 超出时才自动展开
- 单卡瘦身(去掉装饰性大号
100.0%副标):高度从 ~120 px → ~62 px,宽屏一排能塞更多成员
6. 桌面应用 / 构建
- 自动更新链路改为「后台静默下载 + 用户单次确认升级」,含 macOS
xattr -dr com.apple.quarantine剥离,免 Gatekeeper 二次授权 - macOS DMG 打包改用
hdiutil自制,绕过maker-dmg → electron-installer-dmg → appdmg → macos-alias在新 Node 上的 native binding 编译问题 - 新增
.github/workflows/release.yml:on push tagv*自动在macos-latest上构建 arm64 DMG/ZIP 并发布 release,release notes 自动从 CHANGELOG 抠取 - 应用图标重做为符合 Apple HIG 的双蓝 H 标志
升级说明
- 存量用户:旧 holding 的
(l1Id, l2Id, l3Id)在新分类树里 row 仍存在(FK 约束未破坏)但对应的分类名字已变,感知到的是「分类被全部重命名」。建议升级后检查一次每个 holding 的分类归属是否仍合适 - 开发期:删
backend/data/app.db后首次启动,让bootstrap重写入方案 D 树 - 桌面端:v0.1.3 用户启动后会自动检测、后台下载,点击通知确认即可升级,无需 Gatekeeper 二次授权
构建产物
- macOS arm64:
HouseholdBalanceSheet-0.2.0-macos-arm64.dmg(145 MB) - macOS arm64:
HouseholdBalanceSheet-0.2.0-macos-arm64.zip(147 MB)
Overview
v0.2.0 is a substantial UX + data-model upgrade with four main threads:
- The household asset/liability taxonomy is wholesale-replaced by Scheme D (10 asset roots + 6 liability roots, fully flat three-level), with accounting-flavoured leftovers dropped and "Digital assets / Retirement & long-term accounts / Insurance accounts" promoted to first-class roots.
- The entry form dialog gets a brand-new
CategoryTreePickerthat merges the previous "type + three-level category path" fields into a progressive picker (tab + breadcrumb + search + auto-penetration). - A batch of long-standing visual / interaction defects are fixed along the way (dialog overlay clipping, native select caret hugging the edge, popover clipped by viewport, …).
- A new GitHub Actions release workflow now builds and publishes releases automatically on every
v*tag push.
Highlights
1. Taxonomy (Scheme D)
- Asset side regroups from 7 roots (cash & deposits / stable investments / equity investments / insurance & reserves / real estate / physical assets / business & receivables) into 10 roots: cash deposits / fixed income / equity & alternatives / digital assets / retirement & long-term accounts / insurance accounts / real estate / vehicles / other physical / business assets
- Liability side regroups from 6 roots into 6 new roots: housing / business / consumer / vehicle & durables / investment leverage / personal loans from friends and family
- Accounting-flavoured "receivables" (asset side) and "other payables" (liability side) — which households don't really use — are dropped
- Account-type gold lives under "equity & alternatives / alternatives / precious-metal accounts", physical bullion under "other physical / precious metals & jewelry / physical gold"
2. CategoryTreePicker on the entry dialog
- Merges the previous "type (asset/liability) + three-level category path" into a single one-row control
- On open, the panel shows: an
Asset (10) / Liability (6)tab at the top → a clickable breadcrumb (全部 › L1 › L2 ›, each segment can re-pick) → a search box (typing leaves breadcrumb mode, matches any L1/L2/L3 segment) → the current level's list (always ≤10 items) - An L2 with exactly one L3 child auto-penetrates to the L3, saving one click
- Opening the panel auto-scrolls the "分类" label up to the dialog header, maximising how much of the picker fits in the viewport
3. Dialog / Select fixes
Dialognow renders throughcreatePortaltodocument.body, fixing the backdrop that previously left the sidebar and the main content's top padding strip unmaskedDialogbecomesflex max-h-[85vh] flex-colwith aflex-1 overflow-y-autobody and a sticky footer — long content scrolls internally and the action buttons stay visible- The system-wide
Selectcaret is unified:appearance-nonehides the browser default, a self-drawn lucideChevronDownis absolutely positioned — no more Chrome/Safari arrows glued to the right edge
4. Analytics dashboard polish
- ECharts grid paddings tightened across charts to eliminate the visible grey bands on card left / bottom / sankey sides
- The "Risk & Allocation" tab is rearranged: volatility + correlation matrix share the upper row (both have height caps), the unbounded rebalance reminder owns the full-width lower row
- The correlation matrix gains a square-aspect guard (
max-width = height + 160), keeping N×N cells near-square in both directions
5. Entry page "target-ratio rebalancing" panel
- The overview becomes a need-based compact signal panel: when every member is balanced the whole section collapses to zero height; it auto-expands only when someone goes under or over
- Each mini card slims down from ~120 px to ~62 px tall (dropping the decorative
100.0%headline), and a wider screen fits more members per row
6. Desktop app / build
- The auto-update flow is reshaped into "silent background download + single user-confirmed upgrade", with
xattr -dr com.apple.quarantinestripped on macOS so Gatekeeper no longer asks for re-authorization - The macOS DMG step switches to
hdiutil, dodgingmaker-dmg → electron-installer-dmg → appdmg → macos-aliasnative bindings that fail to compile on newer Node - New
.github/workflows/release.ymlbuilds an arm64 DMG/ZIP onmacos-lateston everyv*tag push, then publishes the release with notes auto-extracted from CHANGELOG - The app icon is redesigned to a dual-blue "H" mark following Apple HIG
Upgrade notes
- Existing users: a holding's
(l1Id, l2Id, l3Id)still resolves in the new tree (FK is intact) but the resolved names have shifted, so users perceive it as "categories were renamed". Recommend a one-pass review after upgrading to confirm each holding still sits where it should - Dev environment: delete
backend/data/app.db, then letbootstrapreseed the Scheme D tree on next startup - Desktop: v0.1.3 users will auto-detect and background-download; clicking the notice once confirms the upgrade, no Gatekeeper re-authorization required
Artifacts
- macOS arm64:
HouseholdBalanceSheet-0.2.0-macos-arm64.dmg(145 MB) - macOS arm64:
HouseholdBalanceSheet-0.2.0-macos-arm64.zip(147 MB)
v0.1.3
更新内容
- 完成剩余整改清单,收口 family scope 错误语义、桌面更新链路、preload bridge 能力边界、前端行为测试与后端阶段化流程。
- 将
CLAUDE.md纳入版本控制,补齐仓库级协作说明。 - 将桌面与前端版本提升到
0.1.3,并修复 macOS 发布脚本固定使用本地 Electron Forge CLI,避免npx意外回退到旧版。
构建产物
- macOS arm64: DMG 与 ZIP
- macOS x64: DMG 与 ZIP
验证
cd frontend && node --test tests/*.test.tsnpm --prefix frontend run buildnode --test desktop/tests/*.test.tsnpm --prefix desktop run typechecksource .venv/bin/activate && python -m pytest backend/tests -qnpm --prefix desktop run make:dmg