PocketBuy 佣金计算与后台管理开发、测试、验证 SOP

适用代码库:D:\Africa\cashloan\app\channelcenter
配套需求:10-PocketBuy 佣金系统需求文档.md
版本:V1.0-draft
当前状态:流程草案;须在配套 PRD 评审通过后执行,本 SOP 不代表已修改代码或已完成发布
目标:从需求冻结一直执行到可发布验收,且每一步都有输入、动作、产物和退出标准

1. 总体门禁

开发开始前必须满足:

  1. PRD 评审通过,确认本期只计算每单基础应得佣金 B。
  2. 明确本地 Mock 与生产真实口径的边界。
  3. 创建 ADR,确认 json-rules-engine 通过独立 Node Rule Runtime 使用,Java 保持财务编排与金额权威。
  4. 确认数据库迁移从 V16 开始,不能编辑归档 V1–V15。
  5. 代码、配置、OpenAPI、DDL、测试和运维文档作为同一变更集评审。

发布前必须满足:

  • PRD 第 18 节所有 P0 决策关闭。
  • 四个正向初版场景、全部异常/幂等/生效时间用例通过。
  • 无未解决 P0/P1 缺陷。
  • 规则、输入和输出均无 FPD7/结算/付款耦合。
  • 生产不使用 Mock 地址、Mock 凭据或 Mock 数据。

2. 参与人和职责

角色职责必签产物
产品经理资格事件、角色、场景、档位、历史生效口径PRD、UAT 结果
销售运营店员归属、经理档位、组织主体正确性初版规则矩阵、样例数据
财务确认 B 的业务含义和币种精度;不在本期评审结算公式金额样例
Channel Center 后端事件、配置、编排、金额、台账、审计后端代码和测试
Rule Runtime 开发Node 服务、规则校验/求值、版本锁定Runtime 镜像和测试
管理端前端政策、计算、异常页面前端构建产物和 E2E
BNS/信贷系统交机成功资格事件、订单事实和直接推荐证据接口合同、联调证据
组织/渠道系统qualified_at 查询店长、经理、区域经理历史关系、版本和证据组织接口合同、历史数据样本
QA测试设计、数据、执行、缺陷和回归测试报告
运维/安全配置、密钥、网络、镜像、监控、回滚发布检查单

3. 阶段 0:需求和口径冻结

3.1 操作

产品组织 60 分钟规则评审,逐行确认:

  • 120 美元示例映射到 commission_band=STANDARD,系统不做美元换汇。
  • 无店员:店长850、SA850、经理30、区域20。
  • 有有效店员:增加店员400,SA从850调整为765,其他角色不变。
  • PREMIUM=经理50/区域30 是正式规则还是仅测试档;若不是正式规则,在生产激活配置中删除或替换。
  • 资格事件正式名称、业务时间、撤销方式。
  • 五类受益人稳定 ID 和资格时间快照来源。

3.2 产物

  • 已签字规则矩阵。
  • P0 决策表和责任人/截止时间。
  • 4 个正向 + 至少 4 个异常业务样例。
  • 明确 BNS 负责订单事实/直接推荐证据、组织系统负责历史关系、Channel Center 佣金域负责构建并保存唯一权威快照。

3.3 退出标准

开发可在 Mock 口径下开始,但所有未决项必须有唯一编号;不得把 TBD 写成代码默认值。

4. 阶段 1:ADR 与接口合同

4.1 ADR-Commission-001

ADR 至少包含:

  • 背景:主系统 Java 11,规则库是 JavaScript/TypeScript。
  • 选择:独立、无状态 Node Rule Runtime。
  • 职责:Runtime 只返回命中事件;Java 用 BigDecimal 组合并写库。
  • 替代方案及拒绝理由:浏览器计算、任意脚本、Java 内嵌 JS、完全自研条件引擎。
  • 失败行为:Runtime 不可用时记录可重试异常,不发部分佣金。
  • 安全:无业务库权限、非 root、内网 TLS、payload 限制、依赖锁定。
  • 可撤回性:未来可替换条件引擎,只要保持 Rule Runtime API 和动作合同。

4.2 合同冻结

冻结三个 OpenAPI/JSON Schema:

  1. commission-qualification-event-v1.json
  2. commission-rule-policy-v1.json
  3. commission-rule-runtime-v1.json

每个 schema 必须包含:required、枚举、长度、数值格式、additionalProperties 策略、示例和错误示例。

4.3 退出标准

  • BNS/信贷、组织数据方、Channel Center 三方完成合同评审,并确认 BNS 不构建完整管理链。
  • JSON Schema 校验器可对正反例执行。
  • 上游确认 source_system + event_id 的幂等责任。

5. 阶段 2:分支、模块和任务拆分

5.1 建议模块落点

不改变现有分层:

sa-channel-backend/
  sa-channel-common/    枚举、错误码、金额/Hash公共类型
  sa-channel-dao/       policy、inbox、calculation、entry、exception实体和Mapper
  sa-channel-service/   commission领域服务、权威快照构建、政策选择、归属校验、金额组合器
  sa-channel-feign/     Rule Runtime/组织历史关系客户端
  sa-channel-job/       inbox失败重试任务
  sa-channel-web/       /api/admin/commission/** 和 /api/internal/commission/**
 
sa-channel-admin-web/
  src/api/commission.js
  src/views/commission/
  src/router/index.js
  src/components/Layout.vue
 
commission-rule-runtime/  新的 Node 服务;若架构组要求独立仓库则仅保留接口客户端

5.2 工作项顺序

  1. 合同和错误码。
  2. 数据库迁移和 DAO。
  3. Rule Runtime。
  4. Java 标准化/政策选择/金额组合器。
  5. 事件接收、inbox、重试。
  6. 管理端配置 API。
  7. 计算/异常查询 API。
  8. 管理端页面。
  9. 集成、性能、安全、UAT。

5.3 退出标准

每个工作项有负责人、测试项、评审人和完成定义;不创建“实现佣金系统”这种无法验收的大任务。

6. 阶段 3:数据库实现 SOP

6.1 迁移

在活动目录创建:

sa-channel-backend/sa-channel-web/src/main/resources/db/migration/V16__add_commission_domain.sql

如单文件过大,可按 V16~V18 拆分,但版本号必须唯一递增。禁止修改 db/migration-archive

6.2 DDL 检查

  • 创建 PRD 中五张表。
  • 金额全部 DECIMAL(20,2),禁止 FLOAT/DOUBLE。
  • JSON 字段使用 MySQL JSON。
  • 创建 source_system + event_id 唯一键。
  • 创建政策 policy_code + revision 唯一键。
  • 创建计算/受益人/订单/状态/时间索引。
  • 所有业务表包含 created_at、updated_at。
  • 无物理删除 API。
  • audit_log 仍 INSERT-only。

6.3 验证

在全新本地 DB 和 V15 基线副本分别执行:

  • Flyway migrate 成功。
  • 重复启动不重复建表。
  • 唯一键能阻止重复事件和重复明细。
  • rollback 脚本仅供人工应急评审,不在生产自动执行破坏性回滚。

6.4 退出标准

DBA 审核 DDL、索引、字符集、时区、空间预估和备份/回退方案。

7. 阶段 4:本地 Mock SOP

7.1 原则

  • 使用独立 WireMock/Mockoon 服务或测试 fixture。
  • 本地 profile 只配置外部 base URL 指向 Mock 服务。
  • 生产代码不得通过环境判断返回假数据。
  • Mock 合同与正式 OpenAPI/Schema 使用同一份校验。

7.2 Mock 端点

端点用途
POST /mock/bns/commission-events主动发送资格事件到本地 Channel Center
GET /mock/org/relations?store_id={id}&sa_id={id}&as_of={time}返回该业务时间有效的组织关系、版本和证据
GET /mock/product/{productId}/commission-band返回 STANDARD/PREMIUM

Rule Runtime 必须本地运行真实 json-rules-engine,不能用 WireMock 伪造成功事件作为主集成测试。仅在 Java 客户端单元测试中 Mock Runtime。

7.3 固定数据

准备 PRD 13.2 的 8 个 Mock ID,并将期望输出保存为 golden files。所有 ID、时间和币种固定,保证回归结果可重复。

7.4 退出标准

  • 每个正向/异常响应通过 schema 校验。
  • Mock 服务一键启动,README 写明端口和示例。
  • CI 能在无外网条件下运行契约测试。

8. 阶段 5:Rule Runtime 实现 SOP

8.1 工程约束

  • 固定受支持的 Node LTS 版本。
  • package.json 精确约束 json-rules-engine,提交 lockfile;CI 使用 npm ci
  • 仅暴露健康检查、就绪检查和 /internal/rules/evaluate
  • 不连接 MySQL/Redis,不存规则,不写台账。
  • 禁止加载用户代码、自定义 JavaScript 或不受控 operator。

8.2 请求处理

  1. 校验 Content-Type、body 大小和 JSON Schema。
  2. 校验 policy hash、fact/action/operator 白名单。
  3. 建立本次请求 Engine;加载规则和常量 facts。
  4. 执行 engine.run。
  5. 返回 events、ruleResults、引擎版本和耗时。
  6. 任何异常返回稳定错误码,不返回半套 events。

8.3 测试

  • all/any/not 嵌套。
  • 所有白名单 operator。
  • 非法 fact/operator/action 拒绝。
  • 规则优先级不改变最终 event 集。
  • 同输入同政策多次输出完全一致。
  • 规则数 200、facts 64 KB 下性能满足目标。
  • 深层 JSON、超大数组和畸形请求被限制。

8.4 退出标准

  • 单测覆盖核心分支。
  • npm audit/组织安全工具无阻断级漏洞。
  • 镜像以非 root 运行且无业务网络权限。
  • Java 契约测试能验证真实 Runtime。

9. 阶段 6:Java 后端实现 SOP

9.1 公共层

新增明确枚举,不用魔法字符串:角色、政策状态、计算状态、动作类型、异常码。金额 DTO 使用字符串接收并显式转换 BigDecimal。

9.2 DAO 层

  • Entity 只映射数据库,不直接作为 API DTO/VO。
  • Mapper 继承 MyBatis-Plus BaseMapper。
  • 复杂分页或政策时间选择 SQL 放 XML,全部参数化。
  • 实现唯一键冲突到业务错误码的映射。

9.3 Service 层

建议职责:

服务职责
CommissionEventServiceinbox 幂等接收、状态推进
CommissionInputNormalizerschema 后的跨字段校验、facts 派生
CommissionAttributionService五角色解析和有效性校验
CommissionPolicyService草稿、校验、激活、时间选择、快照 hash
CommissionRuleRuntimeClient调 Node Runtime、超时重试、响应校验
CommissionMoneyComposer动作排序、冲突检查、BigDecimal 运算
CommissionCalculationService编排并事务写 calculation/entries
CommissionExceptionService异常创建、查询和重试

事务只放 Service public 方法。外部 HTTP 不放入长事务。

9.4 金额组合器强制测试

  • 固定 850。
  • 850 × 0.9 = 765.00。
  • 多 multiplier 确认顺序和精度。
  • 重复 grant 报冲突。
  • modifier 找不到 target 报冲突。
  • exclusive group 多命中报冲突。
  • phase/sequence 排序稳定。
  • HALF_UP 边界。
  • 金额/乘数为空、负数、科学计数法和超过精度限制均拒绝。

9.5 Controller 层

  • 请求使用 *Request + JSR-303。
  • 返回 *VO/R<T>,不暴露 Entity。
  • /api/admin/** 使用现有 JWT + @RequireRole
  • /api/internal/** 使用独立服务鉴权拦截器。
  • OpenAPI 注解与 required/枚举一致。
  • Controller 不写业务逻辑或事务。

9.6 重试 Job

  • 只扫描到期且 retryable 的 inbox。
  • 使用分页和分布式锁。
  • 指数退避并设最大次数;超过上限转人工异常。
  • 每次重试记录次数、错误和 trace,不覆盖首次错误。

9.7 退出标准

后端单测、集成测试和 OpenAPI 校验通过;静态检查无敏感日志、无默认值降级、无 Controller 事务、无 float/double 金额。

10. 阶段 7:管理端实现 SOP

10.1 页面实现顺序

  1. 新增 commission.js API 封装。
  2. 新增政策查看矩阵。
  3. 新增政策表单和条件构建器。
  4. 新增只读 JSON/校验结果。
  5. 新增计算列表/详情。
  6. 新增异常列表/重试。
  7. Router 和 Layout 菜单接入。

10.2 UI 约束

  • 保持 Vue 2.7 + Element UI 现有样式。
  • admin 显示编辑/激活/停用/重试;operator 只读。
  • 前端角色控制只改善体验,后端仍必须 403。
  • 金额作为字符串展示,固定两位小数和 NGN。
  • 默认展示自然语言矩阵,JSON 仅只读预览。
  • 枚举由后端 Fact Catalog 返回,不在页面散落硬编码。
  • 保存使用 revision/updated_at 做乐观锁,冲突要求重新加载。

10.3 前端测试

  • 路由权限。
  • 条件 all/any/not 编辑。
  • 角色/组件关联。
  • 9折配置回显。
  • 静态校验错误定位到字段。
  • 激活二次确认文案和生效时间时区。
  • 计算详情显示 before/after。
  • operator 直接访问编辑路由被阻止,API 403 正确提示。

10.4 退出标准

lint、单测、构建和 E2E 通过;Chrome 支持范围内无阻断兼容问题。

11. 阶段 8:测试执行 SOP

11.1 测试层次

层次重点
Schema/契约字段、枚举、required、错误响应
Runtime 单测条件命中和拒绝非法配置
Java 单测归属、政策选择、金额组合、幂等
Repository 集成MySQL 8 DDL、唯一键、JSON、分页
服务集成Java + 真实 Runtime + MySQL + Redis + Mock 外部依赖
API 集成权限、错误码、OpenAPI 一致性
E2E管理端配置→激活→事件→计算详情
性能事件接收、单笔计算、列表、积压恢复
安全权限绕过、JSON DoS、注入、敏感日志、依赖漏洞
UAT业务四场景和可解释性

11.2 必测用例

除 PRD AC-01~AC-22 外,增加:

  • qualified_at 恰好等于 effective_from。
  • qualified_at 恰好等于 effective_to,应选择下一修订。
  • 两个 ACTIVE 政策时间重叠,激活被阻止。
  • occurred_at 与 qualified_at 不同,仍按 qualified_at。
  • Africa/Lagos 夏令时不适用但必须带 offset。
  • clerk attribution 时间晚于资格时间。
  • clerk 不属于订单门店。
  • SA/门店状态不合格。
  • product band 未登记。
  • Runtime 超时一次后重试成功。
  • Runtime 返回相同 requestId 但 policyHash 不同。
  • DB 在落明细前失败,事务不产生半套 entries。
  • 并发 10 次提交同 event_id 只有一套结果。
  • 管理员 A/B 同时编辑,后保存者收到 409。
  • policy JSON 达到大小上限和超过上限。
  • 月度阶梯在99、100、149、150单边界分别输出30、40、40、50。
  • period_status=OPEN 时不得生成SA经理或区域经理最终 B。
  • SA经理和区域经理使用各自受益人订单范围,不能共用一个全局订单数。
  • 同一订单重复完成事件按 order_id 去重,不增加月度计数。
  • 月度阶梯规则与原经理固定/商品档规则同时启用时,激活校验必须报重复 GRANT 冲突。
  • 月结修订不能覆盖原 calculation/entry,必须产生新的修订和差额记录。

11.3 Golden file

四个正向场景的标准化输入、命中 events、计算 steps 和最终输出保存为 golden files。任何变更必须明确更新原因并由产品/QA 复核,禁止测试自动接受新结果。

11.4 建议构建命令

在实际实现后执行:

# 后端
Set-Location D:\Africa\cashloan\app\channelcenter\sa-channel-backend
mvn clean test
 
# 管理端
Set-Location D:\Africa\cashloan\app\channelcenter\sa-channel-admin-web
npm ci
npm run lint
npm run build
 
# Rule Runtime(若放在同仓)
Set-Location D:\Africa\cashloan\app\channelcenter\commission-rule-runtime
npm ci
npm test

具体 Node LTS 和脚本名以 ADR/工程 package.json 为准,SOP 不预先硬编码不存在的脚本行为。

11.5 退出标准

  • AC-01~AC-22 全通过。
  • 自动化测试报告、覆盖率报告、性能报告、安全扫描报告齐全。
  • 所有失败均能通过 trace_id 定位;无静默成功。

12. 阶段 9:联调 SOP

12.1 本地联调

启动顺序:MySQL → Redis → WireMock → Rule Runtime → Channel Center Backend → Admin Web。

执行:

  1. 激活测试政策。
  2. 逐个发送 8 个固定 Mock 数据。
  3. 读取 calculation API 并与 golden file 比较。
  4. 在管理端核对矩阵、命中树、before/after 和异常。
  5. 重放 duplicate 和 mismatch。
  6. 停止 Rule Runtime,验证异常和恢复重试。

12.2 测试环境真实联调

  • 将 base URL 从 Mock 切到 BNS/组织测试服务;不改业务代码。
  • 双方记录 request_id/event_id/trace_id。
  • 抽查 20 笔事件的订单事实、直接推荐证据和佣金系统权威归属快照。
  • 对经理/区域经理 ID 做人工组织表核对。
  • 分别核对上游原始事件 hash、组织响应版本和 Channel Center 最终快照 hash。

12.3 退出标准

无字段口径歧义;上游重试、幂等冲突、超时和补数流程均有实际证据。

13. 阶段 10:UAT SOP

业务人员在只读 UAT 数据下执行:

  1. 查看当前政策矩阵,口头复述四场景金额。
  2. 创建/选择四笔代表订单并触发资格事件。
  3. 验证有店员时 SA 为765且店员为400。
  4. 验证无店员时无店员 entry、SA 为850。
  5. 验证经理档位。
  6. 激活一个未来生效修订,验证生效前后订单选择不同政策。
  7. 查看一笔详情,确认能解释每个金额。
  8. 构造缺经理/无效店员,确认不发部分佣金并进入异常。

UAT 报告必须记录实际 order_id、event_id、policy revision、预期、实际和签字人。

14. 阶段 11:发布 SOP

14.1 发布前检查

  • 主干工作树和发布 commit 明确。
  • 备份数据库受影响表和现有配置。
  • Flyway V16+ 在生产副本演练。
  • Node 镜像 digest、依赖清单和安全扫描固定。
  • 生产环境变量/密钥由运维注入,无 Mock URL。
  • 内网 DNS、TLS、ACL、超时和健康检查已验证。
  • 初版政策由双人复核;effective_from 使用 Africa/Lagos。
  • 资格事件上游先关闭投递或具备安全重试队列。

14.2 建议发布顺序

  1. 数据库备份。
  2. 发布 Rule Runtime,但不接生产流量;验证 health/readiness 和一次只读求值。
  3. 发布 Channel Center 后端,Flyway 自动执行 V16+。
  4. 验证管理端/内部 API 和审计。
  5. 发布管理端静态资源。
  6. 创建并人工复核初版政策,暂不激活。
  7. 小流量开启上游资格事件。
  8. 激活政策并观察 30~60 分钟。
  9. 核对首批至少 20 笔,四角色/五角色各覆盖。
  10. 扩大流量。

14.3 观察指标

  • 事件接收/计算成功数。
  • MANUAL_REVIEW 和各错误码。
  • Rule Runtime P95/P99 和错误率。
  • inbox backlog 和最老事件年龄。
  • 同 event_id payload mismatch。
  • 计算金额分布;SA 只应出现 850 或765(初版规则下)。

14.4 回退

优先使用非破坏性回退:

  1. 停止上游新事件或关闭内部路由。
  2. 停用错误政策,保留所有计算快照。
  3. 回退应用/Runtime 镜像到已验证版本。
  4. 不删除已经生成的 calculation/entry。
  5. 导出受影响 event/calculation 清单,人工判断是否需后续差额处理。
  6. 数据库只在 DBA 批准且确认无新数据依赖时执行专门回退;绝不修改归档迁移。

15. 阶段 12:发布后验证与交接

T+0:核对首批订单、错误率、积压、审计日志和管理端。

T+1:销售运营抽样受益人归属;QA 重放回归;运维检查资源和告警。

T+7:汇总异常类型、重复事件、归属缺失和政策争议,形成 MVP 改进清单。绩效系数和结算如需启动,建立独立需求和接口,不修改本佣金规则输出语义。

交接包必须包含:

  • PRD、ADR、OpenAPI/JSON Schema。
  • DDL 与数据字典。
  • 初版政策 JSON 和 hash。
  • Mock 配置、golden files。
  • 自动化/性能/安全/UAT 报告。
  • 部署配置清单、镜像 digest、监控和告警。
  • 回退手册、当班联系人、已知问题。

16. 缺陷分级与停止条件

级别示例行为
P0重复发佣金、金额错误、角色错发、历史被覆盖、权限绕过立即停止发布/流量
P1大量事件积压、Runtime 不稳定、异常无法重试、审计缺失不得扩大流量
P2非核心筛选/展示问题但数据正确可评估带已知问题上线
P3文案、样式小问题排期修复

任一以下情况必须停止生产启用:

  • 正式资格事件未确认。
  • 店员归属或管理层组织 ID 仍来自 Mock/人工默认。
  • 经理金额档位没有业务签字。
  • 同一时间选中多个 ACTIVE 政策。
  • 幂等并发测试失败。
  • Runtime/Java 结果无法解释或 hash 不一致。
  • 输出出现 FPD7、结算或付款逻辑耦合。

17. 完成定义(Definition of Done)

本 MVP 只有同时满足下列条件才算完成:

  • 需求、ADR、接口和数据模型评审通过。
  • 初版规则能通过后台清晰呈现并生成对应 JSON。
  • 四个正向金额和全部异常用例通过。
  • Java 使用 BigDecimal,Rule Runtime 只做条件判断。
  • 幂等、增量生效、历史不覆盖、异常重试和审计可验证。
  • 外部真实接口完成联调;本地 Mock 与生产配置彻底隔离。
  • 管理端 admin/operator 权限验证通过。
  • OpenAPI、DDL、测试、部署、监控和回退产物齐全。
  • P0 决策和缺陷全部关闭,业务/QA/研发/运维完成签字。