junboV2/CLAUDE.md

9.0 KiB
Raw Permalink Blame History

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 (组织架构是基础领域) 禁止:平级业务领域之间直接依赖(如 attendancescrum

// ✅ 正确示例
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

常见操作指南

编译和测试

# 编译(使用系统 JAVA_HOME
./gradlew compileJava

# 运行测试
./gradlew test

# 构建
./gradlew build

添加新实体

  1. 在对应领域的 entity/ 创建 JPA 实体
  2. repository/ 创建 Repository 接口
  3. 如需导入功能,在 importer/ 创建 ImportService
  4. 更新 JunboApplication.java@EnableJpaRepositories(如果是新领域)

跨领域引用

// ✅ 正确:依赖 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 中

创建数据导入服务

@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
  • RepositoryXxxRepository(如 EmployeeRepository
  • ServiceXxxService(如 KpaService
  • ImporterXxxImportService(如 SignRecordImportService

Spring Data JPA Repository 扫描

JunboApplication.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.propertiesapplication.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 旧代码

参考资料


文档版本: 1.0 最后更新: 2026-02-06 维护者: User & Claude