# 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、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 findByDiagnosisId(String diagnosisId); List findByFaultCategoryAndErrorCode(FaultCategory category, String errorCode); Page 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 必须完成,否则技术债累积