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:
zhuyongxin
2026-06-23 14:44:43 +08:00
parent 48132d297d
commit 8bd758dbaf
6 changed files with 783 additions and 2 deletions
@@ -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 必须完成,否则技术债累积