# Bank Tag Real Rule Phase 1 Backend Implementation Plan

> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 将第一期 9 条银行流水占位规则替换为真实 SQL，并接入现有项目级打标、风险人数回写与结果链路。

**Architecture:** 保持现有 `ccdi_bank_tag_rule + CcdiBankTagServiceImpl + CcdiBankTagAnalysisMapper.xml` 规则式架构不变，不新增模块、不保留兼容性双轨。所有真实命中逻辑统一落在 `CcdiBankTagAnalysisMapper.xml`，Service 只做规则分发和结果装配，参数仍由 `BankTagRuleConfigResolver` 解析。

**Tech Stack:** Java 21, Spring Boot 3, MyBatis XML, Maven, JUnit 5, Mockito, MySQL

---

### Task 1: 先锁定第一期规则边界与参数映射

**Files:**
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java`
- Modify: `sql/ccdi_model_param.sql`
- Modify: `sql/2026-03-16-update-ccdi-model-param-defaults.sql`
- Reference: `assets/模型信息.xlsx`
- Reference: `docs/design/2026-03-20-bank-tag-real-rule-two-phase-design.md`

- [ ] **Step 1: Write the failing test**

在 `BankTagRuleConfigResolverTest.java` 中补第一期参数映射断言，至少覆盖：

- `SINGLE_PURCHASE_AMOUNT`
- `SINGLE_SETTLEMENT_AMOUNT`
- `WITHDRAW_CNT`
- `STOCK_TFR_LARGE`
- `LARGE_STOCK_TRADING`

并补“无参数规则仍返回空参数集”的断言，至少覆盖：

- `GAMBLING_SENSITIVE_KEYWORD`
- `SPECIAL_AMOUNT_TRANSACTION`
- `SUSPICIOUS_INCOME_KEYWORD`
- `LARGE_PURCHASE_TRANSACTION`

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
mvn test -pl ccdi-project -Dtest=BankTagRuleConfigResolverTest
```

Expected:

- `FAIL`
- 原因是第一期规则参数映射或默认参数脚本尚未全部对齐

- [ ] **Step 3: Write minimal implementation**

按第一期规则校准参数映射与默认参数脚本：

- 在 `BankTagRuleConfigResolver.java` 中补第一期规则的 `RULE_PARAM_MAPPING`
- 在 `sql/ccdi_model_param.sql` 中核对并补齐第一期阈值参数初始化
- 在 `sql/2026-03-16-update-ccdi-model-param-defaults.sql` 中同步已有环境默认值修正

要求：

- 只补第一期需要的参数
- 不修改第二期规则边界
- 所有新增或修改的 `param_code` 保持全大写

- [ ] **Step 4: Run test to verify it passes**

Run:

```bash
mvn test -pl ccdi-project -Dtest=BankTagRuleConfigResolverTest
```

Expected:

- `PASS`

- [ ] **Step 5: Commit**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolver.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java sql/ccdi_model_param.sql sql/2026-03-16-update-ccdi-model-param-defaults.sql
git commit -m "补齐第一期流水模型参数映射"
```

### Task 2: 为第一期流水明细型规则写失败前 SQL 结构测试

**Files:**
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java`
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml`

- [ ] **Step 1: Write the failing test**

在 `CcdiBankTagAnalysisMapperXmlTest.java` 中为以下规则补结构断言：

- `selectGamblingSensitiveKeywordStatements`
- `selectSpecialAmountTransactionStatements`
- `selectSuspiciousIncomeKeywordStatements`
- `selectForexBuyAmtStatements`
- `selectForexSellAmtStatements`
- `selectLargePurchaseTransactionStatements`
- `selectStockTfrLargeStatements`
- `selectLargeStockTradingStatements`

断言内容：

- 目标 `select` 已存在
- 对应片段不再包含 `where 1 = 0`
- 仍返回 `bankStatementId/groupId/logId/reasonDetail`

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest
```

Expected:

- `FAIL`
- 原因是第一期规则仍是占位 SQL

- [ ] **Step 3: Write minimal implementation**

在 `CcdiBankTagAnalysisMapper.xml` 中把第一期流水明细型规则替换为真实 SQL：

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

实现要求：

- 继续输出 `bankStatementId/groupId/logId/reasonDetail`
- 条件判断尽量直接复用 `assets/模型信息.xlsx` 已校验可执行的 SQL 口径
- `reasonDetail` 要带出摘要、对手方、金额或阈值关键信息，便于后续结果展示与排障
- 不把业务判断搬到 Java 层

- [ ] **Step 4: Run test to verify it passes**

Run:

```bash
mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest
```

Expected:

- `PASS`

- [ ] **Step 5: Commit**

```bash
git add ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java
git commit -m "实现第一期流水明细规则真实SQL"
```

### Task 3: 为第一期对象型规则补真实 SQL 与分发校验

**Files:**
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml`
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java`
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java`
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java`

- [ ] **Step 1: Write the failing test**

补以下断言：

- `selectWithdrawCntObjects` 不再使用占位 SQL
- `CcdiBankTagServiceImplTest` 中 `WITHDRAW_CNT` 能正确分发到 `analysisMapper.selectWithdrawCntObjects(projectId)`
- `WITHDRAW_CNT` 空命中时任务仍正常成功

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest,CcdiBankTagServiceImplTest
```

Expected:

- `FAIL`

- [ ] **Step 3: Write minimal implementation**

在 XML 中实现 `WITHDRAW_CNT` 的真实对象型 SQL，要求：

- 按员工身份证号归并
- 统计微信/支付宝相关提现的单日次数
- 频次阈值使用参数解析结果
- 输出 `objectType/objectKey/reasonDetail`

同时在 `CcdiBankTagServiceImpl.java` 中确认：

- 第一期开启真实 SQL 的规则都命中明确分发分支
- 不会退回 `default -> List.of()`

- [ ] **Step 4: Run test to verify it passes**

Run:

```bash
mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest,CcdiBankTagServiceImplTest
```

Expected:

- `PASS`

- [ ] **Step 5: Commit**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java
git commit -m "接通第一期对象规则真实分发"
```

### Task 4: 做第一期后端回归与脚本对齐验证

**Files:**
- Modify: `sql/2026-03-16-bank-tagging.sql`
- Create: `docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md`
- Create: `docs/tests/records/2026-03-20-bank-tag-real-rule-phase1-backend-verification.md`
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceRiskCountRefreshTest.java`

- [ ] **Step 1: Align rule metadata SQL**

核对 `sql/2026-03-16-bank-tagging.sql` 中第一期规则元数据，要求：

- `rule_code`、`indicator_code`、`param_code` 保持全大写
- `remark` 从“占位规则，待补充真实SQL”调整为真实规则描述，或至少不再误导为占位
- 不误改第二期规则

- [ ] **Step 2: Run targeted regression**

Run:

```bash
mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest,BankTagRuleConfigResolverTest,CcdiBankTagServiceImplTest,CcdiBankTagServiceRiskCountRefreshTest
```

Expected:

- `PASS`
- 第一期开启真实 SQL 后，风险人数回写链路不回退

- [ ] **Step 3: Write implementation record**

在 `docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md` 中记录：

- 第一期 9 条规则范围
- 参数映射调整内容
- XML 真实 SQL 替换内容
- Service 分发调整内容
- 与第二期边界

- [ ] **Step 4: Write verification record**

在 `docs/tests/records/2026-03-20-bank-tag-real-rule-phase1-backend-verification.md` 中记录：

- 执行命令
- 执行时间
- 结果摘要
- 结论

- [ ] **Step 5: Commit**

```bash
git add sql/2026-03-16-bank-tagging.sql docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md docs/tests/records/2026-03-20-bank-tag-real-rule-phase1-backend-verification.md
git commit -m "补充第一期流水模型后端实施记录"
```
