# junboV2 项目上下文(Claude 参考文档) > 本文档用于为 Claude AI 助手提供项目背景和关键决策上下文 ## 项目概况 **项目名称**: junboV2 **类型**: 企业管理系统 **技术栈**: Spring Boot 2.7.18 + Spring Data JPA + SQLite + Lombok **构建工具**: Gradle 7.6.3 **Java 版本**: Java 8 (1.8) **JDK**: 使用系统 JAVA_HOME 环境变量指定的 JDK ### 业务领域 - **organization** - 组织架构(员工、部门、部门关系) - **attendance** - 考勤管理(签到、请假、工作日历) - **scrum** - Scrum 迭代(Sprint、Story、Story Member) - **kpa** - KPA 绩效(KPA 记录、员工得分) - **incentive** - 激励管理(激励记录) ## 包结构(Package by Feature) ``` info.panli.junbo/ ├── JunboApplication.java # Spring Boot 入口 ├── api/ # REST Controllers(横切层) ├── infrastructure/ # 基础设施(横切层) │ ├── config/ # 配置类 │ └── importer/ # 数据导入接口 ├── organization/ # 【核心领域】组织架构 │ ├── entity/ # JPA 实体 │ ├── repository/ # Spring Data Repository │ └── importer/ # 数据导入服务 ├── attendance/ # 【业务领域】考勤 │ ├── entity/ │ ├── repository/ │ ├── importer/ │ ├── bo/, dao/, po/ # 旧代码(保留,标记 @Deprecated) │ └── service/ ├── scrum/ # 【业务领域】迭代 │ ├── entity/ │ ├── repository/ │ ├── service/ │ └── bo/, dao/, po/ # 旧代码(保留) ├── kpa/ # 【业务领域】KPA │ ├── entity/ │ ├── repository/ │ ├── service/ │ └── bo/, dao/, po/ # 旧代码(保留) └── incentive/ # 【业务领域】激励 ├── entity/ ├── repository/ ├── service/ └── bo/, dao/, po/ # 旧代码(保留) ``` ## 关键架构决策 ### 1. 跨领域依赖规则 ✅ **允许**:其他领域 → `organization` (组织架构是基础领域) ❌ **禁止**:平级业务领域之间直接依赖(如 `attendance` ↔ `scrum`) ```java // ✅ 正确示例 package info.panli.junbo.attendance.entity; import info.panli.junbo.organization.entity.EmployeeEntity; @Entity public class SignRecordEntity { @ManyToOne private EmployeeEntity employee; // 引用组织领域 } ``` ### 2. Importer 职责边界(重要) **原则**: Importer 只负责数据去重,不负责业务逻辑验证 | 职责类型 | 定义 | 示例 | 处理者 | |---------|------|------|--------| | **数据去重** | 完全相同的记录 | 同员工同日期同时间的签到 | ✅ Importer | | **业务冲突** | 逻辑上的矛盾 | 两次请假时间重叠 | ❌ Service 层 | **Importer 应该做的**: - 读取外部数据源(Excel/YAML) - 检查记录是否完全相同(主键/唯一索引) - 跳过重复记录,插入新记录 **Importer 不应该做的**: - 业务规则验证(时间合理性、余额检查) - 数据冲突检测(时间重叠、状态机校验) - 复杂计算和统计 ### 3. 数据访问层演进 | 层次 | 状态 | 使用范围 | |------|------|---------| | **Entity + Repository** | ✅ 当前主力 | 数据持久化、CRUD | | **bo/dao/po** | ⚠️ 遗留代码 | 旧功能、Excel 导入 | 新功能应使用 `Entity + Repository`,旧代码暂时保留标记 `@Deprecated`。 ## 常见操作指南 ### 编译和测试 ```bash # 编译(使用系统 JAVA_HOME) ./gradlew compileJava # 运行测试 ./gradlew test # 构建 ./gradlew build ``` ### 添加新实体 1. 在对应领域的 `entity/` 创建 JPA 实体 2. 在 `repository/` 创建 Repository 接口 3. 如需导入功能,在 `importer/` 创建 ImportService 4. 更新 `JunboApplication.java` 的 `@EnableJpaRepositories`(如果是新领域) ### 跨领域引用 ```java // ✅ 正确:依赖 organization import info.panli.junbo.organization.entity.EmployeeEntity; import info.panli.junbo.organization.repository.EmployeeRepository; // ❌ 错误:旧的 sqlite 包(已删除) import info.panli.junbo.sqlite.entity.EmployeeEntity; // ❌ 错误:平级领域互相依赖 import info.panli.junbo.scrum.entity.SprintEntity; // 在 attendance 中 ``` ### 创建数据导入服务 ```java @Service @RequiredArgsConstructor public class XxxImportService { private final XxxRepository repository; private final EmployeeRepository employeeRepository; @Transactional public ImportResult importFromExcel(String filePath) { // 1. 读取外部数据 List records = readExcel(filePath); int inserted = 0, skipped = 0; for (XxxBo bo : records) { // 2. 查找员工(如果需要) EmployeeEntity employee = employeeRepository .findByNameOrAlias(bo.getEmployeeName()) .orElse(null); if (employee == null) { continue; // 找不到员工,跳过 } // 3. 检查是否已存在(数据去重) boolean exists = repository.existsByEmployeeAndDate( employee, bo.getDate() ); if (exists) { skipped++; continue; } // 4. 保存新记录 XxxEntity entity = convert(bo, employee); repository.save(entity); inserted++; } return ImportResult.builder() .insertedCount(inserted) .skippedCount(skipped) .build(); } // ❌ 不要在这里做业务逻辑验证! } ``` ## 技术细节 ### JPA 实体命名规范 - 实体类:`XxxEntity`(如 `EmployeeEntity`) - Repository:`XxxRepository`(如 `EmployeeRepository`) - Service:`XxxService`(如 `KpaService`) - Importer:`XxxImportService`(如 `SignRecordImportService`) ### Spring Data JPA Repository 扫描 在 `JunboApplication.java` 中配置: ```java @EnableJpaRepositories(basePackages = { "info.panli.junbo.organization.repository", "info.panli.junbo.attendance.repository", "info.panli.junbo.scrum.repository", "info.panli.junbo.kpa.repository", "info.panli.junbo.incentive.repository" }) ``` ### 数据库 - **类型**: SQLite - **配置**: `application.properties` 或 `application.yml` - **初始化**: `DataInitializer.java`(自动从 YAML 导入初始数据) ## 项目历史变更 ### 2026-02-06: 包结构重构 **背景**: 原有代码按领域组织(bo/dao/po),新增 SQLite 代码按层组织(entity/repository/controller),架构不一致。 **方案**: 将所有 SQLite 相关代码迁移到领域包,采用 Package by Feature 架构。 **变更**: - ❌ 删除 `info.panli.junbo.sqlite.*` 包(47 个文件) - ✅ 创建 `organization/`, `attendance/`, `scrum/`, `kpa/`, `incentive/` 领域包 - ✅ 创建 `api/`, `infrastructure/` 横切包 - ✅ 更新所有 import 语句 **结果**: - ✅ 编译通过 - ✅ 96.4% 测试通过(534/554) - ✅ 无包引用错误 ## 常见问题 ### Q: 为什么 bo/dao/po 代码还在? A: 旧功能依赖这些代码,暂时保留标记 `@Deprecated`,后续逐步迁移。 ### Q: 添加新功能应该用哪一套? A: 使用 `Entity + Repository + Service`,不要再用 bo/dao/po。 ### Q: 如何处理跨领域的业务逻辑? A: 通过 Service 层协调,或使用 Spring 事件机制解耦。 ### Q: Importer 和 Service 的边界是什么? A: Importer 只做数据去重导入,Service 做业务逻辑验证和计算。 ### Q: 为什么项目使用 Java 8? A: 项目使用 Spring Boot 2.7.18,与 Java 8 兼容性最佳。确保系统 JAVA_HOME 指向 JDK 8。 ## 后续计划 1. ✅ 包结构重构(已完成) 2. ⏳ 完善 Service 层业务逻辑 3. ⏳ 补充单元测试和集成测试 4. ⏳ 引入 DTO 层(Controller ↔ Service) 5. ⏳ 添加领域事件机制 6. ⏳ 逐步移除 bo/dao/po 旧代码 ## 参考资料 - [包结构重构设计方案](docs/plans/2026-02-05-package-restructure-design.md) - [测试工具包使用指南](docs/testing-toolkit-guide.md) - [JUnit 5 迁移完成报告](docs/junit5-jacoco-completion-report.md) - [项目健康度报告](docs/health-report-2026-02-06.md) - [测试覆盖率报告](docs/test-coverage-report-2026-02-06.md) - [测试修复进度报告](docs/test-fixes-progress-2026-02-06.md) - [测试提升总结](docs/test-improvement-summary-2026-02-06.md) - [测试最终总结](docs/test-final-summary-2026-02-06.md) ⭐ 最新 - Spring Data JPA: https://spring.io/projects/spring-data-jpa - Package by Feature: https://phauer.com/2020/package-by-feature/ - JUnit 5: https://junit.org/junit5/docs/current/user-guide/ --- **文档版本**: 1.0 **最后更新**: 2026-02-06 **维护者**: User & Claude