diff --git a/.dockerignore b/.dockerignore
index 487d98b..6d6d711 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,3 +2,7 @@ target/
.git/
.idea/
outputs/
+**/node_modules/
+**/dist/
+**/node/
+outputs.nobody-backup-*/
diff --git a/AGENTS.md b/AGENTS.md
index b35a784..e03946c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -9,7 +9,7 @@
- 核心目录:
- `src/main/java/com/svnlog/`
- `docs/`
- - SVN 预设地址:`src/main/resources/application.properties`(`svn.presets[*]`)
+ - SVN 预设地址:通过仓库管理页维护,持久化至 `outputs/repository-configs.json`
## 2. 常用命令(Build / Lint / Test / Run)
以下命令默认在仓库根目录执行。
diff --git a/Dockerfile b/Dockerfile
index d809107..7c2eb9d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,11 @@
# ============================================================
# Docker 镜像仓库加速(默认使用 docker.1ms.run 国内代理)
# 如需切换回 Docker Hub:
-# docker compose build --build-arg REGISTRY_MIRROR=docker.io/library
+# DOCKER_REGISTRY_MIRROR=docker.io/library make up
# ============================================================
ARG REGISTRY_MIRROR=docker.1ms.run/library
+# 内部/开发用途,推荐通过 make fast-up 触发快速构建
+ARG FAST_BUILD=false
# ============================================================
# Stage 1: 前端构建(Vue 3 + Vite)
@@ -14,7 +16,7 @@ WORKDIR /frontend
COPY frontend-vue/package.json frontend-vue/package-lock.json ./
-RUN npm ci
+RUN --mount=type=cache,target=/root/.npm npm ci
COPY frontend-vue/ ./
@@ -23,20 +25,20 @@ RUN npm run build
# ============================================================
# Stage 2: 后端构建(Maven + Java 8)
# ============================================================
-FROM ${REGISTRY_MIRROR}/maven:3.9.6-eclipse-temurin-8 AS builder
+FROM ${REGISTRY_MIRROR}/maven:3.9.6-eclipse-temurin-8 AS builder-base
# Maven JVM 调优:增大堆内存、启用并行
ENV MAVEN_OPTS="-Xmx2g -XX:MaxMetaspaceSize=512m -Djava.util.concurrent.ForkJoinPool.common.parallelism=4"
WORKDIR /app
-# 使用阿里云 Maven 镜像加速依赖下载(替换 Maven Central)
-COPY maven-settings.xml /root/.m2/settings.xml
+# 使用阿里云 Maven 镜像加速依赖下载(避免被 /root/.m2 缓存挂载点隐藏)
+COPY maven-settings.xml /app/maven-settings.xml
COPY pom.xml .
RUN --mount=type=cache,target=/root/.m2 \
- mvn -B -DskipTests -T 1C dependency:go-offline
+ mvn -s /app/maven-settings.xml -B -DskipTests -T 1C dependency:go-offline
COPY src ./src
@@ -44,11 +46,21 @@ COPY src ./src
# vite.config.js 中 outDir 为相对 __dirname 的路径,容器内 __dirname=/frontend
COPY --from=frontend-builder /src/main/resources/static/v2 /app/src/main/resources/static/v2
-# 前端产物已由 frontend-builder 阶段构建并 COPY 进来;
-# 此阶段不含 frontend-vue/,且离线模式无法下载 Node,必须跳过前端构建。
-# -T 1C: 按 CPU 核数并行; -o: 离线模式(依赖已缓存,跳过元数据检查)
+# 默认构建分支(不缓存 /app/target,执行 clean)
+FROM builder-base AS builder-false
RUN --mount=type=cache,target=/root/.m2 \
- mvn -B -DskipTests -T 1C -o clean package -Dskip.frontend.build=true
+ mvn -s /app/maven-settings.xml -B -DskipTests -T 1C clean package -Dskip.frontend.build=true && \
+ cp /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar /app/svn-log-tool-1.0.0-jar-with-dependencies.jar
+
+# 快速开发迭代构建分支(缓存 /app/target,不执行 clean)
+FROM builder-base AS builder-true
+RUN --mount=type=cache,target=/root/.m2 \
+ --mount=type=cache,target=/app/target \
+ mvn -s /app/maven-settings.xml -B -DskipTests -T 1C package -Dskip.frontend.build=true && \
+ cp /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar /app/svn-log-tool-1.0.0-jar-with-dependencies.jar
+
+# 根据 FAST_BUILD 的值决定最终作为 builder 的阶段
+FROM builder-${FAST_BUILD} AS builder
# ============================================================
# Stage 3: 运行镜像(最小化 JRE)
@@ -56,7 +68,7 @@ RUN --mount=type=cache,target=/root/.m2 \
FROM ${REGISTRY_MIRROR}/eclipse-temurin:8-jre-alpine
WORKDIR /app
-COPY --from=builder /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar app.jar
+COPY --from=builder /app/svn-log-tool-1.0.0-jar-with-dependencies.jar app.jar
EXPOSE 18088
diff --git a/Makefile b/Makefile
index 00d26c6..f41e6ef 100644
--- a/Makefile
+++ b/Makefile
@@ -5,14 +5,14 @@
# ============================================================
DOCKER_REGISTRY_MIRROR ?= docker.1ms.run/library
-.PHONY: up down status
+.PHONY: up down status fast-up
COMPOSE_CMD := $(shell if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then echo "docker compose"; elif command -v docker-compose >/dev/null 2>&1; then echo "docker-compose"; fi)
BUILD_ENV := DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1
up:
@if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi
- @REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) $(BUILD_ENV) $(COMPOSE_CMD) up -d --build
+ @DOCKER_REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) FAST_BUILD=false $(BUILD_ENV) $(COMPOSE_CMD) up -d --build
@echo "Application is starting at http://localhost:18088"
down:
@@ -23,3 +23,10 @@ status:
@if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi
@$(BUILD_ENV) $(COMPOSE_CMD) ps
@echo "Access URL: http://localhost:18088"
+
+fast-up:
+ @if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi
+ @echo "WARNING: fast-up is for Java incremental dev only."
+ @echo "WARNING: Use 'make up' if you changed frontend resources, or deleted/renamed Java files."
+ @DOCKER_REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) FAST_BUILD=true $(BUILD_ENV) $(COMPOSE_CMD) up -d --build
+ @echo "Application is starting at http://localhost:18088"
diff --git a/README.md b/README.md
index 986a912..d5fb52d 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,12 @@ SVN 日志抓取与 AI 工作量分析工具,统一使用 Web 工作台入口
## 常用命令
```bash
-# 一键启动(Docker,每次会重新构建镜像并打包最新代码)
+# 一键启动(Docker,每次会重新构建镜像并打包最新代码,安全默认构建)
make up
+# 快速开发迭代启动(Docker,保留 Java 编译缓存,仅适合本地 Java 增量开发)
+make fast-up
+
# 查看状态
make status
diff --git a/docker-compose.yml b/docker-compose.yml
index 094728d..dfcb417 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,9 +4,10 @@ services:
context: .
dockerfile: Dockerfile
args:
- # Docker 镜像加速(默认 Docker Hub,国内可设阿里云)
- # 使用方式: REGISTRY_MIRROR=registry.cn-hangzhou.aliyuncs.com/library docker compose build
- REGISTRY_MIRROR: ${REGISTRY_MIRROR:-docker.1ms.run/library}
+ # Docker 镜像加速(使用 DOCKER_REGISTRY_MIRROR 传递,国内可选阿里云,例如 registry.cn-hangzhou.aliyuncs.com/library,不能带 https://)
+ # 内部/开发用途,推荐通过 make fast-up 使用快速构建
+ REGISTRY_MIRROR: ${DOCKER_REGISTRY_MIRROR:-docker.1ms.run/library}
+ FAST_BUILD: ${FAST_BUILD:-false}
container_name: svn-log-tool
network_mode: host
volumes:
diff --git a/docs/README_Web.md b/docs/README_Web.md
index 437ad79..daf03cd 100644
--- a/docs/README_Web.md
+++ b/docs/README_Web.md
@@ -34,12 +34,19 @@ mvn spring-boot:run -Dspring-boot.run.mainClass=com.svnlog.web.WebApplication
http://localhost:18088
```
-## Docker 构建行为
+## Docker 构建行为与优化
-- `make up` 保持“重新构建并启动”的语义,每次都会执行一次 Maven 打包,确保容器内是最新代码。
-- Docker 构建使用 BuildKit 缓存 Maven 本地仓库;首次构建会下载依赖,后续在 `pom.xml` 未变更时会优先命中缓存,不会在每次构建时重复下载全部依赖。
-- 如果修改了 `pom.xml`、执行了 `docker builder prune`、或切换到新的 Docker 环境,依赖缓存会失效并重新下载。
-- 如果本机 Docker 未启用 BuildKit,可显式设置 `DOCKER_BUILDKIT=1` 和 `COMPOSE_DOCKER_CLI_BUILD=1` 后再执行 `make up`。
+- **Docker 镜像加速**:默认使用 `docker.1ms.run/library` 代理。如果需要切换回 Docker Hub 或使用国内其他镜像(如阿里云镜像,例如 `registry.cn-hangzhou.aliyuncs.com/library`,注意不能带 `https://`),可以通过命令行传递 `DOCKER_REGISTRY_MIRROR` 变量:
+ ```bash
+ DOCKER_REGISTRY_MIRROR=registry.cn-hangzhou.aliyuncs.com/library make up
+ ```
+- **快速开发迭代(可选 Fast Build)**:默认情况下,构建仍会执行 `mvn clean package` 以确保打包的正确性(防旧 class 或资源残留)。如果在本地频繁修改 Java 代码,可以使用 `fast-up` 实现秒级编译与构建重启。**注意:如果修改了前端静态资源,或删除/重命名了 Java 类与资源文件,应使用默认构建(`make up`),不要用 Fast Build。**
+ ```bash
+ make fast-up
+ ```
+ 该模式下,Docker 会使用 BuildKit 挂载缓存 `/app/target` 目录,并不再执行 `clean` 目标,使 Maven 能进行增量编译。
+- **依赖缓存**:Docker 构建使用 BuildKit 缓存了 Maven 本地仓库(`.m2`)与 npm 缓存(`.npm`)。在依赖文件未变更时,不会重复下载依赖包。
+- 如果本机 Docker 未启用 BuildKit,可显式设置 `DOCKER_BUILDKIT=1` 和 `COMPOSE_DOCKER_CLI_BUILD=1` 后再执行构建。
## 页面说明
@@ -78,8 +85,9 @@ http://localhost:18088
## SVN 凭据读取优先级
1. 单次请求显式传入的 `username/password`(兼容旧接口)
-2. 设置页保存的运行时 `svnUsername/svnPassword`
-3. 环境变量 `SVN_USERNAME` / `SVN_PASSWORD`
+2. 预设凭据
+3. 全局设置保存的运行时 `svnUsername/svnPassword`
+4. 环境变量 `SVN_USERNAME` / `SVN_PASSWORD`
`GET /api/settings` 不会回显 `openaiApiKey` 或 `svnPassword` 明文,前端通过 `openaiApiKeyConfigured` 和 `svnCredentialsConfigured` 展示配置状态。
@@ -105,7 +113,7 @@ http://localhost:18088
## SVN 预设来源与调用方式
-- SVN 地址统一维护在 `application.properties` 的 `svn.presets[*]` 中。
+- SVN 地址统一通过仓库管理页维护,并持久化到 `outputs/repository-configs.json` 文件中。
- 前端不再传 SVN URL,业务接口统一传 `presetId`,后端按 `presetId` 解析地址。
- `GET /api/svn/presets` 仅返回 `id` 与 `name`(不返回 `url`)。
diff --git a/frontend-vue/src/components/AppSidebar.vue b/frontend-vue/src/components/AppSidebar.vue
index 367ade4..c758707 100644
--- a/frontend-vue/src/components/AppSidebar.vue
+++ b/frontend-vue/src/components/AppSidebar.vue
@@ -14,7 +14,11 @@
+