fix(代理分销注册): 校验手机号/用户名/店铺编号唯一性并支持驳回后重注册
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
- 提交写事务内先取事务级 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 通过
This commit is contained in:
@@ -9,17 +9,41 @@
|
||||
|
||||
系统 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 NOT 创建店铺、账号、钱包或层级,仅保留注册记录与审批结果。
|
||||
注册审批 MUST 使用业务类型 `agent_distribution_approval`,其业务标识 MUST 为待审批注册记录主键。企业微信最终通过时,系统 MUST 在同一事务内创建启用店铺、代理账号、所需钱包,写入上级店铺、初始业务员快照,标记注册记录已通过并记录审计;创建店铺与代理账号前 MUST 复检注册关键字段未被既有账号或店铺占用,被占用时 MUST 整体回滚并返回可定位冲突错误,MUST NOT 创建半套实体。最终驳回时 MUST NOT 创建店铺、账号、钱包或层级,仅保留注册记录与审批结果。
|
||||
|
||||
同一手机号在驳回后再次扫码 MUST 形成新的注册记录与新的审批实例;重复或乱序回调 MUST NOT 重复创建账号、层级或钱包。
|
||||
|
||||
#### Scenario: 扫码注册进入待审批
|
||||
|
||||
- **WHEN** 客户使用有效分销码提交已验证手机号、密码与注册必填资料
|
||||
- **WHEN** 客户使用有效分销码提交已验证手机号、密码与注册必填资料,且手机号、用户名、店铺编号均未被占用
|
||||
- **THEN** 系统仅创建一条待审批注册记录及企业微信审批实例,不创建店铺、账号或钱包
|
||||
|
||||
#### Scenario: 关键字段与既有账号或店铺重复
|
||||
|
||||
- **WHEN** 客户提交的注册手机号、用户名或店铺编号已存在未删除的账号或店铺
|
||||
- **THEN** 系统不创建注册记录与审批实例,按冲突字段返回对应错误码与提示(手机号已存在 / 用户名已存在 / 店铺编号已存在),且不消费该次短信验证码
|
||||
|
||||
#### Scenario: 关键字段与其它待审批申请重复
|
||||
|
||||
- **WHEN** 客户提交的注册手机号、用户名或店铺编号已存在另一条待审批注册记录
|
||||
- **THEN** 系统不创建新的注册记录与审批实例,返回资源冲突错误并指明冲突字段,且不消费该次短信验证码
|
||||
|
||||
#### Scenario: 驳回后重新注册
|
||||
|
||||
- **WHEN** 同一手机号、用户名或店铺编号的上一次申请已被企业微信驳回(含通过后撤销)
|
||||
- **THEN** 系统允许再次提交并创建新的待审批注册记录与新的审批实例,不复用也不改写既有终态记录
|
||||
|
||||
#### Scenario: 并发重复提交
|
||||
|
||||
- **WHEN** 同一手机号、用户名或店铺编号在并发请求中被同时提交
|
||||
- **THEN** 系统至多创建一条待审批注册记录,其余请求返回资源冲突错误
|
||||
|
||||
#### Scenario: 停用代理码注册
|
||||
|
||||
- **WHEN** 客户使用已停用代理所属店铺的分销码注册
|
||||
@@ -32,18 +56,23 @@
|
||||
|
||||
#### Scenario: 落库前失败不消耗验证码
|
||||
|
||||
- **WHEN** 短信验证码校验通过后,注册记录或审批实例创建失败
|
||||
- **WHEN** 短信验证码校验通过后,注册记录或审批实例创建失败(含关键字段冲突)
|
||||
- **THEN** 系统保留该验证码,客户可用同一验证码重试,重试得到的仍是同一失败原因而非验证码失效
|
||||
|
||||
#### Scenario: 审批通过建立层级与业务员快照
|
||||
|
||||
- **WHEN** 企业微信最终通过一条待审批注册记录
|
||||
- **WHEN** 企业微信最终通过一条待审批注册记录,且该记录的手机号、用户名与店铺编号仍未被占用
|
||||
- **THEN** 系统在同一事务内创建启用店铺与代理账号、写入分销码所属店铺为直接上级、复制上级当时业务员为初始业务员,并标记注册记录已通过
|
||||
|
||||
#### Scenario: 审批通过前关键字段已被占用
|
||||
|
||||
- **WHEN** 企业微信通过一条待审批注册记录,但其手机号、用户名或店铺编号已被并发创建的账号或店铺占用
|
||||
- **THEN** 系统整体回滚本次建店建号,返回可定位的冲突错误,注册记录保持待审批且不产生半套实体
|
||||
|
||||
#### Scenario: 审批驳回不产生实体
|
||||
|
||||
- **WHEN** 企业微信最终驳回一条待审批注册记录
|
||||
- **THEN** 系统不创建店铺、账号、钱包或层级,且同一手机号可再次扫码形成新的注册记录
|
||||
- **THEN** 系统不创建店铺、账号、钱包或层级,且同一手机号、用户名或店铺编号可再次扫码形成新的注册记录
|
||||
|
||||
#### Scenario: 重复回调不重复建层级
|
||||
|
||||
|
||||
Reference in New Issue
Block a user