news 2026/9/11 17:32:59

Actual 26.3.0 版本解析:同步服务器安全修复、Tags API、命令栏报表与 React Query 性能迁移

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Actual 26.3.0 版本解析:同步服务器安全修复、Tags API、命令栏报表与 React Query 性能迁移

Actual 26.3.0 版本解析:同步服务器安全修复、Tags API、命令栏报表与 React Query 性能迁移

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

本文基于 Actual 开源仓库 v26.3.0 发布说明 编写,并结合仓库源码(API 层、loot-core 服务端、测试用例)对各项变更进行深度解读,帮助读者理解本次版本更新的安全优先级、新能力与底层实现。

Actual 26.3.0 是一次以"安全优先、体验提质、性能筑基"为基调的例行版本更新。本次版本包含一个面向所有同步服务器(sync server)用户的重要安全修复,官方建议尽快升级;同时为用户带来命令栏直达报表、银行同步账户关联体验改进、Tags 标签管理 API、自定义主题体系简化等多项新特性,并持续推进从 Redux 到 React Query 的大规模状态管理层迁移。

本文将从升级说明、安全修复、Tags API、报表入口、银行同步、主题体系、性能迁移等多个维度,逐项解析 v26.3.0 的变更内容,并给出对应的源码路径与测试证据,方便开发者按图索骥、深入验证。

版本信息与升级建议

发布说明开篇即点明本次更新的核心优先级:

This release contains an important security fix for all users of the sync server. We suggest you update as soon as feasible.

  • Docker Tag:26.3.0
  • Version:v26.3.0
  • 发布形式:月度例行版本(对应仓库 packages/docs/blog 下的 release 系列文档)

如果你通过 Docker 部署同步服务器,直接拉取26.3.0标签的镜像即可完成升级;桌面端用户则等待各平台(Windows/macOS/Linux/Flathub)构建产物发布。由于涉及安全修复,升级优先级应高于普通功能版本。

同步服务器安全修复与基础设施修复

v26.3.0 是少数在发布说明开头就明确标注"重要安全修复"的版本。结合仓库源码,本次与同步服务器健壮性直接相关的修复包括:

  • 校验文件 ID 的正确性(PR #7067):文件 ID(fileId)是同步服务器区分不同预算文件的标识。此前未对传入的 file ID 做格式校验,存在被构造畸形 ID 干扰服务器逻辑的风险;本次更新补充了正确性校验,从源头拦截非法输入。
  • 阻止单斜杠路径被解析为文件路径(PR #6966):同步服务器在解析请求路径时,/这类单斜杠路径此前可能被误当作文件路径处理,导致路径解析行为异常。修复后此类路径不再被错误解析。
  • 同步服务器迁移改用 ESM loader(PR #6346):同步服务器在启动时执行数据库迁移脚本,此前在部分运行环境下迁移加载方式有兼容性问题,本次统一改为 ESM loader,保证迁移可靠执行。
  • 修复 Windows 上运行服务器迁移失败的问题(PR #7076):迁移脚本在 Windows 平台的文件处理路径上存在缺陷,本次修复后跨平台部署一致性得到保障。

此外,发布说明还提到若干非安全类基础设施修复:send函数现在会正确传播错误,catchErrors在浏览器服务器收到未知命令/方法时会把错误写入结果(PR #6942);预算切换时 React Query 缓存未清空的问题得到修复(PR #6953)。

从源码结构看,同步服务器的安全与迁移逻辑集中在 packages/sync-server 目录(如app-sync.tsmigrations.tsapp.ts),上述修复正是围绕该服务端的请求处理与迁移链路展开。

Tags 标签管理 API:四个方法的完整链路

v26.3.0 为 API 新增了完整的标签管理能力(PR #6746),对外暴露getTagscreateTagupdateTagdeleteTag四个方法。这是本次版本中可编程能力提升最显著的一块,也是 API 使用者可以直接上手的新能力。

客户端 API 层:方法签名

在 packages/api/methods.ts 中,四个方法通过send命令映射到服务端 handler:

export function getTags() { return send('api/tags-get'); } export function createTag(tag: Omit<APITagEntity, 'id'>) { return send('api/tag-create', { tag }); } export function updateTag( id: APITagEntity['id'], fields: Partial<Omit<APITagEntity, 'id'>>, ) { return send('api/tag-update', { id, fields }); } export function deleteTag(id: APITagEntity['id']) { return send('api/tag-delete', { id }); }

对应实体类型定义在 packages/loot-core/src/server/api-models.ts:

export type APITagEntity = Pick< TagEntity, 'id' | 'tag' | 'color' | 'description' >; export const tagModel = { toExternal(tag: TagEntity): APITagEntity { return { id: tag.id, tag: tag.tag, color: tag.color ?? null, description: tag.description ?? null, }; }, fromExternal(tag: Partial<APITagEntity>): Partial<TagEntity> { return tag; }, };

可见标签实体的四个对外字段为:id(标签 ID)、tag(标签名称)、color(颜色,可为null)、description(描述,可为null)。toExternal会把内部模型中的可选字段统一归一化为null,保证 API 输出的字段类型稳定。

服务端 Handler 层:命令路由与事务包装

在 packages/loot-core/src/server/api.ts 中,四个api/tags-*命令完成参数校验(checkFileOpen)后转发给标签应用层:

handlers['api/tags-get'] = async function () { checkFileOpen(); const tags = await handlers['tags-get'](); return tags.map(tag => tagModel.toExternal(tag)); }; handlers['api/tag-create'] = withMutation(async function ({ tag }) { checkFileOpen(); const result = await handlers'tags-create'; return result.id; }); handlers['api/tag-update'] = withMutation(async function ({ id, fields }) { checkFileOpen(); await handlers'tags-update' }); }); handlers['api/tag-delete'] = withMutation(async function ({ id }) { checkFileOpen(); await handlers'tags-delete'; });

写操作(create/update/delete)统一由withMutation包装,纳入同步变更流(对应 loot-core 的 mutation 机制),保证本地与云端数据一致性。

标签应用层:排序、去重与幂等

标签的真正业务逻辑在 packages/loot-core/src/server/tags/app.ts,该文件定义了完整的TagsHandlers(包括tags-gettags-createtags-updatetags-delete,以及内部使用的tags-renametags-discovertags-hide-all等):

export type TagsHandlers = { 'tags-get': typeof getTags; 'tags-create': typeof createTag; 'tags-delete': typeof deleteTag; 'tags-delete-all': typeof deleteAllTags; 'tags-hide-all': typeof hideAllTags; 'tags-unhide-all': typeof unhideAllTags; 'tags-update': typeof updateTag; 'tags-rename': typeof renameTag; 'tags-discover': typeof discoverTags; };

值得注意的实现细节:

  • 排序getTags使用Intl.Collatornumeric: true, sensitivity: 'base')对标签按名称做自然排序,数字与字母混合的标签名能按直觉排列。
  • 幂等创建createTag会先查询同名字标签,若已存在同名标签则复用其 ID(返回已有id),避免重复创建。
  • 同步与撤销:写操作经mutator(undoable(...))包装,既进入同步消息流,又支持撤销操作,与 UI 中的标签编辑体验保持一致。

测试用例:可直接运行的验证示例

API 测试位于 packages/api/methods.test.ts,覆盖了完整的生命周期,可直接作为使用范例:

// 创建标签 const tagId1 = await api.createTag({ tag: 'test-tag1', color: '#ff0000' }); const tagId2 = await api.createTag({ tag: 'test-tag2', description: 'A test tag', }); // 查询标签 let tags = await api.getTags(); // 更新标签(可只更新单个字段,其余保持不变) await api.updateTag(tagId1, { tag: 'updated-tag', color: '#00ff00' }); // 删除标签 await api.deleteTag(tagId2);

测试还专门验证了三种边界行为,对实际调用很有参考价值:

  • 最小字段createTag({ tag: 'minimal-tag' })时,colordescription自动落为null
  • 单字段更新:只传{ color }时,tagdescription保持原值;
  • 置空字段updateTag(id, { color: null })updateTag(id, { description: null })可显式清空可选字段。

综合来看,Tags API 打通了「客户端方法 →api/*handler → tags 应用层 → 数据库」的完整链路,且与 UI 内建功能共用同一套服务端逻辑,行为一致、可放心自动化使用。

报表:命令栏直达与配置页返回按钮

v26.3.0 让报表(Reports)模块的触达路径更短:

  • 报表接入命令栏(PR #7002):此前命令栏(Command Bar)主要用于快速跳转账户、预算页面;现在输入报表名称即可在命令栏中直接打开对应报表。对于报表数量较多、习惯键盘操作的用户,这显著减少了"进入报表页再逐一点击"的路径。
  • 报表配置页新增返回按钮(PR #6702):进入报表配置/编辑页面后,现在可以一键返回报表列表,避免多级页面的"回退死角"。

从源码结构看,命令栏相关逻辑位于 packages/desktop-client/src/components/command-bar,报表模块则集中在 packages/desktop-client/src/components/reports。开发者可在这些目录中查看命令项注册与报表配置页的导航实现。

配套的报表修复还包括:报表卡片 tooltip 不再被相邻 widget 遮挡(PR #6849);净值报表第一个月净财富变化值计算修正(PR #6968);卡片视图下预算分析报表的日期范围计算修正(PR #6875);预算分析报表实验标志的反馈链接修正(PR #6914)。

银行同步(Bank Sync):关联流程体验与 API 能力升级

银行同步是本版本改进最密集的模块之一,涵盖 UX 与 API 两个层面:

关联新账户时可指定自定义起始日期与余额

PR #6629 允许用户在链接新的银行同步账户时,指定自定义的起始日期(starting date)与起始余额(balance)。这对于"银行历史数据不全"或"希望从某个时点开始记账"的用户非常实用,避免了默认起始点与实际记账需求不符的问题。

账户 API 支持设置balance_current

PR #6915 让账户(Account)API 支持写入balance_current字段。此前自定义导入器(custom importers)无法通过 API 同步当前余额,导致对账时余额不可见;现在自定义导入器可以在导入交易的同时写入当前余额,直接服务于对账场景。发布说明明确描述了这一用途:

The Account API now allowsbalance_currentto be set, making balances visible for reconciliation when using custom importers.

可配置是否用银行日期覆盖本地日期

PR #6850 新增银行同步选项:允许用银行提供的日期覆盖本地记录的日期。某些银行导入的日期与本地记录存在差异时,用户可自行决定是否信任银行值。

关联流程 UX 改进

发布说明还提到"账户关联流程的 UX 改进"(account linking flow),结合相关变更,本次银行同步的整体交互一致性得到增强。

银行同步的服务端逻辑主要位于 packages/sync-server/src/app-gocardless、app-enablebanking 等目录,账户相关 API 定义则在 packages/loot-core/src/server/accounts 与 packages/api 中,可对照查看balance_current的读写链路。

自定义主题:图表变量、简化 CSS 与高对比度浅色主题

v26.3.0 对自定义主题(Custom Themes)体系做了一轮系统性升级:

柱状/饼图配色变量(PR #6909)

此前自定义主题无法控制报表中柱状图(bar)与饼图(pie)各分片的颜色。本次新增了专用于 bar/pie chart 分片的主题变量(如bar1bar2……以及饼图分片变量),自定义主题作者现在可以完整控制图表配色,而不再局限于主色/背景色等基础变量。

简化自定义主题 CSS 变量(PR #7018)

自定义主题此前需要编写大量细粒度 CSS 变量才能完成定制。本次允许"使用简单的 CSS 变量"(simple CSS variables),降低主题编写门槛——更少的变量即可生效,主题作者无需再逐一覆盖几十个细粒度 token。

高对比度浅色主题(PR #7032)

新增一款高对比度(7.0:1 或更高)浅色主题,面向弱视用户与强光环境,进一步补齐了主题库的可访问性覆盖。

主题库扩充与更名

  • 新增Catppuccin Themes到自定义主题目录(PR #6857);
  • 新增Butterfly自定义主题(PR #6900);
  • 新增"You Need A Dark Mode"主题(PR #6891);
  • "Okabe Ito"主题更名为"Color-blind (dark)"(PR #7058),命名更直观地表达其色盲友好定位;
  • Midnight 主题的menuAutoCompleteTextHover颜色调整为green400(PR #7048)。

主题文件位于 packages/component-library/src/themes(含light.cssdark.cssmidnight.csspalette.css等),自定义主题的引用与变量体系可在此目录及 packages/desktop-client/src/style 中进一步查阅。相关配套改动还包括:桌面端预算页面统一使用一致的颜色变量(PR #6820),并新增 lint 规则禁止直接导入主题文件(PR #6796),保证主题引用规范。

性能与状态管理迁移:Redux → React Query

v26.3.0 延续了把状态管理从 Redux 迁移到 React Query 的长期工程(Maintenance分类中大量相关 PR),目标直指性能与可维护性:

  • 迁移**付款方(payee)与账户(account)**状态管理(PR #6880、#6140);
  • 迁移标签(tag)管理(PR #6941);
  • 迁移分类(category)状态(PR #5977、#6882);
  • 迁移报表数据获取(PR #6951);
  • 重构useTransactionshook 以使用 React Query 获取交易数据(PR #6757),并新增refetchOnSync选项统一处理同步事件(PR #6936);
  • 重构仪表盘数据获取(PR #6957);
  • 重构useAccounts返回完整查询状态(PR #7009);
  • 改进分类服务端应用与 React Query mutation 的错误处理(PR #6958)。

迁移的收益体现在多个方面:数据缓存与失效机制更统一、组件订阅粒度更细(避免无关状态变更引发重渲染)、同步事件触发 refetch 的逻辑更集中。发布说明将其概括为"性能和响应性改进"(Performance and responsiveness improvements),这一点在交易列表、账户切换、报表加载等高频场景中感知最明显。

此外,配套的工程化改动包括:每个包独立tsconfig.json并通过 lage 并行执行(PR #7019)、Electron 构建产物排除出 TypeScript 编译以提升效率(PR #6883)、fetch模块更名为connection以避免与原生 fetch 混淆(PR #6943)、arithmetic.ts移植为严格 TS(PR #6801)、oxlint/oxfmt 升级(PR #6955)以及 lint 规则全面收紧(类型感知 lint PR #6984、warning 转 error PR #6970)等。

预算、导入与其他用户体验增强

预算模板自动化

  • 补齐refill 模板类型的缺失逻辑(PR #6690),并新增limit/refill 自动化编辑器(PR #6692),用户可在界面上直接配置这两种模板的触发条件与参数;
  • 修复跟踪预算中模板余额结转(balance carryover)处理(PR #6922);
  • 修复预算摘要金额的双负号显示问题(PR #6843);
  • 覆盖超支(covering overspending)时,初始焦点落在分类而非金额上(PR #7012);
  • 为分类组新增筛选选项(PR #6834),交易导出时包含分类组信息(PR #6960)。

nYNAB 导入增强

  • 支持将 nYNAB(新版 YNAB)的定期交易导入为 Actual 的 schedules(PR #6844);
  • 从 nYNAB 导入时,标签颜色与 YNAB flags 对应(PR #6866);
  • 修复 YNAB5 导入器重复分类导入报错(PR #6878)。

货币与日期格式

  • 新增多米尼加比索(DOP)(PR #7028)与韩元(KRW)(PR #6846)到货币列表;
  • 月年日期格式修正为不含逗号的 "January 2026"(PR #6748)。

交互细节修复

  • 规则日期字段置空不再导致崩溃(PR #6905);
  • 修复 Ctrl+Enter 新增交易时丢失金额值(PR #6911);
  • 修复算数表达式解析中同级运算符(*//+/-)未按从左到右求值的问题(PR #6993);
  • 隐藏小数位数开启时,移动端预算金额输入修复(PR #6945);
  • 移动端可隐藏已对账(reconciled)交易(PR #6896);
  • 移动端规则列表对齐与全宽显示调整(PR #7081);
  • iOS Safari 状态栏颜色同步(主题色管理增强,PR #6983);
  • 无账户时重定向到账户页(PR #7007);
  • 筛选器中隐藏已选账户(PR #7030);
  • 规则结果窗口导入付款方列的 tooltip 缺失修复(PR #7031);
  • 紧凑视图处理简化,CashFlow 行为更一致(PR #6765);
  • 浏览器语言检测按优先级依次匹配(PR #6812);
  • Token 过期时自动登出(PR #6798);
  • 修复 widget 删除按钮翻译问题(PR #6845);
  • 桌面端链接笔记保持行内(PR #6858);
  • 防止过去错过的日程日期被标记为 upcoming(PR #6925);
  • 模块解析与 API 解析问题修复(PR #7084、#6966)。

小结与升级建议

维度v26.3.0 要点
安全同步服务器文件 ID 校验、单斜杠路径解析修复,建议尽快升级
新 APITags 管理四方法(getTags / createTag / updateTag / deleteTag)
银行同步关联账户自定义起始日期与余额、balance_currentAPI、日期覆盖选项
报表命令栏直达、配置页返回按钮、tooltip 与净财富计算修复
主题bar/pie 图表变量、简化 CSS 变量、高对比度浅色主题、3 个新主题
性能Redux → React Query 大规模迁移(payee/account/tag/category/report/dashboard)
其他新货币、refill 模板逻辑、nYNAB schedules 导入、日期格式修正

对于生产环境的用户,建议优先执行同步服务器升级以覆盖安全修复;API 使用者可直接利用 Tags 四方法把标签管理纳入自动化脚本(参考 packages/api/methods.test.ts 的调用范式);主题作者则可基于简化后的 CSS 变量体系重构现有主题,并利用新增的图表配色变量完善报表观感。

如需继续深入,可在仓库中重点查阅以下路径:API 方法定义 packages/api/methods.ts、API 模型与转换 packages/loot-core/src/server/api-models.ts、标签服务端逻辑 packages/loot-core/src/server/tags/app.ts、主题文件 packages/component-library/src/themes,以及本次版本的完整变更记录 packages/docs/blog/2026-03-02-release-26-3-0.md。

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 17:32:31

Snipe-IT:5 分钟搭好你的免费开源 IT 资产管理系统

Snipe-IT&#xff1a;5 分钟搭好你的免费开源 IT 资产管理系统 【免费下载链接】snipe-it A free open source IT asset/license management system 项目地址: https://gitcode.com/GitHub_Trending/sn/snipe-it 新员工的笔记本发出去了&#xff0c;是谁拿的没人说得清&…

作者头像 李华
网站建设 2026/9/11 17:32:14

ESP32-S3 WiFi STA连接详解:ESP-IDF事件驱动与VS Code开发实践

简介&#xff1a;面向物联网嵌入式开发者的ESP32实战例程&#xff0c;基于Visual Studio Code与ESP-IDF工具链&#xff0c;采用C语言编写&#xff0c;演示STA模式下连接路由器AP热点的完整流程。例程在ESP32-S3上验证运行&#xff0c;代码内已定义外设接线&#xff0c;并配有详…

作者头像 李华
网站建设 2026/9/11 17:30:32

Arduino倾斜开关物联网应用开发指南

1. 项目概述&#xff1a;倾斜开关在物联网中的创新应用 倾斜开关这个看似简单的电子元件&#xff0c;在物联网领域正发挥着越来越重要的作用。作为一位从事嵌入式开发多年的工程师&#xff0c;我最近完成了一个基于Arduino Uno的倾斜开关实验项目&#xff0c;这个项目完美展示了…

作者头像 李华
网站建设 2026/9/11 17:30:03

Excel公式实战:40个提升数据分析效率的核心技巧

1. 为什么Excel公式是数据分析的基石 在数据处理领域&#xff0c;Excel公式就像厨师的刀具套装——看似基础却决定了工作效率的上限。我见过太多数据分析师因为公式掌握不扎实&#xff0c;把半小时能完成的工作硬生生拖成一整天。这40个公式的筛选标准很明确&#xff1a;必须是…

作者头像 李华
网站建设 2026/9/11 17:29:32

数据可视化看板设计:从原理到实战的7步指南

1. 为什么需要可视化数据看板&#xff1f; 在信息爆炸的时代&#xff0c;数据已经成为企业决策的核心依据。但原始数据往往晦涩难懂&#xff0c;就像一本没有目录的百科全书&#xff0c;价值难以被快速提取。这正是可视化数据看板的价值所在——它将枯燥的数字转化为直观的图表…

作者头像 李华