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%)
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
# 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 必须完成,否则技术债累积
|
||||
Reference in New Issue
Block a user