PocketBuy 佣金计算与后台管理开发、测试、验证 SOP
适用代码库:
D:\Africa\cashloan\app\channelcenter
配套需求:10-PocketBuy 佣金系统需求文档.md
版本:V1.0-draft
当前状态:流程草案;须在配套 PRD 评审通过后执行,本 SOP 不代表已修改代码或已完成发布
目标:从需求冻结一直执行到可发布验收,且每一步都有输入、动作、产物和退出标准
1. 总体门禁
开发开始前必须满足:
- PRD 评审通过,确认本期只计算每单基础应得佣金 B。
- 明确本地 Mock 与生产真实口径的边界。
- 创建 ADR,确认
json-rules-engine通过独立 Node Rule Runtime 使用,Java 保持财务编排与金额权威。 - 确认数据库迁移从 V16 开始,不能编辑归档 V1–V15。
- 代码、配置、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:
commission-qualification-event-v1.jsoncommission-rule-policy-v1.jsoncommission-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 工作项顺序
- 合同和错误码。
- 数据库迁移和 DAO。
- Rule Runtime。
- Java 标准化/政策选择/金额组合器。
- 事件接收、inbox、重试。
- 管理端配置 API。
- 计算/异常查询 API。
- 管理端页面。
- 集成、性能、安全、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 请求处理
- 校验 Content-Type、body 大小和 JSON Schema。
- 校验 policy hash、fact/action/operator 白名单。
- 建立本次请求 Engine;加载规则和常量 facts。
- 执行 engine.run。
- 返回 events、ruleResults、引擎版本和耗时。
- 任何异常返回稳定错误码,不返回半套 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 层
建议职责:
| 服务 | 职责 |
|---|---|
CommissionEventService | inbox 幂等接收、状态推进 |
CommissionInputNormalizer | schema 后的跨字段校验、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 页面实现顺序
- 新增
commission.jsAPI 封装。 - 新增政策查看矩阵。
- 新增政策表单和条件构建器。
- 新增只读 JSON/校验结果。
- 新增计算列表/详情。
- 新增异常列表/重试。
- 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。
执行:
- 激活测试政策。
- 逐个发送 8 个固定 Mock 数据。
- 读取 calculation API 并与 golden file 比较。
- 在管理端核对矩阵、命中树、before/after 和异常。
- 重放 duplicate 和 mismatch。
- 停止 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 数据下执行:
- 查看当前政策矩阵,口头复述四场景金额。
- 创建/选择四笔代表订单并触发资格事件。
- 验证有店员时 SA 为765且店员为400。
- 验证无店员时无店员 entry、SA 为850。
- 验证经理档位。
- 激活一个未来生效修订,验证生效前后订单选择不同政策。
- 查看一笔详情,确认能解释每个金额。
- 构造缺经理/无效店员,确认不发部分佣金并进入异常。
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 建议发布顺序
- 数据库备份。
- 发布 Rule Runtime,但不接生产流量;验证 health/readiness 和一次只读求值。
- 发布 Channel Center 后端,Flyway 自动执行 V16+。
- 验证管理端/内部 API 和审计。
- 发布管理端静态资源。
- 创建并人工复核初版政策,暂不激活。
- 小流量开启上游资格事件。
- 激活政策并观察 30~60 分钟。
- 核对首批至少 20 笔,四角色/五角色各覆盖。
- 扩大流量。
14.3 观察指标
- 事件接收/计算成功数。
- MANUAL_REVIEW 和各错误码。
- Rule Runtime P95/P99 和错误率。
- inbox backlog 和最老事件年龄。
- 同 event_id payload mismatch。
- 计算金额分布;SA 只应出现 850 或765(初版规则下)。
14.4 回退
优先使用非破坏性回退:
- 停止上游新事件或关闭内部路由。
- 停用错误政策,保留所有计算快照。
- 回退应用/Runtime 镜像到已验证版本。
- 不删除已经生成的 calculation/entry。
- 导出受影响 event/calculation 清单,人工判断是否需后续差额处理。
- 数据库只在 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/研发/运维完成签字。