# 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: 写失败测试** ```java 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: 最小实现** 先执行迁移: ```powershell 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 ``` 再做精确替换: ```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** ```powershell 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` 里追加: ```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: 最小实现** 执行迁移: ```powershell 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 ``` 统一替换包声明: ```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** ```powershell 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: 写失败测试** ```java @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: 最小实现** 执行迁移: ```powershell 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 ``` 统一替换: ```java package com.label.service; ``` 并把 `ExtractionController`、`QaController`、`SysConfigController`、`ExportController`、`SourceController`、`TaskController`、`AuthController`、`UserController`、`VideoController` 的服务导包改到 `com.label.service.*`。 - [ ] **Step 4: 跑绿** Run: - `mvn -q "-Dtest=PackageStructureMigrationTest#serviceTypesMoved" test` - `mvn -q -DskipTests compile` Expected: PASS。 - [ ] **Step 5: Commit** ```powershell 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: 写失败测试** ```java @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: 最小实现** 执行迁移: ```powershell 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 ``` 统一替换: ```java package com.label.controller; ``` 并把 `OpenApiAnnotationTest.java` 的 import 替换成: ```java 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** ```powershell 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` 中补充: ```java @Test @DisplayName("源码中不再引用旧的 module、common.aop、common.config 包") void sourceTreeHasNoLegacyPackageReferences() throws Exception { try (java.util.stream.Stream paths = java.nio.file.Files.walk(java.nio.file.Path.of("src"))) { java.util.List 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: ```powershell Get-ChildItem -Path src/main/java/com/label/module -Recurse ``` Expected: 没有 Java 文件残留;确认后删除空目录。 - [ ] **Step 4: 全量回归** Run: `mvn clean test` Expected: `BUILD SUCCESS`。 - [ ] **Step 5: Commit** ```powershell 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/request`、`dto/response` - 最终门槛是 `mvn clean test`