diff --git a/docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md b/docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md new file mode 100644 index 00000000..d07122fb --- /dev/null +++ b/docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md @@ -0,0 +1,285 @@ +# 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](/Users/wkc/Desktop/ccdi/ccdi/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 未命中规则时的处理 + +当某个 `logId` 的 `abnormal_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 看起来合理但后端不命中”的问题 + +## 十二、后续计划 + +本设计确认后,下一步仅进入实施计划编写阶段,不直接扩展其他功能。 + +按仓库约定,需要继续补充: + +- 后端实施计划 +- 前端实施计划 +- 本次改动的实施记录 diff --git a/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-design-record.md b/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-design-record.md new file mode 100644 index 00000000..a2e6ed01 --- /dev/null +++ b/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-design-record.md @@ -0,0 +1,36 @@ +# LSFX Mock Server 异常账户命中流水设计记录 + +**日期**: 2026-03-31 +**类型**: 设计记录 +**范围**: `lsfx-mock-server` 异常账户命中流水 + +## 1. 本次变更内容 + +新增正式设计文档: + +- `docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md` + +设计结论如下: + +- 在现有 `rule_hit_plan` 体系中新增 `abnormal_account_hit_rules` +- 在 `FileRecord` 中新增异常账户事实 `abnormal_accounts` +- 通过 `statement_rule_samples.py` 新增两类异常账户命中样本: + - `SUDDEN_ACCOUNT_CLOSURE` + - `DORMANT_ACCOUNT_LARGE_ACTIVATION` +- 保持现有流水接口协议不变,只在 Mock 服务内部补齐“账户事实 + 命中流水”闭环 + +## 2. 设计约束 + +- 不新增异常账户独立接口 +- 不修改现有 `/watson/api/project/getBSByLogId` 返回结构 +- 不把异常账户事实直接暴露给前端 +- 不模拟 `ccdi_account_info` 全字段,只保留规则计算所需最小字段 +- 不开启 subagent;本次设计文档采用本地人工复核替代 spec subagent review + +## 3. 后续文档规划 + +待用户确认设计文档后,继续补充: + +- 后端实施计划 +- 前端实施计划 +- Mock 服务实施记录