From ff3b38ab2e9fcaefb135c8e0c4476788f3070e86 Mon Sep 17 00:00:00 2001 From: wh Date: Thu, 9 Apr 2026 19:27:17 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E6=B7=BB=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E4=BC=98=E5=8C=96=E5=AE=9E=E6=96=BD=E8=AE=A1=E5=88=92?= =?UTF-8?q?=EF=BC=88deploy.md=208=20=E6=9D=A1=E9=9C=80=E6=B1=82=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plans/2026-04-09-deploy-optimization.md | 517 ++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-09-deploy-optimization.md diff --git a/docs/superpowers/plans/2026-04-09-deploy-optimization.md b/docs/superpowers/plans/2026-04-09-deploy-optimization.md new file mode 100644 index 0000000..1d68477 --- /dev/null +++ b/docs/superpowers/plans/2026-04-09-deploy-optimization.md @@ -0,0 +1,517 @@ +# 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 + + + + + + + + + + + ${LOG_PATTERN} + + + + + + ${LOG_PATH}/${APP_NAME}.log + + ${LOG_PATTERN} + + + ${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log + 60MB + 30 + 3GB + + + + + + + + + +``` + +- [ ] **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.xml(INFO 级,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 环境(检测 /.dockerenv):exec 前台运行,保持容器进程存活 +# - 裸机 / VM:nohup 后台运行,日志追加至 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 + # 裸机 / VM:nohup 后台运行 + 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.sh(Docker 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 + + dist + + zip + tar.gz + + true + + + + + src/main/scripts/start.sh + bin + 0755 + + + + + + + src/main/resources + etc + + application.yml + logback.xml + + + + + + ${project.build.directory}/libs + libs + + **/*.jar + + + + + + src/main/assembly/empty-logs + logs + + + + +``` + +- [ ] **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: 替换 `` 段落** + +将 `pom.xml` 的 `` 段(当前仅含 spring-boot-maven-plugin)替换为: + +```xml + + + + + + org.apache.maven.plugins + maven-jar-plugin + + ${project.build.directory}/libs + + + com.label.LabelBackendApplication + false + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + copy-dependencies + + ${project.build.directory}/libs + test + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + create-distribution + package + single + + + src/main/assembly/distribution.xml + + ${project.artifactId}-${project.version} + false + + + + + + + +``` + +即用上述内容完整替换 `pom.xml` 中现有的 `...` 块(原内容为含 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.info(11 文件,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.info(11 文件,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` `${project.build.directory}/libs` — 与 `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.