Files
ccdi/docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md

9.0 KiB
Raw Blame History

LSFX Mock Server 异常账户命中流水设计文档

模块: lsfx-mock-server
日期: 2026-03-31

一、背景

当前仓库中的异常账户模型已经在主系统后端完成规则接入,包含以下两条对象型规则:

  • SUDDEN_ACCOUNT_CLOSURE
  • DORMANT_ACCOUNT_LARGE_ACTIVATION

根据已落地的后端实施计划与实现结果,这两条规则的命中依赖两类事实:

  1. 账户事实:来自 ccdi_account_info 的账户状态、开户日、销户日、账户归属人
  2. 流水事实:来自 ccdi_bank_statement 的账号维度交易时间与交易金额

当前 lsfx-mock-server 已具备以下能力:

  • FileService 为每个 logId 生成稳定的规则命中计划
  • StatementService 根据命中计划拼接规则样本流水
  • /watson/api/project/getBSByLogId 返回分页流水列表

但 Mock 服务现阶段尚未支持异常账户模型对应的“账户事实 + 命中流水”闭环,因此后端即使接入了真实规则 SQL也无法通过现有 Mock 数据稳定命中异常账户规则。

本次目标是在不改动现有接口协议的前提下,为 lsfx-mock-server 补齐异常账户规则的最小闭环造数能力,让同一个 logId 下既有可命中后端 SQL 的账户事实,也有与之匹配的流水样本。

二、目标

  • 在现有 Mock 规则计划体系中新增异常账户命中计划。
  • 为每个命中异常账户规则的 logId 生成稳定的异常账户事实。
  • 按后端 SQL 口径生成两条规则对应的流水样本。
  • 保持现有 /watson/api/project/getBSByLogId 返回结构不变。
  • 保持现有 FileService -> StatementService 主链路不变,不引入平行造数机制。
  • 补充测试,确保命中计划、账户事实和流水样本三者一致。

三、非目标

  • 不新增异常账户独立接口。
  • 不修改现有上传、拉取行内流水、查询流水接口的请求参数与响应结构。
  • 不对外直接返回异常账户事实列表。
  • 不模拟 ccdi_account_info 全字段,只保留两条规则所需最小字段。
  • 不扩展异常账户详情页、分页查询或导出链路。
  • 不引入动态配置平台、DSL 或补丁式兼容逻辑。

四、方案对比

4.1 方案一:并入现有 rule_hit_plan 体系

做法:

  • FileRecord 中新增异常账户命中计划与账户事实
  • build_seed_statements_for_rule_plan(...) 中接入异常账户样本生成
  • StatementService 继续统一补噪声、编号、分页

优点:

  • 完全复用当前 Mock 主链路
  • 同一个 logId 下规则计划、账户事实、流水样本天然一致
  • 实现路径最短,后续联调稳定

缺点:

  • 需要在 FileRecord 中增加一层最小账户事实建模

4.2 方案二:仅在 StatementService 中硬编码异常账户流水样本

优点:

  • 改动最少,实现最快

缺点:

  • 命中流水和账户事实分离
  • 后续若需要调试命中原因或扩展账户事实,维护成本较高

4.3 方案三:新增独立异常账户服务模块

优点:

  • 抽象边界更清晰

缺点:

  • 对当前 Mock 项目来说偏重
  • 超出最短路径实现要求

五、结论

采用方案一。

原因如下:

  • 与当前 Mock 服务的规则计划机制完全一致
  • 不新增接口、不增加平行数据流
  • 能以最小改动实现“账户事实 + 命中流水”的稳定闭环
  • 后续若主系统还需要继续扩展 Mock 规则样本,可以沿用同一套结构

六、总体设计

6.1 新增命中计划维度

在现有规则计划结构上新增:

  • abnormal_account_hit_rules

规则池固定为:

  • SUDDEN_ACCOUNT_CLOSURE
  • DORMANT_ACCOUNT_LARGE_ACTIVATION

FileService 在为 logId 生成规则计划时,继续沿用现有“稳定随机且可复现”的逻辑,把异常账户规则作为平级维度一起生成并回填到 FileRecord

6.2 新增最小账户事实

FileRecord 新增以下字段:

  • abnormal_account_hit_rules: List[str]
  • abnormal_accounts: List[AbnormalAccountFact]

其中 AbnormalAccountFact 仅保留两条规则需要的最小字段:

  • account_no
  • owner_id_card
  • account_name
  • status
  • effective_date
  • invalid_date

说明:

  • 本次不复制主系统 ccdi_account_info 全量结构
  • 只保留命中 SQL 真正会用到的事实,避免过度设计

6.3 样本流水接入位置

现有 StatementService 已通过 build_seed_statements_for_rule_plan(...) 生成规则样本流水。

本次改造保持该入口不变,仅在其内部追加异常账户规则样本构造:

  • build_sudden_account_closure_samples(...)
  • build_dormant_account_large_activation_samples(...)

生成出的异常账户样本与其他规则样本一起组成 seeded_statements,之后继续复用现有逻辑:

  1. 补足噪声流水
  2. 统一分配流水编号
  3. 打乱顺序
  4. 分页返回

七、规则口径设计

7.1 SUDDEN_ACCOUNT_CLOSURE

Mock 口径必须与后端 SQL 对齐:

  • 账户状态为 2
  • invalid_date 非空
  • 流水账号与账户事实中的 account_no 一致
  • 所有命中样本流水时间都落在 [invalid_date - 30天, invalid_date) 区间内

样本策略:

  • 为单个命中账户生成 2 到 3 笔流水
  • 同时覆盖收入和支出,便于后端聚合 windowTotalAmount
  • 保证存在明确的最后交易日,便于推导 lastTxDate
  • 保证存在稳定的单笔最大金额,便于推导 windowMaxSingleAmount

7.2 DORMANT_ACCOUNT_LARGE_ACTIVATION

Mock 口径必须与后端 SQL 对齐:

  • 账户状态为 1
  • effective_date 非空
  • 首笔流水日期 >= effective_date + 6个月
  • 启用后流水满足:
    • windowTotalAmount >= 500000
    • windowMaxSingleAmount >= 100000

样本策略:

  • 首笔流水明确落在开户满 6 个月以后
  • 为避免边界漂移,直接让累计金额和单笔最大金额同时满足阈值
  • 启用后生成 2 笔以上流水,保证累计口径稳定

7.3 未命中规则时的处理

当某个 logIdabnormal_account_hit_rules 中不包含某条规则时:

  • 不生成该规则的账户事实
  • 不生成该规则的流水样本
  • 不制造“接近命中但未命中”的灰度样本

这样可以避免误命中,保证 Mock 语义清晰。

八、数据流设计

本次改造后的数据流如下:

  1. FileService.fetch_inner_flow(...) 或上传链路创建 FileRecord
  2. FileService 生成四类命中计划:
    • large_transaction_hit_rules
    • phase1_hit_rules
    • phase2_statement_hit_rules
    • abnormal_account_hit_rules
  3. FileService 根据异常账户命中计划生成 abnormal_accounts
  4. StatementService._generate_statements(...) 读取 FileRecord
  5. build_seed_statements_for_rule_plan(...) 依据异常账户命中计划拼接对应样本流水
  6. 服务层继续补噪声并返回现有结构的流水列表

结论:

  • 内部多了一层异常账户事实
  • 对外接口保持不变

九、模块与职责

9.1 lsfx-mock-server/services/file_service.py

职责调整:

  • 扩展 FileRecord
  • 生成并保存 abnormal_account_hit_rules
  • 按命中规则生成对应 abnormal_accounts
  • 保证同一 logId 下账户事实稳定可复现

9.2 lsfx-mock-server/services/statement_rule_samples.py

职责调整:

  • 新增异常账户事实结构
  • 新增两类异常账户样本构造器
  • 在统一种子流水构造入口中接入异常账户样本

9.3 lsfx-mock-server/services/statement_service.py

职责保持不变,仅消费新增计划与样本:

  • 读取 FileRecord 中的异常账户计划
  • 调用种子样本生成器
  • 继续完成补噪声、编号、缓存、分页返回

十、测试设计

测试分为三层:

10.1 计划层测试

验证点:

  • FileRecord 能保存 abnormal_account_hit_rules
  • 生成的异常账户计划稳定、可复现
  • 命中计划与账户事实数量、规则类型一致

10.2 样本层测试

验证点:

  • SUDDEN_ACCOUNT_CLOSURE 样本流水日期全部处于销户前 30 天窗口内
  • DORMANT_ACCOUNT_LARGE_ACTIVATION 首笔流水日期晚于开户满 6 个月
  • 休眠账户样本的累计金额和单笔最大金额达到后端 SQL 阈值

10.3 服务层测试

验证点:

  • StatementService._generate_statements(...) 能把异常账户样本混入返回流水
  • 未命中的异常账户规则不会污染其他 logId
  • 同一个 logId 重复查询时缓存结果保持稳定

十一、风险与约束

  • 本次不改协议,因此异常账户事实仅在 Mock 服务内部使用
  • 由于不新增独立接口,联调时仍需通过现有流水接口间接触发后端规则命中
  • 样本日期和金额必须严格贴后端 SQL 口径避免出现“Mock 看起来合理但后端不命中”的问题

十二、后续计划

本设计确认后,下一步仅进入实施计划编写阶段,不直接扩展其他功能。

按仓库约定,需要继续补充:

  • 后端实施计划
  • 前端实施计划
  • 本次改动的实施记录