停止追踪specs,docs等目录文件

This commit is contained in:
wh
2026-04-14 21:04:37 +08:00
parent 5839bc2ece
commit 8ba3de17ab
23 changed files with 0 additions and 7547 deletions

View File

@@ -1,517 +0,0 @@
# Deploy Optimization 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:** 将 label_backend 从 Spring Boot fat JAR 方式改造为薄 jar + Maven Assembly 分发包,并统一日志级别为 INFO。
**Architecture:** 移除 `spring-boot-maven-plugin`,改用 `maven-jar-plugin`(薄 jar+ `maven-dependency-plugin`(复制依赖到 `target/libs/`+ `maven-assembly-plugin`(组装 zip/tar.gz。新增 `start.sh`Docker/VM 双模式启动)和 `logback.xml`60 MB 滚动。Dockerfile 改为多阶段构建,从 `target/libs/``src/main/resources/` 复制构建产物。
**Tech Stack:** Maven 3.9, JDK 17, Spring Boot 3.2.5, maven-assembly-plugin 3.x, logback 1.4.x (Spring Boot 管理版本)
---
## 文件结构
| 操作 | 路径 | 说明 |
|------|------|------|
| 新建 | `src/main/resources/logback.xml` | INFO 级60 MB 滚动日志配置 |
| 新建 | `src/main/scripts/start.sh` | Docker/VM 双模式启动脚本 |
| 新建 | `src/main/assembly/distribution.xml` | Assembly 描述符 |
| 新建 | `src/main/assembly/empty-logs/.gitkeep` | logs/ 目录占位Assembly 引用) |
| 修改 | `pom.xml` | 替换 spring-boot-maven-plugin |
| 修改 | `Dockerfile` | 多阶段构建,复制 etc/ + libs/ |
| 批量修改 | 11 个 Service 类 | `log.debug``log.info`21 处) |
---
## Task 1: 创建 logback.xml
**Files:**
- Create: `src/main/resources/logback.xml`
- [ ] **Step 1: 创建 logback.xml 文件**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
<property name="LOG_PATH" value="${LOG_PATH:-logs}"/>
<property name="APP_NAME" value="label-backend"/>
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出Docker 日志采集依赖 stdout -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 滚动文件60 MB / 个,按日分组,保留 30 天,总上限 3 GB -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}.log</file>
<encoder charset="UTF-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>60MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
```
- [ ] **Step 2: 验证文件存在**
```bash
ls src/main/resources/logback.xml
```
预期输出:`src/main/resources/logback.xml`
- [ ] **Step 3: Commit**
```bash
git add src/main/resources/logback.xml
git commit -m "feat(deploy): 添加 logback.xmlINFO 级60 MB 滚动)"
```
---
## Task 2: 创建 start.sh 启动脚本
**Files:**
- Create: `src/main/scripts/start.sh`
- [ ] **Step 1: 创建目录并写入 start.sh**
```bash
mkdir -p src/main/scripts
```
文件内容 `src/main/scripts/start.sh`
```bash
#!/bin/bash
# label-backend 启动脚本
# - Docker 环境(检测 /.dockerenvexec 前台运行,保持容器进程存活
# - 裸机 / VMnohup 后台运行,日志追加至 logs/startup.log
set -e
BASEDIR=$(cd "$(dirname "$0")/.." && pwd)
LIBDIR="$BASEDIR/libs"
CONFDIR="$BASEDIR/etc"
LOGDIR="$BASEDIR/logs"
mkdir -p "$LOGDIR"
JVM_OPTS="${JVM_OPTS:--Xms512m -Xmx1024m}"
MAIN_CLASS="com.label.LabelBackendApplication"
JAVA_ARGS="$JVM_OPTS \
-Dspring.config.location=file:$CONFDIR/application.yml \
-Dlogging.config=file:$CONFDIR/logback.xml \
-cp $LIBDIR/*"
if [ -f /.dockerenv ]; then
# Docker 容器exec 替换当前进程PID=1 接管信号
exec java $JAVA_ARGS $MAIN_CLASS
else
# 裸机 / VMnohup 后台运行
nohup java $JAVA_ARGS $MAIN_CLASS >> "$LOGDIR/startup.log" 2>&1 &
echo "label-backend started, PID=$!"
fi
```
- [ ] **Step 2: 验证文件存在**
```bash
ls src/main/scripts/start.sh
```
预期输出:`src/main/scripts/start.sh`
- [ ] **Step 3: Commit**
```bash
git add src/main/scripts/start.sh
git commit -m "feat(deploy): 添加 start.shDocker exec / VM nohup 双模式)"
```
---
## Task 3: 创建 Assembly 描述符和目录占位
**Files:**
- Create: `src/main/assembly/distribution.xml`
- Create: `src/main/assembly/empty-logs/.gitkeep`
- [ ] **Step 1: 创建 assembly 目录结构**
```bash
mkdir -p src/main/assembly/empty-logs
touch src/main/assembly/empty-logs/.gitkeep
```
- [ ] **Step 2: 创建 distribution.xml**
文件内容 `src/main/assembly/distribution.xml`
```xml
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0
https://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>dist</id>
<formats>
<format>zip</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<!-- bin/start.sh0755 可执行) -->
<files>
<file>
<source>src/main/scripts/start.sh</source>
<outputDirectory>bin</outputDirectory>
<fileMode>0755</fileMode>
</file>
</files>
<fileSets>
<!-- etc/application.yml + logback.xml -->
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>etc</outputDirectory>
<includes>
<include>application.yml</include>
<include>logback.xml</include>
</includes>
</fileSet>
<!-- libs/:薄 jar + 所有运行时依赖 -->
<fileSet>
<directory>${project.build.directory}/libs</directory>
<outputDirectory>libs</outputDirectory>
<includes>
<include>**/*.jar</include>
</includes>
</fileSet>
<!-- logs/ 空目录占位 -->
<fileSet>
<directory>src/main/assembly/empty-logs</directory>
<outputDirectory>logs</outputDirectory>
</fileSet>
</fileSets>
</assembly>
```
- [ ] **Step 3: 验证文件存在**
```bash
ls src/main/assembly/distribution.xml src/main/assembly/empty-logs/.gitkeep
```
预期输出:两个文件路径均显示
- [ ] **Step 4: Commit**
```bash
git add src/main/assembly/
git commit -m "feat(deploy): 添加 Assembly 描述符 distribution.xml"
```
---
## Task 4: 更新 pom.xml替换 spring-boot-maven-plugin
**Files:**
- Modify: `pom.xml`
- [ ] **Step 1: 替换 `<build><plugins>` 段落**
`pom.xml``<build>` 段(当前仅含 spring-boot-maven-plugin替换为
```xml
<build>
<plugins>
<!-- 薄 jar仅打包编译后的 class输出到 target/libs/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
<archive>
<manifest>
<mainClass>com.label.LabelBackendApplication</mainClass>
<addClasspath>false</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 将所有运行时依赖复制到 target/libs/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<!-- 组装分发包zip + tar.gz -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>create-distribution</id>
<phase>package</phase>
<goals><goal>single</goal></goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/distribution.xml</descriptor>
</descriptors>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
```
即用上述内容完整替换 `pom.xml` 中现有的 `<build>...</build>` 块(原内容为含 spring-boot-maven-plugin 的单插件配置)。
- [ ] **Step 2: 验证语法并试构建**
```bash
mvn validate -q
```
预期输出:无错误(只做 pom.xml 解析校验,不实际编译)
- [ ] **Step 3: Commit**
```bash
git add pom.xml
git commit -m "feat(deploy): pom.xml 替换 fat JAR → 薄 jar + maven-dependency + maven-assembly"
```
---
## Task 5: 更新 Dockerfile
**Files:**
- Modify: `Dockerfile`
- [ ] **Step 1: 替换 Dockerfile 全文**
```dockerfile
# 构建阶段Maven + JDK 17 编译,生成薄 jar 及依赖
FROM maven:3.9-eclipse-temurin-17-alpine AS builder
WORKDIR /app
# 优先复制 pom.xml 利用 Docker 层缓存(依赖不变时跳过 go-offline
COPY pom.xml .
RUN mvn dependency:go-offline -q
COPY src ./src
RUN mvn clean package -DskipTests -q
# 运行阶段:仅含 JRE 的精简镜像
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 复制部署结构bin/ libs/ etc/
COPY --from=builder /app/src/main/scripts/start.sh bin/start.sh
COPY --from=builder /app/target/libs/ libs/
COPY --from=builder /app/src/main/resources/application.yml etc/application.yml
COPY --from=builder /app/src/main/resources/logback.xml etc/logback.xml
RUN mkdir -p logs && chmod +x bin/start.sh
EXPOSE 8080
# start.sh 检测到 /.dockerenv 后以 exec 前台方式运行
ENTRYPOINT ["bin/start.sh"]
```
- [ ] **Step 2: 验证 Dockerfile 语法**
```bash
docker build --no-cache --dry-run . 2>/dev/null || echo "docker not available; syntax check skipped"
```
预期:无语法错误(或 docker 不可用时跳过)
- [ ] **Step 3: Commit**
```bash
git add Dockerfile
git commit -m "feat(deploy): Dockerfile 改为多阶段构建(薄 jar + start.sh"
```
---
## Task 6: 批量替换 log.debug → log.info11 文件21 处)
**Files:**
- Modify: `src/main/java/com/label/module/video/service/VideoProcessService.java` (5 处)
- Modify: `src/main/java/com/label/module/source/service/SourceService.java` (2 处)
- Modify: `src/main/java/com/label/module/user/service/UserService.java` (3 处)
- Modify: `src/main/java/com/label/module/user/service/AuthService.java` (2 处)
- Modify: `src/main/java/com/label/module/config/service/SysConfigService.java` (2 处)
- Modify: `src/main/java/com/label/module/annotation/service/ExtractionApprovedEventListener.java` (2 处)
- Modify: `src/main/java/com/label/module/task/service/TaskService.java` (1 处)
- Modify: `src/main/java/com/label/module/annotation/service/QaService.java` (1 处)
- Modify: `src/main/java/com/label/module/export/service/FinetuneService.java` (1 处)
- Modify: `src/main/java/com/label/module/task/service/TaskClaimService.java` (1 处)
- Modify: `src/main/java/com/label/module/export/service/ExportService.java` (1 处)
- [ ] **Step 1: 批量替换**
```bash
find src/main/java -name "*.java" \
-exec sed -i 's/log\.debug(/log.info(/g' {} +
```
- [ ] **Step 2: 验证替换完整,无 log.debug 残留**
```bash
grep -r "log\.debug" src/main/java && echo "FAIL: 仍有 log.debug 残留" || echo "PASS: 无 log.debug"
```
预期输出:`PASS: 无 log.debug`
- [ ] **Step 3: 验证替换数量正确(应有 21 处 log.info 新增)**
```bash
git diff --stat src/main/java | tail -1
```
预期:显示 11 个文件21 处改动(`21 insertions(+), 21 deletions(-)`
- [ ] **Step 4: Commit**
```bash
git add src/main/java/
git commit -m "refactor(log): log.debug 全量替换为 log.info11 文件21 处)"
```
---
## Task 7: 全量构建验证
**Files:** 只读操作,不修改文件
- [ ] **Step 1: 执行完整构建(跳过测试)**
```bash
mvn clean package -DskipTests
```
预期:`BUILD SUCCESS`,无 ERROR 输出
- [ ] **Step 2: 验证 target/libs/ 目录存在且包含 jar**
```bash
ls target/libs/*.jar | head -5
ls target/libs/label-backend-1.0.0-SNAPSHOT.jar
```
预期:显示薄 jar 及多个依赖 jar
- [ ] **Step 3: 验证分发包已生成**
```bash
ls target/label-backend-1.0.0-SNAPSHOT.zip
ls target/label-backend-1.0.0-SNAPSHOT.tar.gz
```
预期:两个文件均存在
- [ ] **Step 4: 验证分发包内部结构**
```bash
# 使用 unzip 检查 zip 内容Windows Git Bash 或 Linux 均可用)
unzip -l target/label-backend-1.0.0-SNAPSHOT.zip | grep -E "bin/|etc/|libs/|logs/"
```
预期输出包含:
```
label-backend-1.0.0-SNAPSHOT/bin/start.sh
label-backend-1.0.0-SNAPSHOT/etc/application.yml
label-backend-1.0.0-SNAPSHOT/etc/logback.xml
label-backend-1.0.0-SNAPSHOT/libs/label-backend-1.0.0-SNAPSHOT.jar
label-backend-1.0.0-SNAPSHOT/logs/
```
- [ ] **Step 5: 验证 logback.xml 已包含在 etc/ 内**
```bash
unzip -l target/label-backend-1.0.0-SNAPSHOT.zip | grep logback
```
预期:`label-backend-1.0.0-SNAPSHOT/etc/logback.xml`
- [ ] **Step 6: Commit 构建验证记录(如有必要则修正问题后提交)**
若 Step 1-5 全部通过,无需额外提交。若发现问题(如缺少文件、路径错误),修正对应 Task 后重新执行本 Task。
---
## 自检
### Spec 覆盖检查
| deploy.md 需求 | 对应任务 |
|---------------|---------|
| 1. 分发包结构 bin/etc/libs/logs | Task 3 (distribution.xml) + Task 7 验证 |
| 2. start.sh nohup 后台启动 | Task 2 |
| 3. logback.xml INFO + 60 MB 滚动 | Task 1 |
| 4. logback.xml + application.yml 在 etc/ | Task 3 (distribution.xml fileSets) |
| 5. maven-jar-plugin + maven-dependency-plugin | Task 4 |
| 6. Maven Assembly Plugin → zip/tar.gz | Task 3 + Task 4 |
| 7. Dockerfile 复制 etc/ + 调用 start.sh | Task 5 |
| 8. log.debug → log.info | Task 6 |
所有 8 条需求均有对应任务。✅
### 类型一致性
- `MAIN_CLASS="com.label.LabelBackendApplication"` — 与 `src/main/java/com/label/LabelBackendApplication.java` 一致 ✅
- `maven-jar-plugin` 输出路径 `target/libs/` — 与 Dockerfile `COPY --from=builder /app/target/libs/` 一致 ✅
- `distribution.xml` `<directory>${project.build.directory}/libs</directory>` — 与 `maven-dependency-plugin``outputDirectory` 一致 ✅
## GSTACK REVIEW REPORT
| Review | Trigger | Why | Runs | Status | Findings |
|--------|---------|-----|------|--------|----------|
| CEO Review | `/plan-ceo-review` | Scope & strategy | 0 | — | — |
| Codex Review | `/codex review` | Independent 2nd opinion | 0 | — | — |
| Eng Review | `/plan-eng-review` | Architecture & tests (required) | 0 | — | — |
| Design Review | `/plan-design-review` | UI/UX gaps | 0 | — | — |
**VERDICT:** NO REVIEWS YET — run `/autoplan` for full review pipeline, or individual reviews above.

File diff suppressed because it is too large Load Diff

View File

@@ -1,66 +0,0 @@
# Auth And Company Optimization 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:** Replace the remaining Shiro authorization layer with project-owned Redis token authentication and add company CRUD APIs.
**Architecture:** Keep the existing UUID token, Redis session storage, and `CompanyContext` tenant injection. Add project-owned `@RequireAuth` and `@RequireRole` annotations plus a Spring MVC `AuthInterceptor`, then remove Shiro config/classes/dependencies. Add `CompanyService` and `CompanyController` for `sys_company` management.
**Tech Stack:** Java 21, Spring Boot 3.1.5, Spring MVC HandlerInterceptor, RedisTemplate, MyBatis-Plus, JUnit 5, Mockito, AssertJ.
---
### Task 1: Replace Shiro With Custom Auth Interceptor
**Files:**
- Create: `src/main/java/com/label/annotation/RequireAuth.java`
- Create: `src/main/java/com/label/annotation/RequireRole.java`
- Create: `src/main/java/com/label/interceptor/AuthInterceptor.java`
- Create: `src/main/java/com/label/common/auth/TokenPrincipal.java`
- Create: `src/main/java/com/label/common/context/UserContext.java`
- Modify: `src/main/java/com/label/config/ShiroConfig.java`
- Modify: `src/main/java/com/label/common/shiro/TokenFilter.java`
- Modify: `src/main/java/com/label/common/shiro/BearerToken.java`
- Modify: `src/main/java/com/label/common/shiro/UserRealm.java`
- Modify: `src/main/java/com/label/controller/*.java`
- Modify: `src/main/java/com/label/service/*.java`
- Modify: `pom.xml`
- Test: `src/test/java/com/label/unit/AuthInterceptorTest.java`
- [x] Write failing tests for token loading, TTL refresh, role hierarchy, and context cleanup.
- [x] Implement annotations, principal, context, and interceptor.
- [x] Register the interceptor via Spring MVC config.
- [x] Replace controller `@RequiresRoles` usage with `@RequireRole`.
- [x] Remove Shiro-only classes, tests, dependencies, and exception handling.
- [x] Run `mvn -q "-Dtest=AuthInterceptorTest,OpenApiAnnotationTest" test` and `mvn -q -DskipTests compile`.
### Task 2: Add Company Management
**Files:**
- Create: `src/main/java/com/label/service/CompanyService.java`
- Create: `src/main/java/com/label/controller/CompanyController.java`
- Modify: `src/main/java/com/label/mapper/SysUserMapper.java`
- Test: `src/test/java/com/label/unit/CompanyServiceTest.java`
- Test: `src/test/java/com/label/unit/OpenApiAnnotationTest.java`
- [x] Write failing tests for create/list/update/status/delete behavior.
- [x] Implement service validation and duplicate checks.
- [x] Implement admin-only controller endpoints under `/api/companies`.
- [x] Run `mvn -q "-Dtest=CompanyServiceTest,OpenApiAnnotationTest" test` and `mvn -q -DskipTests compile`.
### Task 3: Configuration And Verification
**Files:**
- Modify: `src/main/resources/application.yml`
- Modify: `src/test/java/com/label/unit/ApplicationConfigTest.java`
- [x] Rename `shiro.auth.*` config to `auth.*`.
- [x] Update safe defaults and type-aliases package.
- [x] Run targeted unit tests and compile.
- [x] Run `mvn clean test` once and record any external environment blockers.
### Verification Notes
- `mvn -q "-Dtest=LabelBackendApplicationTests,ApplicationConfigTest,AuthInterceptorTest,CompanyServiceTest,OpenApiAnnotationTest" test` passed.
- `mvn -q -DskipTests compile` passed.
- `mvn clean test` compiled main/test sources and passed unit tests, then failed only because 10 Testcontainers integration tests could not find a valid Docker environment.

View File

@@ -1,528 +0,0 @@
# 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<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:
```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`