Files
label_backend/docs/superpowers/plans/2026-04-14-label-backend-directory-flattening.md
2026-04-14 14:59:46 +08:00

25 KiB
Raw Blame History

label_backend 标准目录扁平化 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal:com.label.module.*com.label.common.aop/common.config 迁移到规范要求的扁平目录,保证行为不变。

Architecture: 先写迁移守卫测试,再按 基础设施 -> 数据层 -> 服务层 -> 控制层 -> 清理回归 的顺序做 git mv 和导包修正,每阶段都用最小测试集验证。

Tech Stack: Java 21、Spring Boot 3.1.5、MyBatis-Plus、Shiro、JUnit 5、AssertJ、Maven


目标目录

  • src/main/java/com/label/annotation
  • src/main/java/com/label/aspect
  • src/main/java/com/label/config
  • src/main/java/com/label/controller
  • src/main/java/com/label/dto
  • src/main/java/com/label/entity
  • src/main/java/com/label/event
  • src/main/java/com/label/listener
  • src/main/java/com/label/mapper
  • src/main/java/com/label/service
  • src/test/java/com/label/unit/PackageStructureMigrationTest.java

Task 1: 锁定基础设施迁移目标

Files:

  • Create: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Modify: src/main/java/com/label/common/aop/OperationLog.java

  • Modify: src/main/java/com/label/common/aop/AuditAspect.java

  • Modify: src/main/java/com/label/common/config/MybatisPlusConfig.java

  • Modify: src/main/java/com/label/common/config/OpenApiConfig.java

  • Modify: src/main/java/com/label/common/config/RedisConfig.java

  • Modify: src/main/java/com/label/module/annotation/event/ExtractionApprovedEvent.java

  • Modify: src/main/java/com/label/module/annotation/service/ExtractionApprovedEventListener.java

  • Modify: src/main/java/com/label/module/annotation/service/ExtractionService.java

  • Test: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Step 1: 写失败测试

package com.label.unit;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@DisplayName("标准目录扁平化迁移守卫测试")
class PackageStructureMigrationTest {

    @Test
    @DisplayName("基础设施类已迁移到目标目录")
    void infrastructureTypesMoved() {
        assertClassExists("com.label.annotation.OperationLog");
        assertClassExists("com.label.aspect.AuditAspect");
        assertClassExists("com.label.config.MybatisPlusConfig");
        assertClassExists("com.label.config.OpenApiConfig");
        assertClassExists("com.label.config.RedisConfig");
        assertClassExists("com.label.event.ExtractionApprovedEvent");
        assertClassExists("com.label.listener.ExtractionApprovedEventListener");

        assertClassMissing("com.label.common.aop.OperationLog");
        assertClassMissing("com.label.common.aop.AuditAspect");
        assertClassMissing("com.label.common.config.MybatisPlusConfig");
        assertClassMissing("com.label.common.config.OpenApiConfig");
        assertClassMissing("com.label.common.config.RedisConfig");
        assertClassMissing("com.label.module.annotation.event.ExtractionApprovedEvent");
        assertClassMissing("com.label.module.annotation.service.ExtractionApprovedEventListener");
    }

    private static void assertClassExists(String fqcn) {
        assertThatCode(() -> Class.forName(fqcn)).doesNotThrowAnyException();
    }

    private static void assertClassMissing(String fqcn) {
        assertThatThrownBy(() -> Class.forName(fqcn)).isInstanceOf(ClassNotFoundException.class);
    }
}
  • Step 2: 跑红

Run: mvn -q "-Dtest=PackageStructureMigrationTest#infrastructureTypesMoved" test

Expected: FAIL提示新包类不存在。

  • Step 3: 最小实现

先执行迁移:

git mv src/main/java/com/label/common/aop/OperationLog.java src/main/java/com/label/annotation/OperationLog.java
git mv src/main/java/com/label/common/aop/AuditAspect.java src/main/java/com/label/aspect/AuditAspect.java
git mv src/main/java/com/label/common/config/MybatisPlusConfig.java src/main/java/com/label/config/MybatisPlusConfig.java
git mv src/main/java/com/label/common/config/OpenApiConfig.java src/main/java/com/label/config/OpenApiConfig.java
git mv src/main/java/com/label/common/config/RedisConfig.java src/main/java/com/label/config/RedisConfig.java
git mv src/main/java/com/label/module/annotation/event/ExtractionApprovedEvent.java src/main/java/com/label/event/ExtractionApprovedEvent.java
git mv src/main/java/com/label/module/annotation/service/ExtractionApprovedEventListener.java src/main/java/com/label/listener/ExtractionApprovedEventListener.java

再做精确替换:

// OperationLog.java
package com.label.annotation;

// AuditAspect.java
package com.label.aspect;
import com.label.annotation.OperationLog;

// MybatisPlusConfig.java / OpenApiConfig.java / RedisConfig.java
package com.label.config;

// ExtractionApprovedEvent.java
package com.label.event;

// ExtractionApprovedEventListener.java
package com.label.listener;
import com.label.event.ExtractionApprovedEvent;
import com.label.module.annotation.entity.TrainingDataset;
import com.label.module.annotation.mapper.AnnotationResultMapper;
import com.label.module.annotation.mapper.TrainingDatasetMapper;
import com.label.module.source.entity.SourceData;
import com.label.module.source.mapper.SourceDataMapper;
import com.label.module.task.service.TaskService;

并把 src/main/java/com/label/module/annotation/service/ExtractionService.java 中事件 import 改成 com.label.event.ExtractionApprovedEvent

  • Step 4: 跑绿

Run:

  • mvn -q "-Dtest=PackageStructureMigrationTest#infrastructureTypesMoved" test
  • mvn -q -DskipTests compile

Expected: 两条命令都 BUILD SUCCESS

  • Step 5: Commit
git add src/test/java/com/label/unit/PackageStructureMigrationTest.java src/main/java/com/label/annotation src/main/java/com/label/aspect src/main/java/com/label/config src/main/java/com/label/event src/main/java/com/label/listener src/main/java/com/label/module/annotation/service/ExtractionService.java
git commit -m "refactor: flatten infrastructure packages"

Task 2: 迁移 DTO、Entity、Mapper

Files:

  • Modify: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Modify: src/test/java/com/label/unit/OpenApiAnnotationTest.java

  • Modify: src/test/java/com/label/integration/AuthIntegrationTest.java

  • Modify: src/test/java/com/label/integration/ExtractionApprovalIntegrationTest.java

  • Modify: src/test/java/com/label/integration/QaApprovalIntegrationTest.java

  • Modify: src/test/java/com/label/integration/UserManagementIntegrationTest.java

  • Modify: src/main/java/com/label/module/annotation/service/ExtractionService.java

  • Modify: src/main/java/com/label/module/annotation/service/QaService.java

  • Modify: src/main/java/com/label/module/config/service/SysConfigService.java

  • Modify: src/main/java/com/label/module/config/controller/SysConfigController.java

  • Modify: src/main/java/com/label/module/export/service/ExportService.java

  • Modify: src/main/java/com/label/module/export/service/FinetuneService.java

  • Modify: src/main/java/com/label/module/export/controller/ExportController.java

  • Modify: src/main/java/com/label/module/source/service/SourceService.java

  • Modify: src/main/java/com/label/module/source/controller/SourceController.java

  • Modify: src/main/java/com/label/module/task/service/TaskClaimService.java

  • Modify: src/main/java/com/label/module/task/service/TaskService.java

  • Modify: src/main/java/com/label/module/task/controller/TaskController.java

  • Modify: src/main/java/com/label/module/user/service/AuthService.java

  • Modify: src/main/java/com/label/module/user/service/UserService.java

  • Modify: src/main/java/com/label/module/user/controller/AuthController.java

  • Modify: src/main/java/com/label/module/user/controller/UserController.java

  • Modify: src/main/java/com/label/module/video/service/VideoProcessService.java

  • Modify: src/main/java/com/label/module/video/controller/VideoController.java

  • Test: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Step 1: 写失败测试

PackageStructureMigrationTest.java 里追加:

    @Test
    @DisplayName("DTO、实体、Mapper 已迁移到扁平数据层")
    void dataTypesMoved() {
        for (String fqcn : java.util.List.of(
                "com.label.dto.LoginRequest", "com.label.dto.LoginResponse", "com.label.dto.UserInfoResponse",
                "com.label.dto.TaskResponse", "com.label.dto.SourceResponse",
                "com.label.entity.AnnotationResult", "com.label.entity.TrainingDataset", "com.label.entity.SysConfig",
                "com.label.entity.ExportBatch", "com.label.entity.SourceData", "com.label.entity.AnnotationTask",
                "com.label.entity.AnnotationTaskHistory", "com.label.entity.SysCompany", "com.label.entity.SysUser",
                "com.label.entity.VideoProcessJob",
                "com.label.mapper.AnnotationResultMapper", "com.label.mapper.TrainingDatasetMapper",
                "com.label.mapper.SysConfigMapper", "com.label.mapper.ExportBatchMapper", "com.label.mapper.SourceDataMapper",
                "com.label.mapper.AnnotationTaskMapper", "com.label.mapper.TaskHistoryMapper",
                "com.label.mapper.SysCompanyMapper", "com.label.mapper.SysUserMapper", "com.label.mapper.VideoProcessJobMapper")) {
            assertClassExists(fqcn);
        }
    }
  • Step 2: 跑红

Run: mvn -q "-Dtest=PackageStructureMigrationTest#dataTypesMoved" test

Expected: FAIL提示 com.label.dto.LoginRequest 等不存在。

  • Step 3: 最小实现

执行迁移:

git mv src/main/java/com/label/module/user/dto/LoginRequest.java src/main/java/com/label/dto/LoginRequest.java
git mv src/main/java/com/label/module/user/dto/LoginResponse.java src/main/java/com/label/dto/LoginResponse.java
git mv src/main/java/com/label/module/user/dto/UserInfoResponse.java src/main/java/com/label/dto/UserInfoResponse.java
git mv src/main/java/com/label/module/task/dto/TaskResponse.java src/main/java/com/label/dto/TaskResponse.java
git mv src/main/java/com/label/module/source/dto/SourceResponse.java src/main/java/com/label/dto/SourceResponse.java
git mv src/main/java/com/label/module/annotation/entity/AnnotationResult.java src/main/java/com/label/entity/AnnotationResult.java
git mv src/main/java/com/label/module/annotation/entity/TrainingDataset.java src/main/java/com/label/entity/TrainingDataset.java
git mv src/main/java/com/label/module/config/entity/SysConfig.java src/main/java/com/label/entity/SysConfig.java
git mv src/main/java/com/label/module/export/entity/ExportBatch.java src/main/java/com/label/entity/ExportBatch.java
git mv src/main/java/com/label/module/source/entity/SourceData.java src/main/java/com/label/entity/SourceData.java
git mv src/main/java/com/label/module/task/entity/AnnotationTask.java src/main/java/com/label/entity/AnnotationTask.java
git mv src/main/java/com/label/module/task/entity/AnnotationTaskHistory.java src/main/java/com/label/entity/AnnotationTaskHistory.java
git mv src/main/java/com/label/module/user/entity/SysCompany.java src/main/java/com/label/entity/SysCompany.java
git mv src/main/java/com/label/module/user/entity/SysUser.java src/main/java/com/label/entity/SysUser.java
git mv src/main/java/com/label/module/video/entity/VideoProcessJob.java src/main/java/com/label/entity/VideoProcessJob.java
git mv src/main/java/com/label/module/annotation/mapper/AnnotationResultMapper.java src/main/java/com/label/mapper/AnnotationResultMapper.java
git mv src/main/java/com/label/module/annotation/mapper/TrainingDatasetMapper.java src/main/java/com/label/mapper/TrainingDatasetMapper.java
git mv src/main/java/com/label/module/config/mapper/SysConfigMapper.java src/main/java/com/label/mapper/SysConfigMapper.java
git mv src/main/java/com/label/module/export/mapper/ExportBatchMapper.java src/main/java/com/label/mapper/ExportBatchMapper.java
git mv src/main/java/com/label/module/source/mapper/SourceDataMapper.java src/main/java/com/label/mapper/SourceDataMapper.java
git mv src/main/java/com/label/module/task/mapper/AnnotationTaskMapper.java src/main/java/com/label/mapper/AnnotationTaskMapper.java
git mv src/main/java/com/label/module/task/mapper/TaskHistoryMapper.java src/main/java/com/label/mapper/TaskHistoryMapper.java
git mv src/main/java/com/label/module/user/mapper/SysCompanyMapper.java src/main/java/com/label/mapper/SysCompanyMapper.java
git mv src/main/java/com/label/module/user/mapper/SysUserMapper.java src/main/java/com/label/mapper/SysUserMapper.java
git mv src/main/java/com/label/module/video/mapper/VideoProcessJobMapper.java src/main/java/com/label/mapper/VideoProcessJobMapper.java

统一替换包声明:

package com.label.dto;
package com.label.entity;
package com.label.mapper;

然后把上面 Files 列表中的旧 com.label.module.*.(dto|entity|mapper) import 全部改到新包。

  • Step 4: 跑绿

Run:

  • mvn -q "-Dtest=PackageStructureMigrationTest#dataTypesMoved,OpenApiAnnotationTest,AuthIntegrationTest,ExtractionApprovalIntegrationTest,QaApprovalIntegrationTest,UserManagementIntegrationTest" test

Expected: PASS。

  • Step 5: Commit
git add src/main/java/com/label/dto src/main/java/com/label/entity src/main/java/com/label/mapper src/test/java/com/label/unit/PackageStructureMigrationTest.java src/test/java/com/label/unit/OpenApiAnnotationTest.java src/test/java/com/label/integration/AuthIntegrationTest.java src/test/java/com/label/integration/ExtractionApprovalIntegrationTest.java src/test/java/com/label/integration/QaApprovalIntegrationTest.java src/test/java/com/label/integration/UserManagementIntegrationTest.java src/main/java/com/label/module
git commit -m "refactor: flatten dto entity and mapper packages"

Task 3: 迁移业务服务层

Files:

  • Modify: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Modify: src/main/java/com/label/module/annotation/controller/ExtractionController.java

  • Modify: src/main/java/com/label/module/annotation/controller/QaController.java

  • Modify: src/main/java/com/label/module/config/controller/SysConfigController.java

  • Modify: src/main/java/com/label/module/export/controller/ExportController.java

  • Modify: src/main/java/com/label/module/source/controller/SourceController.java

  • Modify: src/main/java/com/label/module/task/controller/TaskController.java

  • Modify: src/main/java/com/label/module/user/controller/AuthController.java

  • Modify: src/main/java/com/label/module/user/controller/UserController.java

  • Modify: src/main/java/com/label/module/video/controller/VideoController.java

  • Test: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Step 1: 写失败测试

    @Test
    @DisplayName("服务类已迁移到扁平 service 目录")
    void serviceTypesMoved() {
        for (String fqcn : java.util.List.of(
                "com.label.service.ExtractionService", "com.label.service.QaService",
                "com.label.service.SysConfigService", "com.label.service.ExportService",
                "com.label.service.FinetuneService", "com.label.service.SourceService",
                "com.label.service.TaskClaimService", "com.label.service.TaskService",
                "com.label.service.AuthService", "com.label.service.UserService",
                "com.label.service.VideoProcessService")) {
            assertClassExists(fqcn);
        }
    }
  • Step 2: 跑红

Run: mvn -q "-Dtest=PackageStructureMigrationTest#serviceTypesMoved" test

Expected: FAIL提示 com.label.service.* 不存在。

  • Step 3: 最小实现

执行迁移:

git mv src/main/java/com/label/module/annotation/service/ExtractionService.java src/main/java/com/label/service/ExtractionService.java
git mv src/main/java/com/label/module/annotation/service/QaService.java src/main/java/com/label/service/QaService.java
git mv src/main/java/com/label/module/config/service/SysConfigService.java src/main/java/com/label/service/SysConfigService.java
git mv src/main/java/com/label/module/export/service/ExportService.java src/main/java/com/label/service/ExportService.java
git mv src/main/java/com/label/module/export/service/FinetuneService.java src/main/java/com/label/service/FinetuneService.java
git mv src/main/java/com/label/module/source/service/SourceService.java src/main/java/com/label/service/SourceService.java
git mv src/main/java/com/label/module/task/service/TaskClaimService.java src/main/java/com/label/service/TaskClaimService.java
git mv src/main/java/com/label/module/task/service/TaskService.java src/main/java/com/label/service/TaskService.java
git mv src/main/java/com/label/module/user/service/AuthService.java src/main/java/com/label/service/AuthService.java
git mv src/main/java/com/label/module/user/service/UserService.java src/main/java/com/label/service/UserService.java
git mv src/main/java/com/label/module/video/service/VideoProcessService.java src/main/java/com/label/service/VideoProcessService.java

统一替换:

package com.label.service;

并把 ExtractionControllerQaControllerSysConfigControllerExportControllerSourceControllerTaskControllerAuthControllerUserControllerVideoController 的服务导包改到 com.label.service.*

  • Step 4: 跑绿

Run:

  • mvn -q "-Dtest=PackageStructureMigrationTest#serviceTypesMoved" test
  • mvn -q -DskipTests compile

Expected: PASS。

  • Step 5: Commit
git add src/main/java/com/label/service src/main/java/com/label/module/annotation/controller/ExtractionController.java src/main/java/com/label/module/annotation/controller/QaController.java src/main/java/com/label/module/config/controller/SysConfigController.java src/main/java/com/label/module/export/controller/ExportController.java src/main/java/com/label/module/source/controller/SourceController.java src/main/java/com/label/module/task/controller/TaskController.java src/main/java/com/label/module/user/controller/AuthController.java src/main/java/com/label/module/user/controller/UserController.java src/main/java/com/label/module/video/controller/VideoController.java src/test/java/com/label/unit/PackageStructureMigrationTest.java
git commit -m "refactor: flatten service packages"

Task 4: 迁移控制器并收敛 OpenAPI 测试

Files:

  • Modify: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Modify: src/test/java/com/label/unit/OpenApiAnnotationTest.java

  • Test: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Test: src/test/java/com/label/unit/OpenApiAnnotationTest.java

  • Step 1: 写失败测试

    @Test
    @DisplayName("控制器已迁移到扁平 controller 目录")
    void controllerTypesMoved() {
        for (String fqcn : java.util.List.of(
                "com.label.controller.AuthController", "com.label.controller.UserController",
                "com.label.controller.SourceController", "com.label.controller.TaskController",
                "com.label.controller.ExtractionController", "com.label.controller.QaController",
                "com.label.controller.ExportController", "com.label.controller.SysConfigController",
                "com.label.controller.VideoController")) {
            assertClassExists(fqcn);
        }
    }
  • Step 2: 跑红

Run: mvn -q "-Dtest=PackageStructureMigrationTest#controllerTypesMoved" test

Expected: FAIL提示 com.label.controller.* 不存在。

  • Step 3: 最小实现

执行迁移:

git mv src/main/java/com/label/module/annotation/controller/ExtractionController.java src/main/java/com/label/controller/ExtractionController.java
git mv src/main/java/com/label/module/annotation/controller/QaController.java src/main/java/com/label/controller/QaController.java
git mv src/main/java/com/label/module/config/controller/SysConfigController.java src/main/java/com/label/controller/SysConfigController.java
git mv src/main/java/com/label/module/export/controller/ExportController.java src/main/java/com/label/controller/ExportController.java
git mv src/main/java/com/label/module/source/controller/SourceController.java src/main/java/com/label/controller/SourceController.java
git mv src/main/java/com/label/module/task/controller/TaskController.java src/main/java/com/label/controller/TaskController.java
git mv src/main/java/com/label/module/user/controller/AuthController.java src/main/java/com/label/controller/AuthController.java
git mv src/main/java/com/label/module/user/controller/UserController.java src/main/java/com/label/controller/UserController.java
git mv src/main/java/com/label/module/video/controller/VideoController.java src/main/java/com/label/controller/VideoController.java

统一替换:

package com.label.controller;

并把 OpenApiAnnotationTest.java 的 import 替换成:

import com.label.controller.AuthController;
import com.label.controller.UserController;
import com.label.controller.SourceController;
import com.label.controller.TaskController;
import com.label.controller.ExtractionController;
import com.label.controller.QaController;
import com.label.controller.ExportController;
import com.label.controller.SysConfigController;
import com.label.controller.VideoController;
import com.label.dto.LoginRequest;
import com.label.dto.LoginResponse;
import com.label.dto.UserInfoResponse;
import com.label.dto.TaskResponse;
import com.label.dto.SourceResponse;
  • Step 4: 跑绿

Run: mvn -q "-Dtest=PackageStructureMigrationTest#controllerTypesMoved,OpenApiAnnotationTest" test

Expected: PASS。

  • Step 5: Commit
git add src/main/java/com/label/controller src/test/java/com/label/unit/PackageStructureMigrationTest.java src/test/java/com/label/unit/OpenApiAnnotationTest.java
git commit -m "refactor: flatten controller packages"

Task 5: 清理旧包残留并做全量回归

Files:

  • Modify: src/test/java/com/label/unit/PackageStructureMigrationTest.java

  • Test: src/test/java/com/label/LabelBackendApplicationTests.java

  • Test: src/test/java/com/label/unit/ApplicationConfigTest.java

  • Test: src/test/java/com/label/unit/ShiroConfigTest.java

  • Test: src/test/java/com/label/unit/StateMachineTest.java

  • Test: src/test/java/com/label/unit/TokenFilterTest.java

  • Test: src/test/java/com/label/integration/AuthIntegrationTest.java

  • Test: src/test/java/com/label/integration/ExportIntegrationTest.java

  • Test: src/test/java/com/label/integration/ExtractionApprovalIntegrationTest.java

  • Test: src/test/java/com/label/integration/MultiTenantIsolationTest.java

  • Test: src/test/java/com/label/integration/QaApprovalIntegrationTest.java

  • Test: src/test/java/com/label/integration/ShiroFilterIntegrationTest.java

  • Test: src/test/java/com/label/integration/SourceIntegrationTest.java

  • Test: src/test/java/com/label/integration/SysConfigIntegrationTest.java

  • Test: src/test/java/com/label/integration/TaskClaimConcurrencyTest.java

  • Test: src/test/java/com/label/integration/UserManagementIntegrationTest.java

  • Test: src/test/java/com/label/integration/VideoCallbackIdempotencyTest.java

  • Step 1: 写最终守卫测试

PackageStructureMigrationTest.java 中补充:

    @Test
    @DisplayName("源码中不再引用旧的 module、common.aop、common.config 包")
    void sourceTreeHasNoLegacyPackageReferences() throws Exception {
        try (java.util.stream.Stream<java.nio.file.Path> paths = java.nio.file.Files.walk(java.nio.file.Path.of("src"))) {
            java.util.List<String> violations = paths
                    .filter(path -> path.toString().endsWith(".java"))
                    .map(path -> {
                        try {
                            String text = java.nio.file.Files.readString(path);
                            boolean legacy = text.contains("com.label.module.")
                                    || text.contains("com.label.common.aop")
                                    || text.contains("com.label.common.config");
                            return legacy ? path.toString() : null;
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    })
                    .filter(java.util.Objects::nonNull)
                    .toList();

            org.assertj.core.api.Assertions.assertThat(violations).isEmpty();
        }
    }
  • Step 2: 跑红并定位残留

Run:

  • mvn -q "-Dtest=PackageStructureMigrationTest#sourceTreeHasNoLegacyPackageReferences" test
  • rg -n "com\.label\.module\.|com\.label\.common\.aop|com\.label\.common\.config" src/main/java src/test/java

Expected: 初次 FAIL并列出残留文件。

  • Step 3: 清理残留并确认旧目录为空

Run:

Get-ChildItem -Path src/main/java/com/label/module -Recurse

Expected: 没有 Java 文件残留;确认后删除空目录。

  • Step 4: 全量回归

Run: mvn clean test

Expected: BUILD SUCCESS

  • Step 5: Commit
git add src/main/java src/test/java
git commit -m "refactor: complete backend directory flattening"

自检

  • 覆盖了 annotation / aspect / config / event / listener / dto / entity / mapper / service / controller
  • 没有引入 service.impl
  • 没有拆分 dto/requestdto/response
  • 最终门槛是 mvn clean test