diff --git a/docs/CI集成说明.md b/docs/CI集成说明.md
index d8f7d24..efdee17 100644
--- a/docs/CI集成说明.md
+++ b/docs/CI集成说明.md
@@ -15,9 +15,9 @@ Gitea Actions 触发
↓
java -jar 执行(对比 HEAD~1 与 HEAD)
↓
-有 P0/P1 变更 → 企微通知
+有结构变更 → 企微通知(按 Key 骨架;删除橙/新增绿)
↓
-mode=block 且含 P0/P1/P2 任一变更 → exit 1(流水线失败)
+mode=block 且含任意结构变更 → exit 1(流水线失败)
```
---
@@ -29,7 +29,6 @@ mode=block 且含 P0/P1/P2 任一变更 → exit 1(流水线失败)
| Gitea Runner | 标签 `jdk11`,已安装 Java 11 |
| Nexus 私库 | 可访问 `http://192.168.3.25:18081/nexus/repository/maven-releases` |
| 工具 JAR | `com.codechecker:cache-schema-checker:1.0.0` 已发布 |
-| 仓库 Secret | `WECOM_ROBOT_WEBHOOK` 已配置 |
---
@@ -140,7 +139,6 @@ jobs:
| `code-check` (CodeChecker) | 通用变更检测 | **同模式**,可并列执行 |
| `cache-schema-check` | 缓存结构检测 | 新增 |
-建议:三个 job 独立并行,各自 exit code 独立。
---
@@ -169,7 +167,7 @@ com/codechecker/cache-schema-checker/1.0.0/
| 退出码 | 含义 | 流水线表现 |
|--------|------|------------|
| 0 | 通过(含 notify 模式下的告警) | 绿色 |
-| 1 | 阻断(block 模式 + P0/P1/P2 任一变更) | 红色 |
+| 1 | 阻断(block 模式) | 红色 |
| 2 | 执行错误(配置缺失、jar 异常等) | 红色 |
---
@@ -182,8 +180,8 @@ com/codechecker/cache-schema-checker/1.0.0/
| 下载 jar 失败 | Nexus 地址/版本错误 | 检查 env 变量 |
| 未收到企微 | Secret 未配 / notify.enabled=false | 检查配置 |
| 大量误报 | 锁/计数器未过滤 | 补充 ignore.key_patterns |
-| 漏报 | 写入模式未覆盖 | 启用 W04/W05 或补充 manual_mappings |
-| 类型展开不完整 | 类型在依赖 jar 中 | 补充 manual_mappings.value_type |
+| 漏报 | 写入模式未覆盖 / 模块过滤过窄 | 确认 W01~W05 已启用;检查 `include_modules` |
+| 类型展开不完整 | 类型在依赖 jar 中 | 补充 `manual_mappings.value_type` |
---
@@ -201,4 +199,4 @@ java -jar /path/to/cache-schema-checker-1.0.0.jar \
--modify-time "$(git log -1 --format=%cd --date=format:'%Y-%m-%d %H:%M:%S')"
```
-可加 `--dry-run`(Phase 2 实现)仅输出报告不发企微。
+可加 `--dry-run` 仅输出报告不发企微。
diff --git a/docs/实施方案.md b/docs/实施方案.md
index 99da02f..5217051 100644
--- a/docs/实施方案.md
+++ b/docs/实施方案.md
@@ -1,9 +1,10 @@
# 缓存序列化结构变更检测 — 实施方案
-> 版本:v0.1
-> 日期:2026-07-13
+> 版本:v0.2
+> 日期:2026-07-14
> 技术栈:Java 11 + Maven + JavaParser
-> 目标仓库:`redisCheck`(工具) / `jnpf-java-cloud`(被检测业务仓库)
+> 目标仓库:`redisCheck`(工具) / `jnpf-java-cloud`(被检测业务仓库)
+> 当前阶段:**Phase 1 + Phase 2 已完成**,Phase 3 待做
---
@@ -56,7 +57,7 @@
4. 通过企微机器人发送通知
5. 通过开关控制 **仅通知** 或 **阻断流水线**
-### 1.3 非目标(第一版不做)
+### 1.3 非目标
- 不连接真实 Redis 实例做运行时校验
- 不扫描 Maven 依赖 jar 中的类(仅分析业务仓库源码)
@@ -71,20 +72,20 @@
### 2.1 Redis 序列化方式
-| 类型 | 出现频率 | 第一版策略 |
-|------|----------|------------|
-| `JSON.toJSONString(obj)` / `JSONObject.toJSONString(obj)` | 高 | **重点支持** |
-| `JsonUtil.getObjectToString(obj)` | 高 | **重点支持**(按 Fastjson/Jackson 默认字段规则推断) |
-| `RedisTemplate.opsForValue().set(key, obj)` 直接写对象 | 中 | 第二阶段支持 |
-| `RedisTemplate.opsForHash().put(key, field, obj)` | 中 | 第二阶段支持 |
-| `StringRedisTemplate` 写 JSON 字符串 | 高 | **重点支持** |
+| 类型 | 出现频率 | 策略 |
+|------|----------|------|
+| `JSON.toJSONString(obj)` / `JSONObject.toJSONString(obj)` | 高 | **已支持**(W01/W02) |
+| `JsonUtil.getObjectToString(obj)` | 高 | **已支持**(W03) |
+| `RedisTemplate.opsForValue().set(key, obj)` 直接写对象 | 中 | **已支持**(W04) |
+| `RedisTemplate.opsForHash().put(key, field, obj)` | 中 | **已支持**(W05) |
+| `StringRedisTemplate` 写 JSON 字符串 | 高 | **已支持** |
| 锁 / 计数器 / token 简单值 | 高 | **默认忽略** |
### 2.2 Key 与实体映射
- 不存在统一的「Key → 类型」注册中心
- 存在大量 `static final String`、`String.format(...)`、`buildCacheKey(...)` 等模式
-- 第一版采用:**写入点静态推断 + 可选 YAML 人工补充映射**
+- 因此采用:**写入点静态推断 + 可选 YAML 人工补充映射**
### 2.3 多模块特征
@@ -98,10 +99,9 @@
### 3.1 交付形态
-沿用现有 `code-checker` 模式(见 `redisCheck/.gitea/demo.yaml`):
```text
-redisCheck 仓库
+schemaCheck 仓库
├── 开发 Java 分析工具
├── mvn package 打 fat-jar
├── 发布到 Nexus:com.codechecker:cache-schema-checker:{version}
@@ -144,7 +144,7 @@ flowchart TB
2. **Diff 驱动**:只分析本次 push 变更涉及的文件及其关联类型
3. **本仓限定**:类型解析仅在业务仓库 `src/main/java` 范围内
4. **可配置**:忽略规则、严重级别、通知开关、阻断开关均可 YAML 配置
-5. **可演进**:第一版聚焦 JSON 字符串写入,后续扩展 Template 直写对象
+5. **可演进**:已覆盖 JSON 字符串写入与 Template 直写 / Hash;后续可扩展读路径反向确认、报告落盘等
---
@@ -170,7 +170,7 @@ flowchart TB
## 5. 工程结构(redisCheck 仓库)
```text
-redisCheck/
+schemaCheck/
├── pom.xml # 单模块工程(无父子结构)
├── docs/
│ ├── 实施方案.md
@@ -180,19 +180,19 @@ redisCheck/
│ ├── main/
│ │ ├── resources/
│ │ │ └── default-config.yaml # 内置默认配置(随 jar 发布)
-│ │ └── java/com/codechecker/redis/
+│ │ └── java/com/codechecker/cache/
│ │ ├── cli/ # 命令行入口
│ │ ├── config/ # 配置模型
│ │ ├── git/ # Git 操作
│ │ ├── analyze/ # 编排与工作树扫描
-│ │ ├── detector/ # Redis 写入点检测
-│ │ ├── schema/ # Schema 提取
+│ │ ├── detector/ # Redis 写入点检测(W01~W05)
+│ │ ├── schema/ # Schema 提取与注解
│ │ ├── diff/ # 结构对比
│ │ ├── key/ # Key 推断
-│ │ ├── report/ # 报告
+│ │ ├── report/ # 报告 / 企微 Markdown
│ │ └── notify/ # 企微通知
│ └── test/
-│ ├── resources/fixtures/tenant/
+│ ├── resources/fixtures/{tenant,lock,template}/
│ └── java/...
├── .gitea/
│ ├── workflows/cache-schema-check.yaml
@@ -205,7 +205,7 @@ redisCheck/
```xml
com.codechecker
cache-schema-checker
-1.0.0-SNAPSHOT
+1.0.0
```
打包为 **shaded/fat jar**,主类:`com.codechecker.cache.cli.CacheSchemaCheckerMain`
@@ -273,20 +273,20 @@ git diff --name-only {old-sha} {new-sha} -- '*.java'
在 **变更文件** 中扫描以下 AST 模式:
-| 模式 ID | 匹配表达式 | 提取信息 |
-|---------|------------|----------|
-| W01 | `redisUtil.insert(key, JSON.toJSONString(expr), ttl)` | key 表达式、value 表达式 |
-| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(expr), ...)` | 同上 |
-| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(expr), ...)` | 同上 |
-| W04 | `redisTemplate.opsForValue().set(key, expr, ...)` 且 expr 非字面量 | 第二阶段 |
-| W05 | `redisTemplate.opsForHash().put(key, field, expr)` | 第二阶段 |
-| W06 | `JSON.parseObject(cacheValue, Xxx.class)` | 辅助反向确认读取类型 |
+| 模式 ID | 匹配表达式 | 提取信息 | 状态 |
+|---------|------------|----------|------|
+| W01 | `redisUtil.insert(key, JSON.toJSONString(expr), ttl)` | key 表达式、value 表达式 | ✅ |
+| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(expr), ...)` | 同上 | ✅ |
+| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(expr), ...)` | 同上 | ✅ |
+| W04 | `redisTemplate.opsForValue().set(key, expr, ...)` 且 expr 非字面量 | 直写对象类型 | ✅ Phase 2 |
+| W05 | `redisTemplate.opsForHash().put(key, field, expr)` | Hash 写出 value 类型 | ✅ Phase 2 |
+| W06 | `JSON.parseObject(cacheValue, Xxx.class)` | 辅助反向确认读取类型 | 未做 |
**忽略规则**(自动):
-- value 为字符串字面量、数字、`UUID`、`"1"` 等
-- 方法名含 `setIfAbsent`、`increment`、`delete`、`remove`、`expire`
-- key 匹配 `ignore_key_patterns` 配置
+- value 为字符串字面量、数字、`UUID`、`"1"` 等琐碎值
+- 方法名含 `setIfAbsent`、`increment`、`delete`、`remove`、`expire` 等
+- key 匹配 `ignore.key_patterns` 配置(锁 / token / 登录计数等)
#### Step 5:类型推断
@@ -308,15 +308,16 @@ redisUtil.insert(buildCacheKey(encode), JSON.toJSONString(envelope), ttl);
4. 递归展开 `TenantVO` → `dbName: String`、`linkList: List`
5. 继续展开 `TenantLinkModel` 全部字段
-**注解处理**(第一版):
+**注解处理**:
-| 注解 | 行为 |
-|------|------|
-| `@JSONField(serialize = false)` | 排除字段 |
-| `@JSONField(name = "xxx")` | 字段名映射 |
-| `@JsonIgnore` | 排除字段 |
-| `@JsonProperty("xxx")` | 字段名映射 |
-| `@Schema` | 忽略(不影响序列化) |
+| 注解 | 行为 | 状态 |
+|------|------|------|
+| `@JSONField(serialize = false)` | 排除字段 | ✅ |
+| `@JSONField(name = "xxx")` | 字段名映射 | ✅ |
+| `@JsonIgnore` | 排除字段 | ✅ |
+| `@JsonProperty("xxx")` | 字段名映射 | ✅ |
+| `@JsonIgnoreProperties({...})` | 类级忽略字段 | ✅ Phase 2 |
+| `@Schema` | 忽略(不影响序列化) | ✅ |
#### Step 6:生成 JSON Schema
@@ -367,18 +368,28 @@ redisUtil.insert(buildCacheKey(encode), JSON.toJSONString(envelope), ttl);
生成 `CheckReport`,包含:
- 仓库名、分支、old/new sha、提交人、时间
-- 变更列表(按严重级别排序)
-- 每项:Key 模式、写入位置(类#方法:行号)、旧结构、新结构、变更摘要
+- 按 Key 聚合的结构变更(骨架 before/after)+ 字段级明细
+- 每项通用展示:**Key**、**位置**(`Class#method:line`)、**类型**、旧/新序列化骨架
-调用企微 Webhook 发送 Markdown 消息。
+企微 Markdown 规则:
+
+- 抬头不含 mode / P0~P2 汇总;正文按 Key 展示骨架
+- **删除字段**:旧骨架中橙色 ``
+- **新增字段**:新骨架中绿色 ``
+- key 未解析时展示源码表达式 + 灰色「(key 未解析)」
+- 单条超 4096 UTF-8 字节时按 Key 拆成多条依次发送
+
+CI 控制台额外输出字段明细(含严重级别),再打印与企微一致的 Markdown。
+
+调用企微 Webhook 发送 Markdown(支持 `--dry-run` 仅本地输出)。
#### Step 9:退出码
| 条件 | 退出码 |
|------|--------|
-| 无变更 / 仅 P2 | 0 |
-| `mode=notify` 且存在 P0/P1 | 0(仍通知) |
-| `mode=block` 且存在 P0/P1/P2 | 1 |
+| `enabled=false` / 无变更 | 0 |
+| `mode=notify` 且存在变更 | 0(仍通知) |
+| `mode=block` 且存在任意结构变更 | 1 |
| 配置错误 / 执行异常 | 2 |
---
@@ -442,9 +453,11 @@ mode: notify
# 是否发送企微通知
notify:
enabled: true
- webhook_env: WECOM_ROBOT_WEBHOOK
+ webhook_url: "" # 企微 Webhook 完整 URL;兼容旧字段 webhook_env
```
+企微消息约定见 `docs/配置说明.md` §5:**位置/类型**为每个 Key 的通用项;删除字段橙色、新增字段绿色。
+
---
## 9. CI 集成方案
@@ -492,43 +505,44 @@ jobs:
## 10. 分阶段交付计划
-### Phase 1 — MVP(约 1.5 周)
+### Phase 1 — MVP(约 1.5 周)✅
**目标**:跑通端到端链路,覆盖租户缓存典型场景。
-| 任务 | 产出 |
-|------|------|
-| Maven 工程骨架 + CLI | 可执行 fat-jar |
-| Git diff 扫描 | 变更文件列表 |
-| W01~W03 写入点检测 | 覆盖 JSON 字符串写入 |
-| 基础 Schema 提取 | 支持普通类、内部类、List、嵌套 |
-| Schema Diff P0/P1 | 字段增删、包装、路径迁移 |
-| 企微通知 | Markdown 消息 |
-| notify/block 开关 | 配置驱动 |
-| 夹具测试 | TenantVO/CacheEnvelope 样本 |
+| 任务 | 产出 | 状态 |
+|------|------|------|
+| Maven 工程骨架 + CLI | 可执行 fat-jar | ✅ |
+| Git diff 扫描 | 变更文件列表 | ✅ |
+| W01~W03 写入点检测 | 覆盖 JSON 字符串写入 | ✅ |
+| 基础 Schema 提取 | 支持普通类、内部类、List、嵌套 | ✅ |
+| Schema Diff P0/P1 | 字段增删、包装、路径迁移 | ✅ |
+| 企微通知 | 按 Key 骨架 Markdown | ✅ |
+| notify/block / enabled | 配置驱动 | ✅ |
+| 夹具测试 | TenantVO/CacheEnvelope 样本 | ✅ |
**验收标准**:
-- 对 `TenantDbContentCacheHelper` 的结构变更能输出 P0 报告
+- 对 `TenantDbContentCacheHelper` 的结构变更能输出报告并通知
- 流水线 push 后能收到企微通知
-- `mode=block` 时任意 P0/P1/P2 变更导致 exit 1
+- `mode=block` 时任意结构变更导致 exit 1
### Phase 2 — 增强(约 1 周)✅
| 任务 | 说明 | 状态 |
|------|------|------|
-| W04/W05 模式 | RedisTemplate 直写对象、Hash 写入 | 已完成 |
-| 注解完整支持 | Fastjson/Jackson 注解(含 `@JsonIgnoreProperties`) | 已完成 |
-| Key 推断增强 | `String.format`、常量拼接追溯、`buildXxxKey` | 已完成 |
-| 忽略规则完善 | 锁/计数器/token/字面量/setIfAbsent 自动过滤 | 已完成 |
-| 多模块性能优化 | 并行读文件、索引批量装载、manual_mappings 覆盖 | 已完成 |
+| W04/W05 模式 | RedisTemplate 直写对象、Hash 写入 | ✅ |
+| 注解完整支持 | Fastjson/Jackson(含 `@JsonIgnoreProperties`) | ✅ |
+| Key 推断增强 | `String.format`、常量拼接、`buildXxxKey` | ✅ |
+| 忽略规则完善 | 锁/计数器/token/字面量/setIfAbsent | ✅ |
+| 多模块性能 | 并行读文件、索引批量装载、`manual_mappings` | ✅ |
+| 企微高亮 | 删除橙 `warning` / 新增绿 `info`;位置+类型通用项 | ✅ |
### Phase 3 — 运营(约 0.5 周)
| 任务 | 说明 |
|------|------|
| 报告落盘 | 可选输出 JSON 报告文件 |
-| 误报反馈 | `suppressions` 配置支持按写入点忽略 |
+| 误报反馈 | `suppressions` 按写入点 / change_types 精细忽略 |
| 更多业务场景覆盖 | 考勤、文件下载进度等 |
---
@@ -548,10 +562,9 @@ jobs:
| 夹具 | 验证点 |
|------|--------|
-| `tenant-cache/` | 包装结构变更 P0 |
-| `attendance-base-setting/` | Map 结构缓存 |
-| `evaluate-config/` | VO 字段新增 P1 |
-| `lock-only/` | 应被忽略 |
+| `fixtures/tenant/` | 包装结构变更(TenantVO → CacheEnvelope) |
+| `fixtures/lock/` | 锁/计数器/token 应被忽略 |
+| `fixtures/template/` | W04 Template 直写 |
### 11.3 端到端测试
@@ -577,13 +590,13 @@ jobs:
| # | 决策项 | 结论 |
|---|--------|------|
-| 1 | 阻断范围 | `block` 模式下 **P0/P1/P2 全部阻断**(exit 1) |
+| 1 | 阻断范围 | `block` 模式下 **任意结构变更均阻断**(exit 1) |
| 2 | 发布坐标 | 独立产物 `com.codechecker:cache-schema-checker:1.0.0` |
| 3 | 配置归属 | **双层配置**:jar 内 `default-config.yaml` + 业务仓覆盖合并 |
| 4 | 上线策略 | 先 `notify` 观察 **1 周**,稳定后手动切 `block` |
| 5 | 检测范围 | **仅 `src/main/java`**,不扫描测试代码 |
-以上决策已纳入实施方案,可进入开发阶段。
+以上决策已纳入实施方案;**Phase 1 / Phase 2 已交付**,可进入 Phase 3 或业务仓全量观察。
---
diff --git a/docs/配置说明.md b/docs/配置说明.md
index b16225e..33750ad 100644
--- a/docs/配置说明.md
+++ b/docs/配置说明.md
@@ -1,6 +1,8 @@
# 缓存序列化结构检测 — 配置说明
-> **双层配置**:工具 jar 内置 `default-config.yaml`(默认) + 业务仓库 `.gitea/config/cache-schema-check-config.yaml`(覆盖)
+> **双层配置**:工具 jar 内置 `default-config.yaml`(默认) + 业务仓库 `.gitea/config/cache-schema-check-config.yaml`(覆盖)
+> 工具坐标:`com.codechecker:cache-schema-checker:1.0.0`
+> 主类:`com.codechecker.cache.cli.CacheSchemaCheckerMain`
---
@@ -22,23 +24,28 @@ jar 内 default-config.yaml(工具仓维护)
```yaml
# jnpf-java-cloud/.gitea/config/cache-schema-check-config.yaml
+enabled: true
mode: notify
notify:
enabled: true
- webhook_env: WECOM_ROBOT_WEBHOOK
+ # 推荐直接写完整 Webhook;也可用环境变量在流水线注入
+ webhook_url: ""
include_modules:
- jnpf-tenant
```
+流水线通常把 Secret 注入环境或配置文件中的 `webhook_url`。兼容旧字段:`webhook_env`(值为 `http` 开头时当作 URL 使用)。
+
### 1.2 工具内置默认配置(jar 内 default-config.yaml)
-由 `redisCheck` 仓库维护,随 jar 发布,包含:
+由 `redisCheck` 仓库维护,随 jar 发布,默认包含:
-- `detection.patterns`(W01~W03)
-- `ignore.key_patterns`(锁/计数器/token)
-- `detection.min_confidence`、`max_field_depth` 等
+- `detection.patterns`:**W01~W05**(JSON 字符串写入 + Template 直写 + Hash)
+- `ignore.key_patterns`(锁 / 计数器 / token)
+- `detection.min_confidence`、`max_field_depth`
+- `mode: notify`、`enabled: true`
---
@@ -63,8 +70,10 @@ source_roots:
# 通知配置
notify:
enabled: true
- # 从环境变量读取 Webhook URL
- webhook_env: WECOM_ROBOT_WEBHOOK
+ # Webhook 完整 URL(优先)
+ webhook_url: ""
+ # 兼容旧字段:值为 http 开头时视为 URL
+ # webhook_env: WECOM_ROBOT_WEBHOOK
# 无变更时是否也发通知(一般 false)
notify_on_clean: false
# 消息标题前缀
@@ -76,9 +85,9 @@ ignore:
key_patterns:
- "*:lock"
- "*:lock:*"
+ - "*lock*"
- "loginCount:*"
- "Authorization:*"
- - "Authorization:login:session:*"
# 忽略的文件路径模式
file_patterns:
@@ -89,7 +98,7 @@ ignore:
# 检测规则
detection:
- # 启用的写入模式
+ # 启用的写入模式(默认已全部开启)
patterns:
- W01 # redisUtil.insert + JSON.toJSONString
- W02 # redisTemplate.opsForValue().set + JSON.toJSONString
@@ -171,7 +180,8 @@ mode: block
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `enabled` | boolean | true | 是否发企微 |
-| `webhook_env` | string | WECOM_ROBOT_WEBHOOK | 环境变量名 |
+| `webhook_url` | string | `""` | 企微机器人 Webhook 完整 URL(优先) |
+| `webhook_env` | string | — | 兼容旧字段;值为 `http` 开头时当作 URL |
| `notify_on_clean` | boolean | false | 无变更时是否通知 |
| `title_prefix` | string | [缓存结构变更] | 消息标题前缀 |
@@ -182,25 +192,33 @@ mode: block
- `*` 匹配单层
- `**` 匹配多层
-常见内置忽略(代码层也有硬编码兜底):
+内置/代码层常见过滤:
-- 分布式锁 key
-- 登录计数
-- session/token
+- 分布式锁 key(配置 glob + 方法名忽略)
+- 登录计数、session/token
+- 琐碎 value:字面量、`"1"`、`UUID.randomUUID()` 等
+- 方法:`setIfAbsent` / `increment` / `delete` / `expire` 等
### 3.5 detection.patterns
-| 模式 | 说明 | 阶段 |
+| 模式 | 说明 | 状态 |
|------|------|------|
-| W01 | `redisUtil.insert(key, JSON.toJSONString(x), ttl)` | Phase 1 |
-| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(x), ...)` | Phase 1 |
-| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(x), ...)` | Phase 1 |
-| W04 | `redisTemplate.opsForValue().set(key, obj, ...)` | Phase 2(已启用) |
-| W05 | `redisTemplate.opsForHash().put(key, field, obj)` | Phase 2(已启用) |
+| W01 | `redisUtil.insert(key, JSON.toJSONString(x), ttl)` | 已启用 |
+| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(x), ...)` | 已启用 |
+| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(x), ...)` | 已启用 |
+| W04 | `redisTemplate.opsForValue().set(key, obj, ...)` 直写对象 | 已启用(Phase 2) |
+| W05 | `redisTemplate.opsForHash().put(key, field, obj)` | 已启用(Phase 2) |
+
+业务仓可通过只声明子集暂时关闭某些模式,例如仅保留 JSON 写入:
+
+```yaml
+detection:
+ patterns: [W01, W02, W03]
+```
### 3.6 manual_mappings
-当自动推断不准确时使用。匹配优先级 **高于** 自动推断。
+当自动推断不准确时使用。匹配优先级 **高于** 自动推断(按 `类全名#方法名` 覆盖 key 模式与 value 类型)。
| 字段 | 必填 | 说明 |
|------|------|------|
@@ -217,59 +235,97 @@ mode: block
```yaml
suppressions:
- id: my-suppression
- writer_method: "com.example.FooService#cacheBar"
+ key_pattern: "file:download:user:progress:*"
change_types:
- FIELD_ADDED
reason: "新增字段向后兼容"
```
+### 3.8 include_modules / exclude_modules
+
+| 字段 | 说明 |
+|------|------|
+| `include_modules` | 非空时仅扫描列出的顶层模块;空表示全仓 |
+| `exclude_modules` | 始终排除的顶层模块 |
+
+顶层模块取路径第一段,例如 `jnpf-tenant/jnpf-tenant-biz/src/main/java/...` → `jnpf-tenant`。
+
---
-## 4. 环境变量
+## 4. 环境变量 / Secret
| 变量 | 必填 | 说明 |
|------|------|------|
-| `WECOM_ROBOT_WEBHOOK` | notify.enabled=true 时必填 | 企微机器人 Webhook 完整 URL |
+| `WECOM_ROBOT_WEBHOOK` | 视流水线写法 | 可将 Secret 写入配置中的 `webhook_url`,或在启动前注入 |
在 Gitea 仓库 Settings → Secrets 中配置。
---
-## 5. 企微消息格式示例
+## 5. 企微消息格式
+
+### 5.1 结构说明
+
+- 抬头:仓库、分支、提交、提交人、时间(**不再**展示 mode / P0P1P2 汇总)
+- 正文:按 **一个 Redis Key 一块**,展示位置、类型与前后序列化骨架
+- 超长(UTF-8 > 4096 字节)时按 key **拆成多条**消息依次发送
+- CI 控制台另打「字段明细」(含 P0/P1/P2),企微侧不分级别
+
+### 5.2 字段高亮颜色
+
+| 变更 | 企微颜色 | Markdown |
+|------|----------|----------|
+| 字段删除(标在旧骨架) | 橙色 | `…` |
+| 字段新增 / 包装层(标在新骨架) | 绿色 | `…` |
+| 路径迁移 | 旧橙 / 新绿 | 同上 |
+| key 未解析提示 | 灰色 | `(key 未解析)` |
+
+### 5.3 示例(已解析 key)
```markdown
## [缓存结构变更] jnpf-java-cloud
-> 分支: feature/tenant-cache
-> 提交: a1b2c3d → e4f5g6h
-> 提交人: zhangsan
-> 时间: 2026-07-13 14:00:00
-> 模式: notify
+> **分支**: code/redis_change_detection_v1.0
+> **提交**: cedd161c → 67c8a6eb
+> **提交人**: dongzi
+> **时间**: 2026-07-13 16:54:17
-### P0 - 顶层结构包装变更
-- **Key**: `tenant:db:content:*`
-- **位置**: `TenantDbContentCacheHelper#cacheSuccess:92`
-- **变更**:
- - `dbName` → `vo.dbName`(字段路径迁移)
- - `linkList` → `vo.linkList`(字段路径迁移)
- - 新增顶层字段 `expiresAtMs`
-- **影响**: 旧缓存反序列化可能失败,需评估缓存刷新策略
+- Key --> `tenant:db:content:*`
+ > **位置**: `TenantDbContentCacheHelper#cacheSuccess:92`
+ > **类型**: `CacheEnvelope`
+ > **value值由:** “{"dbName":"","linkList":[{"id":""}]}”
+ > **变更为:** “…(仅新增/迁移字段片段带 绿色)…”
```
+实际发送时仅对改动属性片段染色:新增 → `info`(绿),删除 → `warning`(橙)。
+
+### 5.4 示例(key 未解析)
+
+```markdown
+- Key --> `req.getKey()` (key 未解析)
+ > **位置**: `ClockInXxxService#export:128`
+ > **类型**: `List`
+ > **value值由:** “{"a":""}”
+ > **变更为:** “…新增字段带绿色高亮…”
+```
+
+未解析时按「写入位置 + key 表达式」拆分聚合,避免多个未知 key 串在一起。
+
---
## 6. 推荐上线配置
-### 6.1 观察期(第 1 周,已确认策略)
+### 6.1 观察期(第 1 周)
业务仓默认配置:
```yaml
+enabled: true
mode: notify
notify:
enabled: true
- webhook_env: WECOM_ROBOT_WEBHOOK
+ webhook_url: "" # 由流水线写入真实 Webhook
include_modules:
- jnpf-tenant
@@ -285,6 +341,7 @@ include_modules: [] # 扩至全仓
### 6.2 全量启用(观察期结束后)
```yaml
+enabled: true
mode: block
include_modules: [] # 空表示全部模块
detection: