补充异常账户模型打标设计文档

This commit is contained in:
wkc
2026-03-31 16:12:45 +08:00
parent a8e15e16d9
commit 3741ef5fe4
2 changed files with 420 additions and 0 deletions

View File

@@ -0,0 +1,382 @@
# 异常账户模型接入银行流水打标设计文档
**模块**: 银行流水打标
**日期**: 2026-03-31
## 一、背景
当前银行流水打标主链路已经具备以下基础能力:
- 规则元数据管理与启用控制
- `CcdiBankTagServiceImpl` 统一执行入口
- `CcdiBankTagAnalysisMapper.xml` 承载真实规则 SQL
- `ccdi_bank_statement_tag_result` 统一承载 `STATEMENT / OBJECT` 命中结果
- 项目风险总览按对象型结果聚合员工风险情况
根据 [异常账户.xlsx](/Users/wkc/Desktop/ccdi/ccdi/assets/异常账户.xlsx) 与 [员工账户.xlsx](/Users/wkc/Desktop/ccdi/ccdi/assets/员工账户.xlsx),本次需要新增独立模型“异常账户”,并正式接入以下两条规则:
- `SUDDEN_ACCOUNT_CLOSURE`:突然销户
- `DORMANT_ACCOUNT_LARGE_ACTIVATION`:休眠账户大额启用
这两条规则均依赖新增账户信息表 `ccdi_account_info`,且风险筛查对象明确为“员工本人”。本次目标是在不改造现有打标架构的前提下,将两条规则纳入现有项目打标主链路,并补充能够稳定命中的测试数据与验证手段。
## 二、目标
本次设计目标如下:
1. 新增账户信息表 `ccdi_account_info`,支撑异常账户规则计算。
2. 新增独立模型 `ABNORMAL_ACCOUNT`,并接入 2 条对象型规则。
3. 将两条规则接入现有 `executeObjectRule(...)` 打标链路,不新增平行处理模块。
4. 补充最小可命中的测试数据 SQL并覆盖正样本与反样本。
5. 保留 Java 自动化测试,同时在验证阶段使用 MySQL MCP 执行真实 SQL确认命中结果符合业务口径。
6. 在设计确认后,分别产出后端与前端实施计划文档。
## 三、范围
### 3.1 本次范围
- 新增 `ccdi_account_info` 建表 SQL
- 新增模型 `ABNORMAL_ACCOUNT`
- 新增规则元数据 `SUDDEN_ACCOUNT_CLOSURE``DORMANT_ACCOUNT_LARGE_ACTIVATION`
- `CcdiBankTagServiceImpl` 新增对象型规则分发
- `CcdiBankTagAnalysisMapper.java/.xml` 新增 2 条对象型查询
- 新增测试数据 SQL
- 新增 Java 自动化测试
- 新增基于 MySQL MCP 的真实 SQL 验证步骤
- 新增设计文档、后端实施计划、前端实施计划
### 3.2 不在本次范围
- 不开发“异常账户人员信息”独立查询、分页、详情、导出真实数据链路
- 不改前端页面展示逻辑
- 不扩展到关系人或外部账户
- 不新增动态规则引擎、DSL 或兼容性补丁方案
- 不改造 `lsfx-mock-server`
- 不将固定阈值改造成项目可配置参数
## 四、现状分析
### 4.1 当前主链路
当前项目级银行流水打标流程为:
1. `CcdiBankTagServiceImpl.rebuildProject(...)` 加载启用规则。
2. 规则按 `rule_code` 分发到 `executeStatementRule(...)``executeObjectRule(...)`
3. `CcdiBankTagAnalysisMapper.xml` 执行真实 SQL返回流水型或对象型命中结果。
4. Service 将命中结果组装为 `CcdiBankTagResult` 并写入 `ccdi_bank_statement_tag_result`
5. 项目结果总览再按对象维度聚合风险人数和命中规则快照。
### 4.2 当前缺口
当前仓库中“异常账户人员信息”仍为占位展示,且主打标规则中尚无“异常账户”模型与对应规则编码。也就是说,本次缺口主要是:
- 缺少账户信息基础表
- 缺少异常账户模型与规则元数据
- 缺少两条规则的对象型 SQL
- 缺少最小可命中的测试样本与真实 SQL 验证
## 五、方案对比
### 5.1 方案一:最小闭环接入现有对象型打标链路
做法:
- 新增独立模型 `ABNORMAL_ACCOUNT`
- 两条规则均按 `OBJECT` 结果类型落到员工维度
- 通过 `CcdiBankTagAnalysisMapper.xml` 计算命中结果
- 结果继续写入 `ccdi_bank_statement_tag_result`
优点:
- 改动最小
- 完全复用现有打标主链路
- 能直接进入现有员工风险总览聚合
缺点:
- 本轮不打通“异常账户人员信息”独立详情链路
### 5.2 方案二:在方案一基础上同时打通异常账户独立结果链路
优点:
- 风险详情中的“异常账户人员信息”可展示真实数据
缺点:
- 改动范围明显扩大
- 超出本次需求
- 不符合最短路径实现要求
### 5.3 方案三:仅补 SQL 验证,不接入主系统打标链路
优点:
- 开发最省
缺点:
- 无法满足“正式接入主系统打标链路”的需求
### 5.4 结论
采用方案一:
- 新增独立模型 `ABNORMAL_ACCOUNT`
- 两条规则均按对象型规则接入现有打标链路
- 结果沉淀到现有结果表
- 后续如需开发异常账户独立查询能力,再以此为基础扩展
## 六、总体设计
### 6.1 模型与规则设计
本次新增如下模型与规则:
- 模型编码:`ABNORMAL_ACCOUNT`
- 模型名称:`异常账户`
- 规则一:`SUDDEN_ACCOUNT_CLOSURE` / `突然销户`
- 规则二:`DORMANT_ACCOUNT_LARGE_ACTIVATION` / `休眠账户大额启用`
两条规则统一定义为:
- `result_type = OBJECT`
- `object_type = STAFF_ID_CARD`
- `object_key = 员工身份证号`
### 6.2 结果落库
两条规则命中后继续写入现有结果表 `ccdi_bank_statement_tag_result`,不新增单独结果表。
结果字段约束如下:
- `model_code = ABNORMAL_ACCOUNT`
- `rule_code` 使用全大写风格
- `result_type = OBJECT`
- `bank_statement_id = null`
- `object_type = STAFF_ID_CARD`
- `object_key = 员工身份证号`
- `reason_detail` 存储账户号、异常日期与统计快照
### 6.3 数据流
数据流保持为:
1. 项目级打标入口加载启用规则。
2. 当规则编码为 `SUDDEN_ACCOUNT_CLOSURE``DORMANT_ACCOUNT_LARGE_ACTIVATION` 时,进入 `executeObjectRule(...)`
3. Mapper SQL 在项目范围内将 `ccdi_bank_statement``ccdi_account_info``ccdi_base_staff` 关联。
4. SQL 返回员工身份证号维度的对象型命中结果。
5. Service 将命中结果写入 `ccdi_bank_statement_tag_result`
6. 员工风险聚合继续从该结果表汇总,无需新建平行链路。
## 七、表结构设计
### 7.1 新增表 `ccdi_account_info`
以 [员工账户.xlsx](/Users/wkc/Desktop/ccdi/ccdi/assets/员工账户.xlsx) 为准,新增表 `ccdi_account_info`,核心字段如下:
- `account_id`
- `account_no`
- `account_type`
- `account_name`
- `owner_type`
- `owner_id`
- `bank`
- `bank_code`
- `currency`
- `is_self_account`
- `monthly_avg_trans_count`
- `monthly_avg_trans_amount`
- `trans_freq_type`
- `dr_max_single_amount`
- `cr_max_single_amount`
- `dr_max_daily_amount`
- `cr_max_daily_amount`
- `trans_risk_level`
- `status`
- `effective_date`
- `invalid_date`
- `created_by`
- `updated_by`
- `create_time`
- `update_time`
### 7.2 关联约束
本次规则只识别员工本人账户,关联口径固定为:
- `ccdi_account_info.owner_type = 'EMPLOYEE'`
- `ccdi_account_info.owner_id = ccdi_base_staff.id_card`
- `ccdi_account_info.account_no = ccdi_bank_statement.LE_ACCOUNT_NO`
说明:
- 仓库中当前未见单独的账号加解密或标准化链路,因此本次设计要求建表脚本、测试数据与流水数据直接使用一致账号值
- 本次不将关系人账户纳入规则范围
## 八、规则 SQL 口径
### 8.1 `SUDDEN_ACCOUNT_CLOSURE`
业务口径:
- 员工本人账户已销户
- 销户日前 30 天内仍存在交易记录
SQL 设计约束:
- 仅统计项目内流水
- 统计窗口限定为 `[invalid_date - 30天, invalid_date)`
- 按“员工身份证号 + 账号”粒度聚合,再映射回员工对象
命中条件:
- `status = 2`
- `invalid_date is not null`
- 窗口内存在至少 1 笔交易
返回结果:
- `objectType = STAFF_ID_CARD`
- `objectKey = 员工身份证号`
`reasonDetail` 结构:
- `账户{account_no}于{invalid_date}销户销户前30天内最后交易日{last_tx_date},累计交易金额{window_total_amount}元,单笔最大金额{window_max_single_amount}元`
### 8.2 `DORMANT_ACCOUNT_LARGE_ACTIVATION`
业务口径:
- 员工本人账户状态正常
- 开户后长期未使用
- 首次启用后出现大额资金流动
SQL 设计约束:
- 仅统计项目内流水
- 以该账户在项目内的首次流水日期作为“启用时间”
- “沉睡时长”按开户日期到首次交易日期计算
命中条件:
- `status = 1`
- `effective_date is not null`
- `first_tx_date >= effective_date + 6个月`
- 且满足以下任一:
- 启用后累计交易总额 `>= 500000`
- 启用后单笔最大交易金额 `>= 100000`
返回结果:
- `objectType = STAFF_ID_CARD`
- `objectKey = 员工身份证号`
`reasonDetail` 结构:
- `账户{account_no}开户于{effective_date},首次交易日期{first_tx_date},沉睡时长{dormant_months}个月,启用后累计交易金额{total_amount}元,单笔最大金额{max_single_amount}元`
### 8.3 公共规则约束
- 仅识别员工本人账户,不识别关系人和外部账户
- 仅按项目内流水计算,不跨项目拼接历史流水
- 累计金额使用 `amount_dr + amount_cr`
- 单笔最大金额使用 `greatest(amount_dr, amount_cr)`
- 同一员工多个账户分别判断,允许同一规则写入多条结果,避免强行合并后丢失账户级快照
## 九、测试数据设计
### 9.1 测试数据组织原则
新增一份独立增量 SQL放在 `sql/migration/`,仅构造本次规则所需最小样本。
### 9.2 样本设计
建议最少包含以下样本:
- 员工 A命中 `SUDDEN_ACCOUNT_CLOSURE`
- 账户已销户
- 销户前 30 天内有 2 到 3 笔项目流水
- 员工 B命中 `DORMANT_ACCOUNT_LARGE_ACTIVATION`
- 开户日期早于首次交易至少 6 个月
- 启用后累计金额超过 50 万
- 员工 C休眠不足 6 个月,不命中
- 员工 D已销户但销户前 30 天无流水,不命中
### 9.3 数据一致性要求
- `ccdi_account_info.account_no``ccdi_bank_statement.LE_ACCOUNT_NO` 必须一致
- `owner_id` 与员工身份证号一致
- 正样本与反样本必须处于同一项目验证口径下,避免跨项目误差
## 十、测试与验证设计
### 10.1 Java 自动化测试
保留两层自动化测试:
1. Service 分发测试
- 新规则能进入 `executeObjectRule(...)`
2. Mapper / SQL 结构测试
- 新 Mapper 方法存在
- XML 中存在对应 `<select>`
- 规则元数据和模型编码无拼写错误
3. 结果聚合测试
- 新规则写入后,员工风险总览可正常聚合
### 10.2 MySQL MCP 真实 SQL 验证
本次新增一层真实 SQL 验证,要求在测试阶段直接通过 MySQL MCP 执行规则 SQL确认结果符合口径。
验证要求:
- 使用项目数据库连接信息
- 不手写 `mysql -e`
- 直接执行对象型规则对应 SQL
- 校验命中员工身份证号是否与测试样本一致
- 校验反样本不会被查出
- 校验 `reason_detail` 中异常日期、累计金额、单笔最大金额等关键快照是否符合预期
### 10.3 测试结束清理
若验证阶段启动了本地前后端、Mock 服务或其他辅助进程,测试结束后需主动关闭,避免残留占用端口。
## 十一、实施边界
### 11.1 后端实施内容
- 新增建表与规则元数据 SQL
- 新增 Mapper 方法和 XML SQL
- 新增 Service 分发
- 新增测试数据 SQL
- 新增自动化测试
- 执行 MySQL MCP SQL 验证
### 11.2 前端实施内容
本轮前端原则上不改代码,但仍需产出一份前端实施计划,明确说明:
- 现有页面继续复用项目总览对象聚合结果
- 本轮不开发异常账户独立列表与详情
- 前端无需新增接口或交互
## 十二、验收标准
验收标准如下:
1. `ccdi_account_info` 建表脚本存在且字段与 Excel 一致。
2. 模型 `ABNORMAL_ACCOUNT` 与两条规则元数据已落库,编码统一全大写。
3. `CcdiBankTagServiceImpl` 已接入两条规则对象型执行分支。
4. 规则命中结果成功写入 `ccdi_bank_statement_tag_result`
5. 员工风险总览聚合后可看到新增模型与规则命中。
6. 测试数据中的正样本可命中,反样本不命中。
7. MySQL MCP 真实 SQL 验证结果与业务口径一致。
## 十三、后续文档规划
设计确认后,继续补充以下文档:
- `docs/plans/backend/` 下的后端实施计划
- `docs/plans/frontend/` 下的前端实施计划
- `docs/reports/implementation/` 下的后端实施记录
- `docs/reports/implementation/` 下的前端实施记录

View File

@@ -0,0 +1,38 @@
# 异常账户模型接入银行流水打标设计记录
**日期**: 2026-03-31
**类型**: 设计记录
**范围**: 银行流水打标 - 异常账户模型
## 1. 本次变更内容
新增正式设计文档:
- `docs/design/2026-03-31-abnormal-account-bank-tag-design.md`
设计结论如下:
- 新增独立模型 `ABNORMAL_ACCOUNT`
- 新增两条对象型规则:
- `SUDDEN_ACCOUNT_CLOSURE`
- `DORMANT_ACCOUNT_LARGE_ACTIVATION`
- 新增账户信息表 `ccdi_account_info`
- 规则结果继续落到 `ccdi_bank_statement_tag_result`
- 通过测试数据 SQL、Java 自动化测试和 MySQL MCP 真实 SQL 验证共同确认命中口径
## 2. 设计约束
- 不开发异常账户独立查询、分页或详情链路
- 不改前端展示逻辑
- 不扩展到关系人或外部账户
- 不增加动态规则引擎或兼容性补丁方案
- 不改造 `lsfx-mock-server`
## 3. 后续文档规划
待用户确认设计文档后,继续补充:
- 后端实施计划
- 前端实施计划
- 后端实施记录
- 前端实施记录