# 银行流水模型真实规则两阶段落地设计文档

**模块**: 银行流水打标
**日期**: 2026-03-20

## 一、背景

当前项目已经具备银行流水打标基础链路：

- 规则元数据表 `ccdi_bank_tag_rule`
- 结果表 `ccdi_bank_statement_tag_result`
- 任务表 `ccdi_bank_tag_task`
- 规则执行入口 `CcdiBankTagServiceImpl`
- SQL 承载文件 `CcdiBankTagAnalysisMapper.xml`
- 参数解析器 `BankTagRuleConfigResolver`

其中“大额交易”模型下的首批规则已经具备真实 SQL，其余不少规则虽然已经补齐了：

- `rule_code`
- `model_code`
- Service 分发入口
- Mapper 方法签名
- XML `select`

但当前 XML 仍是 `where 1 = 0` 的占位 SQL，尚未产生真实命中结果。

根据 [assets/模型信息.xlsx](/Users/wkc/Desktop/ccdi/ccdi/assets/模型信息.xlsx) 当前整理结果，现有未真实实现、且在本环境中已判定可直接执行 SQL 的银行流水模型共 19 条。本次需求是将这 19 条规则从“占位规则”替换为“真实规则”。

## 二、目标

本次设计目标如下：

1. 将 19 条未真实实现的银行流水模型接入现有真实打标链路。
2. 保持现有规则式架构不变，不新增平行模块或兼容性补丁链路。
3. 将真实命中逻辑统一收敛到 `CcdiBankTagAnalysisMapper.xml`。
4. 补齐规则执行所需的参数映射、初始化 SQL 与验证测试。
5. 为控制改动规模，将 19 条规则拆成两期实施，并分别产出前后端实施计划。

## 三、范围

### 3.1 本次范围

- `CcdiBankTagAnalysisMapper.xml` 中 19 条占位规则替换为真实 SQL
- `CcdiBankTagServiceImpl` 中对应规则的真实执行分发校准
- `BankTagRuleConfigResolver` 中新增规则参数映射补齐
- `sql/` 下与本次规则相关的初始化脚本或增量脚本调整
- 单元测试、结构测试与回归测试补齐
- 新增 1 份设计文档、2 份后端实施计划、2 份前端实施计划

### 3.2 不在本次范围

- 不新增前端页面字段、交互或展示组件
- 不引入动态规则引擎、脚本注册中心或 DSL
- 不新增数据库表结构
- 不处理 `xlsx` 中当前环境不可直接执行的规则
- 不改造“大额交易”已真实落地的 8 条规则逻辑

## 四、现状分析

### 4.1 当前实现结构

当前银行流水打标流程为：

1. `CcdiBankTagServiceImpl.rebuildProject(...)` 加载启用规则。
2. 按 `rule_code` 分发到 `executeStatementRule / executeObjectRule`。
3. 通过 `CcdiBankTagAnalysisMapper` 调用 XML 中的具体 SQL。
4. 将命中结果组装为 `CcdiBankTagResult` 后批量入库。
5. 刷新项目风险人数，供结果总览等后续页面使用。

### 4.2 当前核心问题

19 条目标规则目前已具备“入口”，但不具备“真实命中能力”：

- `ccdi_bank_tag_rule` 中已有规则元数据
- `CcdiBankTagServiceImpl` 中已有大部分分发分支
- `CcdiBankTagAnalysisMapper.java` 中已有对应方法
- `CcdiBankTagAnalysisMapper.xml` 中对应 `<select>` 仍为占位 SQL

因此当前的主要缺口不是“补骨架”，而是“把占位 SQL 换成真实规则 SQL，并补齐参数映射与测试”。

### 4.3 当前环境可直接落地的 19 条规则

#### 第一期

- `GAMBLING_SENSITIVE_KEYWORD`
- `SPECIAL_AMOUNT_TRANSACTION`
- `SUSPICIOUS_INCOME_KEYWORD`
- `SINGLE_PURCHASE_AMOUNT`
- `SINGLE_SETTLEMENT_AMOUNT`
- `LARGE_PURCHASE_TRANSACTION`
- `STOCK_TFR_LARGE`
- `LARGE_STOCK_TRADING`
- `WITHDRAW_CNT`

#### 第二期

- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- `MULTI_PARTY_GAMBLING_TRANSFER`
- `MONTHLY_FIXED_INCOME`
- `FIXED_COUNTERPARTY_TRANSFER`
- `HOUSE_REGISTRATION_MISMATCH`
- `PROPERTY_FEE_REGISTRATION_MISMATCH`
- `TAX_ASSET_REGISTRATION_MISMATCH`
- `SUPPLIER_CONCENTRATION`
- `SALARY_QUICK_TRANSFER`
- `SALARY_UNUSED`

## 五、方案对比

### 5.1 方案一：一次性直接替换 19 条占位 SQL

优点：

- 最短路径
- 架构最稳定
- 规则口径统一落地后可立即进入现有结果链路

缺点：

- 单次改动面较大
- SQL、参数、测试回归压力集中

### 5.2 方案二：按模型组拆成多轮交付

优点：

- 单次改动更小

缺点：

- 一部分规则真实、一部分规则仍占位，阶段内口径不完整
- 和本次“一次性纳入两批规划”的目标不一致

### 5.3 方案三：改造成更通用的动态规则架构

优点：

- 长期可维护性表面上更统一

缺点：

- 明显超出本次需求
- 会把风险扩大到 Service、Mapper、配置、测试结构整体重构

### 5.4 结论

采用方案一，但执行层面拆成两期实施：

- 总体架构保持不变
- 设计一次性定稿
- 实施按“先易后难”拆成两期

## 六、总体设计

### 6.1 架构原则

本次遵循以下原则：

1. 不引入新模块
2. 不新增兼容性双轨逻辑
3. 不在 Java Service 层补业务口径判断
4. 所有真实命中逻辑统一落在 `CcdiBankTagAnalysisMapper.xml`
5. 参数解析仍通过 `BankTagRuleConfigResolver`

### 6.2 数据流

真实规则执行链路保持为：

1. `CcdiBankTagServiceImpl.rebuildProject(...)` 发起重算。
2. `ruleMapper.selectEnabledRules(modelCode)` 获取启用规则。
3. `BankTagRuleConfigResolver.resolve(projectId, rule)` 解析项目有效参数。
4. `executeStatementRule / executeObjectRule` 依据 `rule_code` 分发。
5. `CcdiBankTagAnalysisMapper.xml` 执行真实 SQL，返回 `STATEMENT` 或 `OBJECT` 命中结果。
6. Service 将命中结果组装为 `CcdiBankTagResult` 并批量入库。
7. 调用 `projectOverviewService.refreshProjectRiskCounts(projectId, operator)` 刷新项目风险人数。

### 6.3 规则落地边界

#### 流水明细型规则

输出：

- `bankStatementId`
- `groupId`
- `logId`
- `reasonDetail`

代表规则包括：

- `GAMBLING_SENSITIVE_KEYWORD`
- `SPECIAL_AMOUNT_TRANSACTION`
- `SUSPICIOUS_INCOME_KEYWORD`
- `HOUSE_REGISTRATION_MISMATCH`
- `PROPERTY_FEE_REGISTRATION_MISMATCH`
- `TAX_ASSET_REGISTRATION_MISMATCH`
- `LARGE_PURCHASE_TRANSACTION`
- `STOCK_TFR_LARGE`
- `LARGE_STOCK_TRADING`
- 外汇购汇/结汇规则

#### 对象型规则

输出：

- `objectType`
- `objectKey`
- `reasonDetail`

对象维度统一使用员工主键口径：

- `objectType = STAFF_ID_CARD`
- `objectKey = 员工身份证号`

代表规则包括：

- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- `MULTI_PARTY_GAMBLING_TRANSFER`
- `MONTHLY_FIXED_INCOME`
- `FIXED_COUNTERPARTY_TRANSFER`
- `SUPPLIER_CONCENTRATION`
- `WITHDRAW_CNT`
- `SALARY_QUICK_TRANSFER`
- `SALARY_UNUSED`

### 6.4 参数策略

参数只通过现有 `ccdi_model_param` 获取，不新增第二参数源。

本次需要补齐的规则参数映射包括：

- `MULTI_PARTY_GAMBLING_TRANSFER` -> `MULTI_PARTY_AMT_MIN`、`MULTI_PARTY_AMT_MAX`
- `FIXED_COUNTERPARTY_TRANSFER` -> `FIXED_COUNTERPARTY_TRANSFER_MIN`、`FIXED_COUNTERPARTY_TRANSFER_MAX`
- `SINGLE_PURCHASE_AMOUNT` 对应购汇类单值阈值
- `SINGLE_SETTLEMENT_AMOUNT` 对应结汇类单值阈值
- `WITHDRAW_CNT` 对应提现频次阈值
- `STOCK_TFR_LARGE`、`LARGE_STOCK_TRADING` 等单值阈值按现有参数脚本统一校准

对本身不依赖阈值的规则，不强行补充虚假参数。

### 6.5 错误处理策略

本次不增加补丁式兜底逻辑：

- 真实 SQL 报错：整次打标任务按现有逻辑失败
- 规则无命中：任务正常成功，命中数为 0
- 参数缺失：按现有解析结果暴露问题，并通过脚本与测试补齐

## 七、两期拆分设计

### 7.1 第一期设计目标

优先替换依赖简单、回归范围可控的规则，形成第一批真实命中能力。

第一期规则：

- `GAMBLING_SENSITIVE_KEYWORD`
- `SPECIAL_AMOUNT_TRANSACTION`
- `SUSPICIOUS_INCOME_KEYWORD`
- `SINGLE_PURCHASE_AMOUNT`
- `SINGLE_SETTLEMENT_AMOUNT`
- `LARGE_PURCHASE_TRANSACTION`
- `STOCK_TFR_LARGE`
- `LARGE_STOCK_TRADING`
- `WITHDRAW_CNT`

第一期特点：

- 单表筛选为主
- 依赖关系较少
- 参数映射简单
- 适合先完成真实 SQL 替换和基础回归

### 7.2 第二期设计目标

完成跨表比对、对象聚合和窗口口径更复杂的规则。

第二期规则：

- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- `MULTI_PARTY_GAMBLING_TRANSFER`
- `MONTHLY_FIXED_INCOME`
- `FIXED_COUNTERPARTY_TRANSFER`
- `HOUSE_REGISTRATION_MISMATCH`
- `PROPERTY_FEE_REGISTRATION_MISMATCH`
- `TAX_ASSET_REGISTRATION_MISMATCH`
- `SUPPLIER_CONCENTRATION`
- `SALARY_QUICK_TRANSFER`
- `SALARY_UNUSED`

第二期特点：

- 跨表比对较多
- 聚合口径更复杂
- 对交易时间、关系人口径、资产登记口径更敏感

## 八、测试设计

### 8.1 XML 结构测试

在 `CcdiBankTagAnalysisMapperXmlTest` 中补充：

- 目标规则不再使用 `where 1 = 0`
- 新增真实 SQL 仍满足 XML 结构合法
- `STATEMENT` 规则仍返回完整命中字段
- `OBJECT` 规则仍返回完整命中字段

### 8.2 参数解析测试

在 `BankTagRuleConfigResolverTest` 中补充：

- 新增规则参数映射断言
- 双阈值规则参数完整性断言
- 无参数规则仍返回空参数集

### 8.3 Service 分发测试

在 `CcdiBankTagServiceImplTest` 中补充：

- 每条新增规则都能命中正确 Mapper 方法
- 不再落入默认空分支
- 真实规则空命中时任务仍可成功结束

### 8.4 受影响链路回归

至少覆盖：

- `CcdiBankTagAnalysisMapperXmlTest`
- `BankTagRuleConfigResolverTest`
- `CcdiBankTagServiceImplTest`
- 受影响的项目风险人数回写与结果总览后端测试

## 九、文档产物

按仓库规范，本次输出以下文档：

1. 本设计文档：
   - `docs/design/2026-03-20-bank-tag-real-rule-two-phase-design.md`
2. 第一期后端实施计划：
   - `docs/plans/backend/2026-03-20-bank-tag-real-rule-phase1-backend-implementation.md`
3. 第一期前端实施计划：
   - `docs/plans/frontend/2026-03-20-bank-tag-real-rule-phase1-frontend-implementation.md`
4. 第二期后端实施计划：
   - `docs/plans/backend/2026-03-20-bank-tag-real-rule-phase2-backend-implementation.md`
5. 第二期前端实施计划：
   - `docs/plans/frontend/2026-03-20-bank-tag-real-rule-phase2-frontend-implementation.md`

其中前端实施计划用于明确边界：

- 本期无前端代码改造
- 前端仅做依赖说明和联调预期记录

## 十、结论

本方案采用“现有架构内真实替换占位 SQL”的最短路径设计，并将 19 条目标规则拆成两期实施：

- 第一期先处理依赖少、风险低的 9 条规则
- 第二期再处理聚合与跨表逻辑更重的 10 条规则

这样既满足“一次性完成完整设计”的要求，又能在实施阶段有效控制改动规模和回归风险，不会偏离当前项目既有技术路线。
