Files
junhong_cmp_fiber/openspec/changes/add-shop-salesperson-groups/design.md
break 370fd3e67f
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m49s
update
2026-09-03 09:28:28 +08:00

3.9 KiB
Raw Blame History

Context

现有店铺已存在负责人候选和数据范围能力;用户组是新的业务分类,不能复用 RBAC 角色或代理店铺层级。推导关系必须保持实时,避免负责人改组后大量回写店铺造成不一致。

Decisions

  • 新增业务用户组表和平台用户—组关联(用户唯一)表;组编码唯一且不可改,停用不删除既有成员关联。
  • 店铺不保存组 ID。列表/详情以店铺负责人关联平台用户,再左连接用户组得到组及停用状态;按组筛选同样使用该关系。
  • 勾选批量交接采用一次事务:先按操作者数据范围锁定/校验全量店铺及目标用户,再统一更新和写审计。任何校验失败不写入。
  • Excel 使用既有异步导入模式逐行事务;每行在数据范围内查询,统一拒绝文案不区分无权与不存在,并持久化任务明细。
  • 用户组成员批量设置直接替换关联;不引入组管理员、层级、额外权限或数据范围计算。

管理动作契约

用户组及成员

  • POST /business-user-groups:超级管理员、平台用户提交 code164 字符,未删除组内唯一)、name1100 字符)、sort(非负整数)、enabledremark(最多 500 字符)。成功返回组 ID 与字段;重复编码返回“业务用户组编码已存在”。
  • PUT /business-user-groups/:id:允许更新名称、排序、启停、备注;code 永不允许修改。不存在/已删除返回既有资源不存在。
  • DELETE /business-user-groups/:id:请求须带二次确认;存在成员时返回“用户组仍有成员,只能停用或先移走成员”,不物理删除。
  • PUT /business-user-groups/:id/members:请求 account_ids 非空数组;所有账号必须是启用平台用户且目标组启用。事务内替换每个账号旧组关系,任一账号无效则全量回滚。DELETE /business-user-groups/members 使用同一校验清空指定账号归属。成功操作写成员前后审计。

店铺负责人批量交接

  • PUT /shops/business-owner/batch:请求 shop_ids(非空、去重)及 business_owner_account_id(有效平台业务员)或显式 null(清空)。先按操作者数据范围锁定并校验所有店铺,再统一更新 tb_shop.business_owner_account_id 并逐店写审计;任何目标无权、不存在、已删除或负责人无效时,返回统一失败且整批无写入。
  • Excel 导入使用既有异步导入任务;每行提供店铺标识及负责人账号标识或清空标识。每行独立授权、存在性、负责人有效性校验和事务更新;结果保存行号、成功/失败、失败原因、变更前后负责人及汇总。无权和不存在对调用方使用同一错误文案。

读侧投影

  • 扩展既有店铺列表、详情、筛选与导出:返回 business_owner_account_id、负责人名称、business_user_group_id、组编码、组名称、组启用状态;组字段从当前负责人—成员关系实时左连接。
  • 组筛选只匹配当前负责人所属组;负责人为空或无成员关系时归入“未分组”。历史店铺不回填;负责人改组/停用后下一次读立即反映变化。

Risks / Trade-offs

  • 实时 join 增加列表复杂度 → 为负责人和成员关联建立查询索引,不以冗余字段换一致性风险。
  • 负责人/分组并发更新 → 店铺交接和用户改组均使用事务与受影响行检查;读取接受当前已提交快照。
  • 导入部分成功 → 明确为逐行语义,任务明细是唯一结果来源。

Migration Plan

  1. 新增成对迁移创建用户组、成员关联和导入/查询索引,不回填历史组归属。
  2. 部署读侧空组兼容,再启用维护、批量和导入入口。
  3. 隔离库验证成员唯一、停用保留、实时推导、批量原子失败、导入逐行结果及迁移 up/down/up。