
Actual 23.4.2 版本解析按命名计划自动预算、侧边栏浮动优化与服务端密码重置脚本【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actualActual 是一款本地优先local-first的个人财务管理应用23.4.2 是其 2023 年 4 月发布的一个维护型版本涵盖客户端Actual与服务端Actual Server两侧的改动。本文以官方发布说明 packages/docs/blog/2023-04-22-release-23.4.2.md 为主线结合当前仓库源码深入讲解「按命名计划named schedules自动写入预算模板」「侧边栏自动浮动行为改进」「撤销快捷键修复」「零值对账修复」「自动补全依赖清理」以及服务端「reset-password密码重置脚本」与「Nordigen 错误信息增强」等核心变更的实现原理与使用方式帮助读者理解这些更新背后的工程逻辑并直接上手实践。版本概览一个客户端与服务端同步发布的维护版本23.4.2 同时发布了客户端与服务端两个组件Docker 镜像标签为23.4.2组件版本变更类型Actual客户端23.4.21 个功能Feature、1 个增强Enhancement、2 个缺陷修复Bugfix、2 项维护MaintenanceActual Server服务端23.4.21 个功能、1 个增强整体上这是一次小版本迭代客户端聚焦预算模板与交互体验的打磨服务端则补上了一个此前缺失的运维能力——命令行重置密码。下文分别展开。客户端Actual 23.4.2变更详解按命名计划自动生成预算模板金额Feature #885本版本最重要的功能更新是预算模板Budget Template新增了schedule关键字可以按「命名计划」named schedule自动计算出当月应预算的金额该功能由社区贡献者 pole95 提交。在 Actual 的预算模板体系中每个模板行由类型type、指令directive、优先级priority等字段构成。schedule类型的模板行并不直接写死金额而是通过name或内部使用的scheduleId关联到一条已有的计划Schedule由预算引擎在运行时解析出金额。相关实现位于 packages/loot-core/src/server/budget/schedule-template.ts入口函数为runSchedule。从源码可以看到其核心计算流程按名称/ID 匹配计划通过template.scheduleId优先避免重命名破坏关联或template.name兼容旧数据查询schedules表中tombstone 0的活跃计划再经由getRuleForSchedule拿到该计划关联的规则从中提取日期条件与金额条件。计算单次金额从规则条件中提取金额若金额条件是区间isbetween则取两端平均值若模板配置了adjustment调整量与adjustmentType还会按百分比percent或固定值fixed对金额做修正——例如adjustment: 10, adjustmentType: percent表示在原金额基础上上浮 10%。区分「当月付清」与「沉没分摊」对于本月到期的计划pay-month-of即num_months 0且频率与间隔满足条件如每月一次、每周间隔 ≤ 4、每天间隔 ≤ 31直接预算全额对于更远的未来计划如年度账单则按getMonthlyBaseContribution/getSinkingContributionBreakdown进行跨月分摊sinking fund将目标金额按月拆解并优先用已有余额覆盖最近到期的计划。处理边界情况已完成的计划completed会被排除已经过去的非重复计划会记录Schedule xxx is in the Past错误周/日频率且间隔较大的计划按跨月月数折算。对应的单元测试覆盖了这些行为见 packages/loot-core/src/server/budget/schedule-template.test.ts例如月度重复计划直接预算全额金额为负时取正如-10000→ 预算10000年度计划配合已有余额时仅预算当月分摊额$1200的年度账单当月只需$1000full: true到期月一次性付清时不为未来月份预存资金percent/fixed两种调整方式分别得到11000与10500的结果多计划并存时按到期日排序让已有余额优先覆盖最早的账单。使用方式在预算模板中新增一行type 设为schedulename 填写要关联的计划的名称或使用内部 scheduleId引擎即会在每次运行模板时自动按计划金额与日期计算应预算值无需手工维护金额计划金额变动时模板自动跟随。改进侧边栏自动浮动行为Enhancement #868该版本优化了侧边栏的「自动浮动」auto-floating表现。在桌面端中侧边栏支持浮动模式floating sidebar相关组件位于 packages/desktop-client/src/components/sidebar其中FloatableSidebar在 packages/desktop-client/src/components/FinancesApp.tsx 中被挂载。侧边栏的浮动行为同时受两个因素控制见 packages/desktop-client/src/components/Titlebar.tsx用户偏好floatingSidebar通过useGlobalPref读取sidebar.alwaysFloats来自 packages/desktop-client/src/components/sidebar/SidebarProvider.tsx 的上下文状态。改进后的自动浮动逻辑让侧边栏在窗口宽度变化或用户展开/收起操作时能更平稳地在「固定」与「浮动」两种形态之间切换减少跳动与遮挡提升多窗口、窄屏场景下的使用体验。这是交互层的小步优化不影响数据与预算逻辑。修复撤销键盘快捷键失效问题Bugfix #926此前在某些场景下CtrlZmacOS 为CmdZ撤销快捷键会被忽略本版本修复了该问题。Actual 的撤销机制是「本地优先 服务端同步」架构下的关键能力撤销/重做并非简单操作 DOM 或组件状态而是通过向核心层发送undo/redo消息、回滚底层数据表变更实现的。相关实现见packages/desktop-client/src/undo/index.ts核心入口_undo throttle(() send(undo), 100)对undo消息做了 100ms 节流并通过_undoEnabled标志在特定场景下临时禁用撤销packages/desktop-client/src/hooks/useUndo.ts将撤销能力以 hook 形式注入页面组件packages/desktop-client/src/global-events.ts监听undo-event将撤销事件与标签undoTag状态路由到各页面监听器。修复前当焦点位于某些输入控件或撤销状态被节流窗口吞掉时快捷键事件可能无法正确触发undo()修复后撤销快捷键在更多交互场景下都能稳定响应配合界面右下角的撤销提示条undo notification使用体验更一致。修复零值预算的对账问题Bugfix #915该修复针对「对一个零值预算执行对账reconcile」时出现的异常。对账是 Actual 核对账户余额与账单一致性的核心功能其实现位于 packages/loot-core/src/server/accounts/app.ts其中reconcileTransactions负责将银行同步/导入的交易与现有交易重新匹配相关逻辑也有测试覆盖见 packages/loot-core/src/server/accounts/sync.test.ts。修复前当对账涉及的金额合计为零例如收支相抵或全部金额为 0 的批量操作时会触发除零或空值比较等边界问题修复后引擎能正确处理零值场景保证对账过程正常完成、余额状态一致。自动补全依赖清理Maintenance #916 / #924两个维护性 PR 完成了对旧自动补全autocomplete组件的收尾#916移除jlongster/lively依赖重构旧的自动补全组件使其不再依赖该库并禁用了新的自动补全#924进一步移除react-select及新自动补全组件。这说明 23.4.2 处在自动补全组件的新旧交替期旧实现被彻底清理新实现由后续版本基于组件库 packages/component-library 中的Select等组件重写暂时禁用。对普通用户而言此次清理减少了打包体积与运行时依赖属于纯工程性改进不改变功能行为。服务端Actual Server 23.4.2变更详解新增npm run reset-password脚本Feature #186这是本版本服务端最重要的运维能力补充通过一条命令即可设置或重置服务器登录密码解决了此前忘记密码后只能手工操作数据库的痛点。使用方式在 sync-server 目录下执行npm run reset-password脚本会自动判断当前状态并走两条分支尚未设置过密码首次初始化提示It looks like you dont have a password set yet. Lets set one up now!交互式输入新密码后完成初始化已设置过密码提示It looks like you already have a password set. Lets reset it!交互式输入新密码后完成重置并提醒所有已登录的浏览器与设备需要使用新密码重新登录。脚本实现见 packages/sync-server/src/scripts/reset-password.js它通过needsBootstrap()判断是否首次初始化分别调用 packages/sync-server/src/accounts/password.js 中的bootstrapPassword与changePassword。除了npm run reset-password服务端 CLI 还提供了等价的命令行参数形式见 packages/sync-server/bin/actual-server.jsactual-server --reset-passwordbin/actual-server.js通过 Node 内置的parseArgs解析--reset-password布尔参数命中后先动态加载../src/scripts/reset-password.js执行重置随后process.exit()不会启动同步服务。底层实现原理密码并非明文存储而是以 Argon2id 哈希保存。hashPassword使用如下参数见 packages/sync-server/src/accounts/password.js参数遵循 OWASP 密码存储建议const ARGON2_OPTIONS { type: argon2.argon2id, // Argon2id 变体 memoryCost: 47104, // 内存成本 46 MiB timeCost: 1, // 迭代次数 parallelism: 1, // 并行度 };同时兼容旧数据verifyPassword会先判断哈希前缀$argon2开头走 Argon2 校验否则回退到 bcrypt 比较bcrypt.compare保证升级前用 bcrypt 存储的密码仍可正常登录登录成功时还会将旧 bcrypt 哈希原地升级为 Argon2id 哈希见loginWithPassword中的isLegacyHash分支。两个关键安全细节空密码被拒绝isValidPassword拒绝null、undefined与空字符串bootstrapPassword与changePassword对空密码统一返回{ error: invalid-password }OpenID-only 实例保护如果实例启用了 OpenID 认证没有 password 认证方法changePassword会返回{ error: no-password-method }而不是静默成功且不会禁用已存在的 OpenID 方法——避免误操作破坏已有认证配置。这两点均有测试验证见 packages/sync-server/src/accounts/password.test.js。服务端 CLI 的完整参数表见 packages/sync-server/README.md如下参数说明-h/--help打印帮助信息并退出-v/--version打印版本号并退出--config指定配置文件路径--reset-password设置或重置服务器密码注意actual-app/sync-servernpm 包要求Node.js v22 或更高版本见 packages/sync-server/README.md。更清晰地报告 Nordigen 请求异常Enhancement #189Nordigen现 GoCardless Bank Account Data是 Actual 对接银行账户数据聚合的渠道之一。此前当 Nordigen 请求返回非预期状态码时报错信息较为模糊难以定位问题本版本增强了错误报告让失败请求的状态码与上下文信息更明确便于用户在银行同步失败时快速判断是凭证失效、账户被移除还是 API 侧限流。仓库中 Nordigen/GoCardless 相关实现位于 packages/sync-server/src/app-gocardless共 80 余个 TS 文件涉及账户授权、交易拉取、银行元数据等完整流程。该增强不改变同步功能本身只提升可观测性属于服务端的可维护性改进。小结Actual 23.4.2 是一个「稳中有进」的版本客户端为预算模板带来按命名计划自动预算的能力schedule模板关键字配合计划金额调整percent/fixed与沉没分摊逻辑让「计划驱动的预算」真正自动化同时打磨了侧边栏浮动交互修复了撤销快捷键与零值对账两个影响日常使用的缺陷并清理了旧的自动补全依赖服务端补齐了reset-password运维能力npm 脚本 --reset-password参数双入口基于 Argon2id 哈希并保持 bcrypt 向后兼容还内置了对 OpenID-only 实例的保护Nordigen 异常报告也得到增强。对于自托管用户升级到23.4.2后最值得立刻上手的功能就是npm run reset-password——从此忘记密码不再需要动数据库。对于开发者schedule模板的实现schedule-template.ts与密码管理实现password.js都是理解 Actual 预算引擎与认证体系的上佳入口配套的 schedule-template.test.ts 与 password.test.js 则直接给出了各种边界行为的行为契约。【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考