Files
SuperBizAgent-java/devflow/projects/2026-06-23-phase1-infrastructure/decisions.md
T
zhuyongxin 8bd758dbaf docs(devflow): 补充 Phase 1 项目记忆文档
创建 Phase 1 基础设施搭建的完整 devflow 文档:

- brief.md: 项目背景、目标、范围、技术选型、关键决策
- decisions.md: 6 个架构决策记录 (ADR)
  - ADR-001: Flyway 数据库版本管理
  - ADR-002: 枚举类型存储为 VARCHAR
  - ADR-003: Redis JSON 序列化
  - ADR-004: Spring Data JPA 命名约定
  - ADR-005: 会话 TTL 可配置
  - ADR-006: 包名暂时混用
- evidence.md: 测试证据、性能指标、编译验证、数据库结构
  - 27 个测试全部通过
  - 性能指标达标
  - 提交记录追踪
- acceptance.md: 验收标准、测试结果、遗留问题
  - 20/33 任务完成
  - 部分验收通过

更新全局文档:
- devflow/index.md: 新增 phase1-infrastructure 项目索引
- devflow/glossary/CONTEXT.md: 新增 8 个术语和 4 条业务规则

Progress: 20/33 tasks completed (61%)
2026-06-23 14:44:43 +08:00

197 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1 基础设施搭建 — Decisions
## ADR-001: 采用 Flyway 管理数据库版本
**状态**: 已接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
项目需要版本化管理数据库表结构,支持多环境部署和团队协作。
### 决策
采用 Flyway 作为数据库迁移工具,JPA `ddl-auto` 设置为 `validate`。
### 理由
- Flyway 提供版本化 SQL 脚本管理
- `validate` 模式确保代码与数据库结构一致,防止意外修改
- 迁移脚本可版本控制,支持回滚和审计
- 与 Spring Boot 深度集成,配置简单
### 后果
- 表结构修改必须通过 SQL 迁移脚本
- 开发环境首次启动需要执行 Flyway 迁移
- 生产环境部署自动执行未执行的迁移脚本
---
## ADR-002: 枚举类型存储为 VARCHAR
**状态**: 已接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
JPA 实体类使用 Java 枚举(FaultCategory、DiagnosisStatus、SourceType),数据库列类型为 VARCHAR,Hibernate 校验报错类型不匹配。
### 决策
在 JPA 实体中明确指定 `columnDefinition = "VARCHAR"`:
```java
@Enumerated(EnumType.STRING)
@Column(name = "fault_category", length = 32, columnDefinition = "VARCHAR(32)")
private FaultCategory faultCategory;
```
### 理由
- MySQL 的 ENUM 类型限制灵活性(新增枚举值需要 ALTER TABLE)
- VARCHAR 支持动态扩展枚举值
- `@Enumerated(EnumType.STRING)` 存储枚举名称,可读性好
- `columnDefinition` 明确告知 Hibernate 期望的数据库类型
### 后果
- 数据库列存储字符串值(如 `"EXTERNAL_API"`)
- 枚举值修改不影响数据库结构
- 需要在应用层校验枚举值合法性
---
## ADR-003: Redis 会话管理采用 JSON 序列化
**状态**: 已接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
SessionContext 包含复杂对象(List<ToolCall>、LocalDateTime),需要选择合适的序列化方案存储到 Redis。
### 决策
使用 `GenericJackson2JsonRedisSerializer` + `JavaTimeModule`:
```java
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY
);
```
### 理由
- JSON 格式可读性强,便于调试
- 支持 Java 8 时间类型(LocalDateTime)
- 支持多态反序列化(通过 `@class` 类型信息)
- 跨语言友好(如需要其他服务读取 Redis 数据)
### 后果
- Redis 中存储的是 JSON 字符串
- 增加了 `@class` 元数据字段
- 序列化性能略低于二进制方案(Kryo、Protobuf)
- 对象结构变更需要考虑兼容性
---
## ADR-004: Repository 方法遵循 Spring Data JPA 命名约定
**状态**: 已接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
Repository 需要提供多种查询方法(按 ID、按业务字段、按时间范围等),需要选择查询定义方式。
### 决策
使用 Spring Data JPA 方法命名约定,不手写 `@Query`:
```java
Optional<DiagnosisRecord> findByDiagnosisId(String diagnosisId);
List<DiagnosisRecord> findByFaultCategoryAndErrorCode(FaultCategory category, String errorCode);
Page<DiagnosisRecord> findByCreatedAtBetween(LocalDateTime start, LocalDateTime end, Pageable pageable);
```
### 理由
- 方法名即查询语义,自解释
- 无需手写 SQL/JPQL,减少语法错误
- Spring Data JPA 自动生成查询实现
- 支持分页、排序等高级特性
### 后果
- 复杂查询(多表连接、子查询)需要手写 `@Query`
- 方法名可能很长(多条件组合查询)
- 依赖 Spring Data JPA 的命名解析规则
---
## ADR-005: 会话 TTL 可配置,默认由调用方指定
**状态**: 已接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
不同场景的会话过期时间需求不同(短诊断 5 分钟,长会话 1 小时)。
### 决策
`createSession` 方法接受 `ttlSeconds` 参数,由调用方指定过期时间:
```java
String createSession(SessionContext context, long ttlSeconds);
```
### 理由
- 灵活控制不同场景的会话时长
- 避免硬编码过期时间
- 支持动态刷新(`refreshSession` 方法)
### 后果
- 调用方需要明确指定 TTL
- 需要在业务层统一管理 TTL 策略
- Redis 自动清理过期会话,无需手动删除
---
## ADR-006: 包名暂时混用,Task 4 统一重构
**状态**: 临时接受
**日期**: 2026-06-23
**决策者**: zhuyongxin
### 背景
- 枚举类在 `com.superbiz.agent.domain.enums`
- 新建实体类在 `org.example.domain.entity`
- 新建 Repository 在 `org.example.repository`
### 决策
暂时通过跨包 import 解决编译问题,Task 4 统一重构为 `com.superbiz.agent.*`。
### 理由
- Phase 1 重点是功能实现和测试验证
- 包名重构涉及全局修改,风险较高
- Task 4 专门负责代码结构重构,一次性解决
### 后果
- 当前包名混乱,影响可维护性
- IDE 导航和代码搜索不友好
- Task 4 必须完成,否则技术债累积