junboV2/CLAUDE.md

290 lines
9.0 KiB
Markdown
Raw Permalink 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.

# 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<XxxBo> 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