# Bank Tag Placeholder Models 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:** 根据 `assets/模型信息.xlsx` 补齐现有银行流水打标缺失模型的后端规则骨架，让新增规则可以进入统一打标流程，并通过 XML 占位 SQL 保证执行不报错且不产生伪命中结果。

**Architecture:** 继续沿用现有 `ccdi_bank_tag_rule + CcdiBankTagServiceImpl + CcdiBankTagAnalysisMapper.xml` 的规则式架构，不引入动态 SQL。新增规则只补“规则定义 + 分发入口 + XML 独立占位查询”，真实业务 SQL 后续逐条替换；本期不改现有 8 条大额交易规则逻辑。

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

---

### Task 1: 补齐规则清单与初始化 SQL

**Files:**
- Reference: `assets/模型信息.xlsx`
- Reference: `docs/design/2026-03-18-bank-tag-model-placeholder-design.md`
- Modify: `sql/2026-03-16-bank-tagging.sql`

- [ ] **Step 1: 盘点缺失规则**

对照 `assets/模型信息.xlsx` 与 `sql/2026-03-16-bank-tagging.sql`，列出当前未落库的 25 条规则，确认每条规则的：

- `model_code`
- `model_name`
- `rule_code`
- `rule_name`
- `indicator_code`
- `result_type`
- `risk_level`
- `business_caliber`
- `sort_order`

- [ ] **Step 2: 写失败前检查**

运行：

```bash
rg -n "ABNORMAL_TRANSACTION|SUSPICIOUS_RELATION|SUSPICIOUS_PROPERTY|SUSPICIOUS_PURCHASE|SUSPICIOUS_INTEREST_PAYMENT" sql/2026-03-16-bank-tagging.sql
```

预期：当前命中为空或明显不完整，说明缺失模型尚未写入初始化 SQL。

- [ ] **Step 3: 更新规则初始化数据**

在 `sql/2026-03-16-bank-tagging.sql` 中：

- 保留现有 8 条 `LARGE_TRANSACTION` 规则不变
- 按设计稿补齐其余 25 条规则的 `INSERT INTO ccdi_bank_tag_rule`
- `rule_code` 生成规则遵循设计稿：
  - 优先复用 Excel 已有英文指标名
  - 无英文指标名时使用 `<MODEL_CODE>_<两位序号>` 占位编码
- `result_type` 按“流水明细/个人”等返回形式映射为 `STATEMENT` 或 `OBJECT`
- `risk_level` 映射为 `HIGH`、`GENERAL` 或 `NULL`
- `remark` 统一写明“占位规则，待补充真实SQL”

- [ ] **Step 4: 静态自检**

运行：

```bash
sed -n '1,220p' sql/2026-03-16-bank-tagging.sql
```

预期：

- 所有 10 个模型组均已出现
- 现有 8 条规则仍在
- 新增规则字段完整，没有手工遗漏列值

- [ ] **Step 5: 提交**

```bash
git add sql/2026-03-16-bank-tagging.sql
git commit -m "补齐流水打标规则初始化数据"
```

### Task 2: 为缺失规则补齐 Mapper 接口与 XML 占位 SQL

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

- [ ] **Step 1: 写失败前测试**

先在 `CcdiBankTagAnalysisMapperXmlTest.java` 增加两个失败测试，示例结构如下：

```java
@Test
void allPlaceholderRules_shouldExistInAnalysisMapperXml() throws Exception {
    String xml = readXml(RESOURCE);
    assertTrue(xml.contains("selectAbnormalTransactionStatements"));
    assertTrue(xml.contains("selectSuspiciousPropertyObjects"));
}

@Test
void placeholderRules_shouldUseEmptyResultSqlTemplate() throws Exception {
    String xml = readXml(RESOURCE);
    assertTrue(xml.contains("where 1 = 0"));
}
```

- [ ] **Step 2: 运行测试确认失败**

运行：

```bash
mvn test -pl ccdi-project -am -Dtest=CcdiBankTagAnalysisMapperXmlTest#allPlaceholderRules_shouldExistInAnalysisMapperXml,CcdiBankTagAnalysisMapperXmlTest#placeholderRules_shouldUseEmptyResultSqlTemplate
```

预期：FAIL，提示新规则方法或占位 SQL 尚未存在。

- [ ] **Step 3: 增加 Mapper 方法签名**

在 `CcdiBankTagAnalysisMapper.java` 中为 25 条缺失规则补方法签名，要求：

- `STATEMENT` 规则返回 `List<BankTagStatementHitVO>`
- `OBJECT` 规则返回 `List<BankTagObjectHitVO>`
- 方法命名与 `rule_code` 语义或占位编码一一对应
- 暂不为占位规则增加阈值参数

- [ ] **Step 4: 增加 XML 占位 SQL**

在 `CcdiBankTagAnalysisMapper.xml` 中为每条缺失规则新增独立 `<select>`：

- `STATEMENT` 规则使用 `bankStatementId/groupId/logId/reasonDetail` 四列
- `OBJECT` 规则使用 `objectType/objectKey/reasonDetail` 三列
- 所有占位 SQL 都必须 `where 1 = 0`
- 每条 SQL 单独保留坑位，不复用通用 `select`

参考占位结构：

```xml
<select id="selectSuspiciousPurchaseStatements" resultMap="BankTagStatementHitResultMap">
    select
        bs.bank_statement_id AS bankStatementId,
        bs.group_id AS groupId,
        bs.batch_id AS logId,
        '占位SQL，待补充真实规则' AS reasonDetail
    from ccdi_bank_statement bs
    where 1 = 0
</select>
```

- [ ] **Step 5: 重新运行 XML 测试**

运行：

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

预期：PASS，XML 结构完整、方法名齐全、文档仍然是合法 MyBatis XML。

- [ ] **Step 6: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java 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: 补齐 Service 规则分发并保证空结果任务可成功结束

**Files:**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java`
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java`

- [ ] **Step 1: 写失败前测试**

在 `CcdiBankTagServiceImplTest.java` 中增加两个代表性测试：

```java
@Test
void rebuildProject_shouldDispatchPlaceholderStatementRuleAndFinishWithoutResults() {
    // 规则 resultType=STATEMENT
    // mock analysisMapper.selectXxx() 返回 List.of()
    // 断言 deleteByProjectAndModel 被调用
    // 断言 insertBatch 不会被调用
}

@Test
void rebuildProject_shouldDispatchPlaceholderObjectRuleAndFinishWithoutResults() {
    // 规则 resultType=OBJECT
    // mock analysisMapper.selectXxx() 返回 List.of()
    // 断言任务状态最终更新为 SUCCESS
}
```

- [ ] **Step 2: 运行测试确认失败**

运行：

```bash
mvn test -pl ccdi-project -am -Dtest=CcdiBankTagServiceImplTest#rebuildProject_shouldDispatchPlaceholderStatementRuleAndFinishWithoutResults,CcdiBankTagServiceImplTest#rebuildProject_shouldDispatchPlaceholderObjectRuleAndFinishWithoutResults
```

预期：FAIL，当前 `switch` 还未覆盖新增规则。

- [ ] **Step 3: 补齐规则分发**

在 `CcdiBankTagServiceImpl.java` 中：

- 在 `executeStatementRule` 中补齐所有新增 `STATEMENT` 规则的分发
- 在 `executeObjectRule` 中补齐所有新增 `OBJECT` 规则的分发
- 新增规则统一调用对应占位 Mapper 方法
- 保持现有 8 条大额交易规则的调用方式不变

- [ ] **Step 4: 重新运行服务测试**

运行：

```bash
mvn test -pl ccdi-project -am -Dtest=CcdiBankTagServiceImplTest
```

预期：PASS，新增占位规则不会报错，空结果任务仍能正常完成。

- [ ] **Step 5: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java
git commit -m "补齐流水打标占位规则分发"
```

### Task 4: 固化占位规则的参数解析边界

**Files:**
- Modify if needed: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolver.java`
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java`
- Reference: `sql/ccdi_model_param.sql`
- Reference: `sql/2026-03-16-update-ccdi-model-param-defaults.sql`

- [ ] **Step 1: 先写边界测试**

在 `BankTagRuleConfigResolverTest.java` 中增加一个回归测试，确认占位规则即便没有参数映射也能安全返回：

```java
@Test
void resolve_shouldReturnEmptyThresholdsForPlaceholderRulesWithoutIndicatorCode() {
    // ruleCode 使用新增占位规则
    // indicatorCode 为空
    // 断言 thresholdValues 为空 map
}
```

- [ ] **Step 2: 运行测试确认当前边界**

运行：

```bash
mvn test -pl ccdi-project -am -Dtest=BankTagRuleConfigResolverTest#resolve_shouldReturnEmptyThresholdsForPlaceholderRulesWithoutIndicatorCode
```

预期：

- 若当前实现已满足，测试直接 PASS
- 若实现依赖了不安全的默认逻辑，则先 FAIL，再做最小修正

- [ ] **Step 3: 做最小实现**

遵循最小原则：

- 不为占位规则新增 `RULE_PARAM_MAPPING`
- 不修改现有大额交易参数映射
- 只有在测试暴露不安全行为时，才对 `BankTagRuleConfigResolver.java` 做最小修补
- 本期不改 `sql/ccdi_model_param.sql` 和 `sql/2026-03-16-update-ccdi-model-param-defaults.sql`，避免在无真实 SQL 的前提下引入无效默认参数

- [ ] **Step 4: 运行解析器测试**

运行：

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

预期：PASS，现有阈值规则和新增占位规则都能安全解析。

- [ ] **Step 5: 提交**

```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
git commit -m "明确占位规则参数解析边界"
```

### Task 5: 做全量编译与交付前验证

**Files:**
- Reference: `sql/2026-03-16-bank-tagging.sql`
- Reference: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml`
- Optional Record: `docs/tests/records/bank-tag-placeholder-backend-test.md`

- [ ] **Step 1: 运行后端核心测试集**

运行：

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

预期：PASS。

- [ ] **Step 2: 运行模块编译**

运行：

```bash
mvn -pl ccdi-project -am -DskipTests compile
```

预期：BUILD SUCCESS。

- [ ] **Step 3: 如需落库验证，使用 UTF-8 执行脚本**

如需在本地库验证中文 SQL 脚本，必须运行：

```bash
bin/mysql_utf8_exec.sh sql/2026-03-16-bank-tagging.sql
```

预期：脚本执行成功，中文模型名与规则名不乱码。

- [ ] **Step 4: 做最终 diff 自检**

运行：

```bash
git diff -- .gitignore sql/2026-03-16-bank-tagging.sql ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolver.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java
```

预期：diff 仅包含本次规则补齐与占位实现，没有顺手改出无关噪音。

- [ ] **Step 5: 提交**

```bash
git add .gitignore sql/2026-03-16-bank-tagging.sql ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolver.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java
git commit -m "补齐银行流水模型占位规则"
```
