Skip to content

[Bug] 共享账本 Editor 新建标签后不可见,并在关联交易后生成重复标签 #435

Description

@tedzhouhk

问题描述

在 BeeCount Cloud 共享账本中,Editor 从手机 App 新建标签后:

  1. App 提示标签已创建、同步状态也显示已上传;
  2. 该标签随后不会出现在当前共享账本的标签选择器中;
  3. Owner 及其他成员的 App/Web 也看不到该标签;
  4. 当 Editor 在 Web 端把这个标签名称关联到一笔共享交易后,Owner 设备会在拉取交易时创建一条新的同名标签;
  5. 新标签再次上传后,所有成员才开始看到它。

最终服务端会出现两条名称相同但 syncId 不同的标签,分别属于 Editor 和 Owner。

复现步骤

  1. 创建一个共享账本,账户 A 为 Owner,账户 B 为 Editor;
  2. 账户 B 在手机 App 的共享账本交易标签选择器中选择“新建标签”;
  3. 等待 BeeCount Cloud 自动同步完成;
  4. 检查账户 B 的共享账本标签选择器,以及账户 A 的 App/Web 标签列表;
  5. 使用账户 B 在 Web 端编辑一笔共享交易,填入刚才创建的标签名称;
  6. 等待账户 A 的手机 App 拉取并再次同步;
  7. 检查服务端和各端标签列表。

实际行为

  • Editor 新建的标签被保存为 Editor 自己的 user-global 标签;
  • 共享账本的 Editor 标签选择器只展示 Owner 的镜像标签,因此刚创建的标签会“消失”;
  • Owner 和其他成员无法读取 Editor 的 user-global 标签;
  • Web 更新交易时可能只提交 tags 名称而没有合法的 tagIds
  • Owner 手机拉取这笔交易后,旧协议 fallback 会按名称创建新的本地标签并生成新的 UUID;
  • 同步兜底逻辑随后将该标签作为 Owner 的 user-global 标签上传,造成同名重复标签。

“标签已同步”的提示并非网络层误报:服务端确实接受了变更,但它进入了 Editor 的个人用户作用域,而不是共享账本可见的标签集合。

期望行为

共享账本内创建、选择和同步标签的权限及作用域必须一致,不能出现以下情况:

  • Editor 创建成功但当前共享账本不可见;
  • 通过关联交易间接为 Owner 创建标签;
  • 同一个逻辑标签在不同用户作用域下生成多个 syncId
  • 未知的标签名称被客户端 fallback 静默升级为 Owner 的全局标签。

根因

当前实现同时存在三处不一致:

  1. 标签数据模型是 user-global,创建时归当前登录用户所有;
  2. 共享账本 Editor 的选择器会完全替换为 Owner 的共享资源镜像;
  3. 交易同步仍允许只有标签名称、没有 tagIds,移动端对此执行“按名称创建本地标签”的兼容逻辑。

另外,标签选择器期望 TagEditPage 返回新建的 Tag 以自动选中,但创建页目前丢弃了 createTag() 返回值并以空结果退出,因此自动选中逻辑不会执行。

方案一:维持现有 Owner 标签模型(短期止血)

共享账本标签继续采用“Owner 的 user-global 标签作为唯一权威集合”。

App

  • 当前账本为共享账本且角色为 Editor 时,隐藏或禁用“新建标签”;
  • 提示“共享账本标签由 Owner 管理”;
  • Editor 仍可在自己的个人账本中创建个人标签;
  • Owner/单人账本创建标签后,TagEditPage 应返回新建标签,使选择器可以立即选中。

Web/服务端

  • Editor 编辑共享交易时,只能选择 Owner 已有标签;
  • 请求必须携带属于 Owner 的合法 tagIds
  • 对只有未知标签名称、没有合法 tagIds 的共享交易写入返回校验错误;
  • 移动端应用共享交易时,不得因为缺少 tagIds 而自动创建 Owner 标签;
  • 对旧协议名称 fallback:共享账本中只允许按名称匹配现有 Owner/镜像标签,匹配不到则跳过并记录同步警告。

优点

  • 改动和迁移范围较小;
  • 与当前 Owner 资源镜像模型一致;
  • 可以快速阻止重复标签继续产生。

缺点

  • Editor 无法在共享账本中创建新标签;
  • 协作体验受到限制,需要联系 Owner 先创建标签。

方案二:新增账本级共享标签(完整协作方案)

为共享账本增加独立于任何用户个人标签库的 ledger-scoped 标签模型。

数据模型

  • 标签以 ledger_id + sync_id 为稳定身份;
  • Owner 和 Editor 均可在当前共享账本中创建标签;
  • Editor 创建的标签不会进入 Editor 或 Owner 的个人 user-global 标签库;
  • 共享标签只在对应共享账本中可见;
  • 所有成员及交易引用同一个 syncId

权限建议

  • Owner、Editor:创建和使用共享标签;
  • Owner:可管理、重命名和删除全部共享标签;
  • Editor 是否允许重命名/删除,可单独定义,或仅允许管理自己创建的标签。

同步和兼容

  • App 和 Web 创建共享标签时调用明确的 ledger-scoped 写入接口;
  • 服务端生成或确认唯一 syncId,提交后广播给所有成员;
  • 交易必须引用共享标签 syncId
  • 需要设计现有 Owner 标签在共享账本中的迁移/映射策略;
  • 需要同时修改 BeeCount App 和 BeeCount-Cloud。

优点

  • 符合共享记账的协作预期;
  • Editor 可以正常创建标签;
  • 不会修改 Owner 在其他私人账本使用的全局标签库;
  • 权限和数据所有权边界清晰。

缺点

  • 涉及数据库、同步协议、App/Web UI 和迁移逻辑,改动较大;
  • 需要处理旧交易及现有 Owner 标签的兼容映射。

建议实施顺序

  1. 先采用方案一阻止继续生成重复标签,并修复创建页不返回新标签的问题;
  2. 如果产品目标允许 Editor 管理共享账本标签,再以方案二作为后续完整改造;
  3. 修复上线后,提供检查或清理工具识别同名不同 syncId 的历史重复标签,不建议仅按名称自动跨用户合并。

验收测试

  • Editor 在共享账本中不会创建不可见的个人标签;
  • Owner 创建标签后,Editor App/Web 可以及时看到;
  • Editor 关联 Owner 标签时,所有端使用相同 syncId
  • 共享交易只有未知标签名称时,不会触发 Owner 端自动建标签;
  • 个人账本创建标签及旧协议兼容不受影响;
  • 创建标签后,支持创建的场景能够立即自动选中;
  • 方案二若实施:Owner 与 Editor 创建的共享标签均只属于当前账本。

环境

  • BeeCount Cloud:1.6.2
  • 同步方式:BeeCount Cloud 自建服务
  • 影响范围:Android/iOS App、Web,以及 BeeCount-Cloud 同步协议

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions