diff --git a/.claude/rules/cicd.md b/.claude/rules/cicd.md
index 98c83942..176d7e3b 100644
--- a/.claude/rules/cicd.md
+++ b/.claude/rules/cicd.md
@@ -8,8 +8,11 @@ paths:
# CI/CD & Deployment
-- CI workflow: `.gitea/workflows/ci.yml` — build -> docker -> deploy on push to main or feature branches
+- CI workflow: `.gitea/workflows/ci.yml` — build -> docker -> deploy on push to main or feature branches. `paths-ignore` skips the whole pipeline for docs-only / `.planning/` / `.claude/` / `*.md` changes (push and PR triggers).
- Build step skips integration tests (`-DskipITs`) — Testcontainers needs Docker daemon
+- Build caches (parallel `actions/cache@v4` steps in the `build` job): `~/.m2/repository` (key on all `pom.xml`), `~/.npm` (key on `ui/package-lock.json`), `ui/node_modules/.vite` (key on `ui/package-lock.json` + `ui/vite.config.ts`). UI install uses `npm ci --prefer-offline --no-audit --fund=false` so the npm cache is the primary source.
+- Maven build performance (set in `pom.xml` and `cameleer-server-app/pom.xml`): `useIncrementalCompilation=true` on the compiler plugin; Surefire uses `forkCount=1C` + `reuseForks=true` (one JVM per CPU core, reused across test classes); Failsafe keeps `forkCount=1` + `reuseForks=true`. Unit tests must not rely on per-class JVM isolation.
+- UI build script (`ui/package.json`): `build` is `vite build` only — the type-check pass was split out into `npm run typecheck` (run separately when you want a full `tsc --noEmit` sweep).
- Docker: multi-stage build (`Dockerfile`), `$BUILDPLATFORM` for native Maven on ARM64 runner, amd64 runtime. `docker-entrypoint.sh` imports `/certs/ca.pem` into JVM truststore before starting the app (supports custom CAs for OIDC discovery without `CAMELEER_SERVER_SECURITY_OIDCTLSSKIPVERIFY`).
- `REGISTRY_TOKEN` build arg required for `cameleer-common` dependency resolution
- Registry: `gitea.siegeln.net/cameleer/cameleer-server` (container images)
diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index d48f1759..d88e43fa 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -5,8 +5,20 @@ on:
branches: [main, 'feature/**', 'fix/**', 'feat/**']
tags-ignore:
- 'v*'
+ paths-ignore:
+ - '.planning/**'
+ - 'docs/**'
+ - '**/*.md'
+ - '.claude/**'
+ - 'AGENTS.md'
+ - 'CLAUDE.md'
pull_request:
branches: [main]
+ paths-ignore:
+ - '.planning/**'
+ - 'docs/**'
+ - '**/*.md'
+ - '.claude/**'
delete:
jobs:
@@ -45,11 +57,25 @@ jobs:
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
+ - name: Cache npm registry
+ uses: actions/cache@v4
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-npm-${{ hashFiles('ui/package-lock.json') }}
+ restore-keys: ${{ runner.os }}-npm-
+
+ - name: Cache Vite build artifacts
+ uses: actions/cache@v4
+ with:
+ path: ui/node_modules/.vite
+ key: ${{ runner.os }}-vite-${{ hashFiles('ui/package-lock.json', 'ui/vite.config.ts') }}
+ restore-keys: ${{ runner.os }}-vite-
+
- name: Build UI
working-directory: ui
run: |
echo '//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}' >> .npmrc
- npm ci
+ npm ci --prefer-offline --no-audit --fund=false
npm run build
env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
diff --git a/AGENTS.md b/AGENTS.md
index 422e41d2..9a819b3c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,7 +1,7 @@
# GitNexus — Code Intelligence
-This project is indexed by GitNexus as **cameleer-server** (9318 symbols, 23997 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
+This project is indexed by GitNexus as **cameleer-server** (9321 symbols, 24004 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
diff --git a/CLAUDE.md b/CLAUDE.md
index 88a2f756..1f95916d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -22,8 +22,19 @@ Cameleer Server — observability server that receives, stores, and serves Camel
```bash
mvn clean compile # Compile all modules
mvn clean verify # Full build with tests
+mvn clean verify -DskipITs # Fast: unit tests only (no Testcontainers)
```
+### Faster local builds
+
+- **Surefire reuses forks** (`cameleer-server-app/pom.xml`): unit tests run with `forkCount=1C` + `reuseForks=true` — one JVM per CPU core, reused across classes. Test classes that mutate static state must clean up after themselves.
+- **Testcontainers reuse** — opt-in per developer. Add to `~/.testcontainers.properties`:
+ ```
+ testcontainers.reuse.enable=true
+ ```
+ Then `AbstractPostgresIT` containers persist across `mvn verify` runs (saves ~20s per run). Stop them manually when you need a clean DB: `docker rm -f $(docker ps -aq --filter label=org.testcontainers.reuse=true)`.
+- **UI build** dropped redundant `tsc --noEmit` from `npm run build` (Vite/esbuild type-checks during bundling). Run `npm run typecheck` explicitly when you want a full type-check pass.
+
## Run
```bash
@@ -85,7 +96,7 @@ When adding, removing, or renaming classes, controllers, endpoints, UI component
# GitNexus — Code Intelligence
-This project is indexed by GitNexus as **cameleer-server** (9318 symbols, 23997 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
+This project is indexed by GitNexus as **cameleer-server** (9321 symbols, 24004 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
diff --git a/cameleer-server-app/pom.xml b/cameleer-server-app/pom.xml
index 4c10c5d8..d80a01e8 100644
--- a/cameleer-server-app/pom.xml
+++ b/cameleer-server-app/pom.xml
@@ -189,8 +189,8 @@
org.apache.maven.plugins
maven-surefire-plugin
- 1
- false
+ 1C
+ true
diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractPostgresIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractPostgresIT.java
index e3596e81..8d897e5a 100644
--- a/cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractPostgresIT.java
+++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractPostgresIT.java
@@ -21,10 +21,12 @@ public abstract class AbstractPostgresIT {
postgres = new PostgreSQLContainer<>("postgres:16")
.withDatabaseName("cameleer")
.withUsername("cameleer")
- .withPassword("test");
+ .withPassword("test")
+ .withReuse(true);
postgres.start();
- clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12");
+ clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12")
+ .withReuse(true);
clickhouse.start();
}
diff --git a/pom.xml b/pom.xml
index 0a970dac..9562c50a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,7 @@
${java.version}
${java.version}
+ true
diff --git a/ui/package.json b/ui/package.json
index 5b8c06e2..7562a945 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -7,7 +7,8 @@
"dev": "vite",
"dev:local": "cross-env VITE_API_TARGET=http://localhost:8081 vite",
"dev:remote": "cross-env VITE_API_TARGET=http://192.168.50.86:30090 vite",
- "build": "tsc -p tsconfig.app.json --noEmit && vite build",
+ "build": "vite build",
+ "typecheck": "tsc -p tsconfig.app.json --noEmit",
"lint": "eslint .",
"preview": "vite preview",
"generate-api": "openapi-typescript src/api/openapi.json -o src/api/schema.d.ts",