- 提交写事务内先取事务级 advisory lock,再校验既有未删除账号/店铺与其它待审批申请: 手机号 1014、用户名 1013、店铺编号 1031、待审批占用 1007,冲突不落库且不消费短信验证码 - 已驳回(含通过后撤销)与已通过的终态记录不阻塞重新注册,形成新记录与新审批实例 - 并发同关键字段提交串行裁决,同一关键字段至多一条待审批记录 - 审批通过建店建号前复检关键字段,冲突返回可定位错误并整体回滚,不再以裸数据库错误收场 - 归档 Change fix-agent-distribution-registration-duplicate-guard 并同步主 Spec 验证:junhong_cmp_test + Redis DB 6 受控脚手架 37 项通过 / 0 项失败(含 6 路并发仅 1 条落库、 审批冲突回滚与无冲突建店回归),清理后 fixture 残留 0;gofmt/go build/go vet 全绿; openspec validate --all 35 项通过、doctor healthy、context-health 通过
6.5 KiB
MODIFIED Requirements
Requirement: 分销码与待审批代理注册
系统 SHALL 在每个代理店铺创建时生成全局唯一、不可修改的随机分销码;二维码仅编码 H5 注册入口和该码,二维码渲染与 H5 页面不属于本能力。分销码 MUST NOT 支持人工指定或编辑。
系统 SHALL 提供公开后端接口 POST /api/c/v1/agent-distribution-registrations,不要求登录、JWT、角色或权限。请求 MUST 携带有效 distribution_code、短信已验证手机号、密码及既有注册必填资料;系统 MUST 复用既有短信验证码校验与限流规则,并 MUST 保证同一验证码至多被消费一次。系统 MUST 为该次申请创建唯一的待审批注册记录,并 MUST NOT 在审批通过前创建店铺、代理账号、钱包或上下级归属。
系统 MUST 在创建注册记录与审批实例前校验注册关键字段(手机号、用户名、店铺编号)的唯一性:任一字段与既有未删除账号或店铺冲突时,MUST 按字段返回各自可定位的错误码与提示(手机号已存在、用户名已存在、店铺编号已存在);任一字段与其它待审批(status=0)注册记录冲突时,MUST 返回资源冲突错误并指明冲突字段。关键字段冲突时 MUST NOT 创建注册记录或审批实例,MUST NOT 消费短信验证码,客户修正资料后 MUST 能用同一验证码重试。
已驳回(含企业微信通过后撤销按驳回处理)与已通过的注册记录 MUST NOT 阻止同一手机号、用户名或店铺编号再次提交;状态为终态的历史注册记录只作为历史事实保留。同一关键字段的并发提交 MUST 被串行裁决,同一手机号、用户名或店铺编号至多存在一条待审批注册记录,MUST NOT 出现两条指向同一关键字段的待审批申请。店铺名称不参与唯一性校验。
分销码无效、分销码所属店铺已停用、上级店铺缺少启用的主账号、短信验证码无效或已被消费时,系统 MUST NOT 创建注册记录或审批实例,且 MUST 按失败原因返回各自可定位的错误码与提示,MUST NOT 统一为同一不可用结果。短信验证码 MUST 在注册记录与审批实例落库成功后才消费;落库前的任何失败 MUST NOT 消费验证码,客户 MUST 能用同一验证码直接重试。分销码所属店铺停用 MUST NOT 级联变更既有下级与既有佣金关系。
注册审批 MUST 使用业务类型 agent_distribution_approval,其业务标识 MUST 为待审批注册记录主键。企业微信最终通过时,系统 MUST 在同一事务内创建启用店铺、代理账号、所需钱包,写入上级店铺、初始业务员快照,标记注册记录已通过并记录审计;创建店铺与代理账号前 MUST 复检注册关键字段未被既有账号或店铺占用,被占用时 MUST 整体回滚并返回可定位冲突错误,MUST NOT 创建半套实体。最终驳回时 MUST NOT 创建店铺、账号、钱包或层级,仅保留注册记录与审批结果。
同一手机号在驳回后再次扫码 MUST 形成新的注册记录与新的审批实例;重复或乱序回调 MUST NOT 重复创建账号、层级或钱包。
Scenario: 扫码注册进入待审批
- WHEN 客户使用有效分销码提交已验证手机号、密码与注册必填资料,且手机号、用户名、店铺编号均未被占用
- THEN 系统仅创建一条待审批注册记录及企业微信审批实例,不创建店铺、账号或钱包
Scenario: 关键字段与既有账号或店铺重复
- WHEN 客户提交的注册手机号、用户名或店铺编号已存在未删除的账号或店铺
- THEN 系统不创建注册记录与审批实例,按冲突字段返回对应错误码与提示(手机号已存在 / 用户名已存在 / 店铺编号已存在),且不消费该次短信验证码
Scenario: 关键字段与其它待审批申请重复
- WHEN 客户提交的注册手机号、用户名或店铺编号已存在另一条待审批注册记录
- THEN 系统不创建新的注册记录与审批实例,返回资源冲突错误并指明冲突字段,且不消费该次短信验证码
Scenario: 驳回后重新注册
- WHEN 同一手机号、用户名或店铺编号的上一次申请已被企业微信驳回(含通过后撤销)
- THEN 系统允许再次提交并创建新的待审批注册记录与新的审批实例,不复用也不改写既有终态记录
Scenario: 并发重复提交
- WHEN 同一手机号、用户名或店铺编号在并发请求中被同时提交
- THEN 系统至多创建一条待审批注册记录,其余请求返回资源冲突错误
Scenario: 停用代理码注册
- WHEN 客户使用已停用代理所属店铺的分销码注册
- THEN 系统拒绝创建注册记录与审批实例,且不产生任何店铺或账号
Scenario: 验证码无效或已消费
- WHEN 请求携带的短信验证码无效、过期或已被消费
- THEN 系统拒绝创建注册记录,且不消耗该分销码的注册名额
Scenario: 落库前失败不消耗验证码
- WHEN 短信验证码校验通过后,注册记录或审批实例创建失败(含关键字段冲突)
- THEN 系统保留该验证码,客户可用同一验证码重试,重试得到的仍是同一失败原因而非验证码失效
Scenario: 审批通过建立层级与业务员快照
- WHEN 企业微信最终通过一条待审批注册记录,且该记录的手机号、用户名与店铺编号仍未被占用
- THEN 系统在同一事务内创建启用店铺与代理账号、写入分销码所属店铺为直接上级、复制上级当时业务员为初始业务员,并标记注册记录已通过
Scenario: 审批通过前关键字段已被占用
- WHEN 企业微信通过一条待审批注册记录,但其手机号、用户名或店铺编号已被并发创建的账号或店铺占用
- THEN 系统整体回滚本次建店建号,返回可定位的冲突错误,注册记录保持待审批且不产生半套实体
Scenario: 审批驳回不产生实体
- WHEN 企业微信最终驳回一条待审批注册记录
- THEN 系统不创建店铺、账号、钱包或层级,且同一手机号、用户名或店铺编号可再次扫码形成新的注册记录
Scenario: 重复回调不重复建层级
- WHEN 同一注册审批终态被重复投递
- THEN 系统至多创建一次店铺、账号、钱包与层级关系