@cjmalloy/jasper
Jasper Knowledge Management Server
Install
agr install @cjmalloy/jasper --target copilotWrites 1 file into .github/copilot-instructions.md, pinned to git-789b837f.
- .github/copilot-instructions.md
Document
Jasper Knowledge Management Server
ALWAYS follow these instructions and only fall back to additional search and context gathering if the information in these instructions is incomplete or found to be in error.
Working Effectively
Bootstrap, build, and test the repository:
⚠️ CRITICAL: Java Version Requirement
This project uses Spring Boot 4.1.0 and targets Java 25. Use Java 25 for all normal builds; Java 21 is the minimum supported fallback and requires overriding java.version.
Java 25 is now available in the build environment!
Recommended Approach - Use Java 25 Directly:
-
Set JAVA_HOME to Java 25:
export JAVA_HOME=/usr/lib/jvm/temurin-25-jdk-amd64 export PATH=$JAVA_HOME/bin:$PATH -
Build and test:
./mvnw clean compile # or ./mvnw clean package
Alternative - Docker Build:
- Docker Build:
docker build -t jasper .- ⚠️ Known Issue: Docker builds may fail with certificate errors (PKIX path building failed) in some environments due to the Java truststore in the Docker base image. This does not affect GitHub Actions CI.
- Workaround: Use local build with Java 25 instead
Quick Decision Guide
| Your Situation | Build Approach | Steps |
|---|---|---|
| Most common (Java 25 available) | Use Java 25 directly (RECOMMENDED) | 1. export JAVA_HOME=/usr/lib/jvm/temurin-25-jdk-amd642. export PATH=$JAVA_HOME/bin:$PATH3. ./mvnw clean package |
| Docker available | Use Docker (may have PKIX cert issues locally) | docker build -t jasper . |
| Java 21 available (fallback) | Use Java 21 with version override | export JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64 then build with -Djava.version=21 |
Local Development with Java 25 (RECOMMENDED):
- Set JAVA_HOME:
export JAVA_HOME=/usr/lib/jvm/temurin-25-jdk-amd64 - Add to PATH:
export PATH=$JAVA_HOME/bin:$PATH - Install Bun for JavaScript tests:
curl -fsSL https://bun.sh/install | bash && export PATH="$HOME/.bun/bin:$PATH" - Clean build:
./mvnw clean compile-- takes 11 seconds. NEVER CANCEL. Set timeout to 30+ seconds. - Full build with tests:
./mvnw clean package-- takes 85 seconds. NEVER CANCEL. Set timeout to 180+ seconds. - Skip tests build:
./mvnw clean package -DskipTests-- takes 15 seconds. NEVER CANCEL. Set timeout to 30+ seconds.
Docker-Based Build (Alternative):
- Build with Docker:
docker build -t jasper .-- takes ~2 minutes. NEVER CANCEL. Set timeout to 600+ seconds. - Build builder stage only:
docker build --target builder -t jasper-builder .-- takes ~2 minutes. Set timeout to 600+ seconds. - Build test stage:
docker build --target test -t jasper-test .-- takes ~5 minutes. Set timeout to 600+ seconds. - Run tests in Docker:
docker run --rm jasper-test-- executes test suite in container - Efficient log reading: Pipe output through
tail -100ortee build.logto efficiently read Docker build logs - ⚠️ Known Issue: Docker builds may fail with certificate errors (PKIX path building failed) in some local environments. This is caused by the Java truststore in the Docker base image not trusting Maven Central certificates. The
--network=hostflag does NOT fix this. Use local Java 25 Maven build instead if this occurs.
Fallback - Use Java 21 (if Java 25 not available):
- Install Java 21:
sudo apt-get update && sudo apt-get install -y openjdk-21-jdk - Set JAVA_HOME:
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64(or/usr/lib/jvm/temurin-21-jdk-amd64if using Temurin) - Add to PATH:
export PATH=$JAVA_HOME/bin:$PATH - Important: Since pom.xml targets Java 25, you must add
-Djava.version=21to all Maven commands. Example:./mvnw clean compile -Djava.version=21
Running the Application
ALWAYS run the bootstrapping steps first.
Docker Compose (Recommended for Development):
- Full stack:
docker compose up-- starts web app, database, and Redis - Supporting services only:
docker compose up db redis -d-- background database and cache for local development
Local Development:
- Start supporting services:
docker compose up db redis -d - Run application:
SPRING_PROFILES_ACTIVE=dev SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/jasper SPRING_DATASOURCE_USERNAME=jasper SPRING_DATASOURCE_PASSWORD=jasper ./mvnw spring-boot:run - Application starts on port 8081 (takes ~22 seconds to start)
- Health check:
curl http://localhost:8081/management/health
Production Build:
- Build Docker image:
docker build -t jasper .-- takes ~2 minutes. NEVER CANCEL. Set timeout to 600+ seconds. - Test Docker build:
docker build --target test -t jasper-test .-- takes ~5 minutes. NEVER CANCEL. Set timeout to 600+ seconds.
Testing
Unit and Integration Tests:
- Local SQLite (Recommended):
./mvnw test -Dspring.profiles.active=test,sqlite,scripts-- runs without PostgreSQL or Docker. NEVER CANCEL. Set timeout to 180+ seconds. - Local PostgreSQL/Testcontainers:
./mvnw test-- requires Docker. NEVER CANCEL. Set timeout to 180+ seconds. - Docker-based PostgreSQL:
docker build --target test -t jasper-test . && docker run --rm -v /var/run/docker.sock:/var/run/docker.sock jasper-test-- takes ~5 minutes. NEVER CANCEL. Set timeout to 600+ seconds. - The Docker-based test command mounts the local Docker socket so Testcontainers can start PostgreSQL; only run it with trusted images in a trusted local environment.
- Note: Some tests require Bun and Python dependencies to pass completely
- Test failures related to missing
/home/runner/.bun/bin/bunare expected without Bun installation
Efficient Log Reading with Docker: When building with Docker, use these techniques to efficiently read logs:
- Tail output:
docker build -t jasper . 2>&1 | tail -100-- shows last 100 lines - Save to file:
docker build -t jasper . 2>&1 | tee build.log-- saves full log while showing output - Progress mode:
docker build --progress=plain -t jasper .-- shows all build output without fancy formatting
Load Testing with Gatling:
- Navigate to gatling directory:
cd gatling - PostgreSQL load tests:
docker compose --profile lt up --build --exit-code-from gatling-- NEVER CANCEL. Set timeout to 180+ seconds. - SQLite load tests:
docker compose -f docker-compose.sqlite.yaml --profile lt up --build --exit-code-from gatling-- NEVER CANCEL. Set timeout to 180+ seconds. - Docker supported tests:
docker compose up -d; ../mvnw gatling:test - Run a specific test using the
GATLING_TESTenvironment variable:GATLING_TEST=SmokeTest docker compose --profile lt up --build --exit-code-from gatling- Available tests:
SmokeTest,Comprehensive,UserJourney,StressTest,Inferno - Default test (if not specified):
SmokeTest
- Available tests:
- When adding new Gatling simulations: ALWAYS update
.github/workflows/gatling.ymlto include the new test in the CI pipeline. Add a new step following the pattern of existing tests (e.g.,GATLING_TEST=YourNewTest)
GitHub Actions Integration:
- Build/test workflow:
.github/workflows/test.ymlbuilds the Docker image and runs tests against PostgreSQL and SQLite - Load test workflow:
.github/workflows/gatling.ymlruns every Gatling simulation against PostgreSQL and SQLite - CodeQL analysis:
.github/workflows/codeql.ymlruns static security analysis - Docker publish:
.github/workflows/publish.ymlbuilds and publishes Docker images to GHCR - Release:
.github/workflows/release.ymlcreates draft GitHub releases with JAR artifacts - GitHub Pages:
.github/workflows/pages.ymldeploys test reports and documentation - Cleanup:
.github/workflows/cleanup.ymlremoves stale PR caches and artifacts - Build and test workflows run on push to master and pull requests
Validation
ALWAYS manually validate any new code by running through complete end-to-end scenarios after making changes.
Required Validation Steps:
- Start supporting services:
docker compose up -d - Test health endpoint:
curl http://localhost:8081/management/health(should return{"status":"UP"}) - Test API endpoint:
curl http://localhost:8081/api/v1/ref/page(should return JSON with empty content array) - Run tests with dependencies: Install Bun and Python, then run both PostgreSQL (
./mvnw test) and SQLite (./mvnw test -Dspring.profiles.active=test,sqlite,scripts) suites for complete validation; the SQLite suite is the minimum for changes unrelated to database behavior - Clean up:
docker compose down
Key Application Features to Test:
- RESTful API for knowledge management (Refs, Extensions, Users, Plugins, Templates)
- Tag-based access control system
- Real-time updates via WebSocket
- Plugin system for extensibility
- Backup/restore functionality
- Multi-tenant operation support
CI Validation:
- Always ensure GitHub Actions pass before merging
- Check test reports in GitHub Actions artifacts
- Verify both unit tests and Gatling load tests complete successfully
Common Tasks
Development Workflow:
- Make code changes
- Quick validation (local):
./mvnw clean compile-- validates compilation in ~11 seconds - Run specific test class (local):
./mvnw test -Dtest=YourTestClass - Run application for manual testing: See "Running the Application" section
- Full test suite before committing:
./mvnw clean package-- ~85 seconds (or Docker:docker build --target test -t jasper-test . && docker run --rm jasper-test)
Troubleshooting:
Most Common Error: "release version 25 not supported" or "release version 21 not supported"
- Cause: Java 25 (or Java 21+) is not in your PATH or JAVA_HOME is not set
- Working Solution (tested): Set JAVA_HOME to Java 25:
export JAVA_HOME=/usr/lib/jvm/temurin-25-jdk-amd64export PATH=$JAVA_HOME/bin:$PATH- Verify:
java -version(should show Java 25) - Build:
./mvnw clean package
- Fallback (if Java 25 not available): Use Java 21:
sudo apt-get update && sudo apt-get install -y openjdk-21-jdkexport JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64export PATH=$JAVA_HOME/bin:$PATH- Build:
./mvnw clean package -Djava.version=21(the-Djava.version=21flag is required since pom.xml targets Java 25)
- Why not change to Java 17?: This project supports Java 21 or newer and targets Java 25 - changing pom.xml to Java 17 will not work
- Alternative: Use Docker build
docker build -t jasper .(but may have PKIX certificate issues in some environments)
- Alternative: Use Docker build
Other Common Issues:
- Docker certificate error ("PKIX path building failed"): This is caused by the Java truststore in the Docker base image not trusting Maven Central certificates. The
--network=hostflag does NOT fix this. Use local Java 25 Maven build instead (see above). Note: This issue does not affect GitHub Actions CI. - If JavaScript tests fail: Install Bun with
curl -fsSL https://bun.sh/install | bashOR use Docker build - If Python tests fail: Ensure Python 3 is installed (
sudo apt install python3 python3-pip) OR use Docker build - If database connection fails: Ensure PostgreSQL container is running (
docker compose up db -d) - If Maven hangs: Check network connectivity for dependency downloads. First Maven build downloads many dependencies which can take 5-10 minutes. Subsequent builds are faster (~11-85 seconds depending on scope).
- If Docker build fails: Ensure Docker has enough disk space (
docker system prune -ato clean up)
Performance Notes:
- NEVER CANCEL builds or tests
- Compilation alone: ~11 seconds (local, cached) or ~2-5 minutes (Docker with dependencies)
- Full test suite: ~85 seconds (local) or ~5 minutes (Docker)
- Docker build (all stages): ~2 minutes
- Docker build (builder stage only): ~2 minutes
- Gatling load tests: ~27 seconds
- Application startup: ~22 seconds
Repository Structure
jasper/
├── .github/workflows/ # GitHub Actions CI/CD pipelines
├── .m2/settings.xml # Maven settings (minimal)
├── docker/ # Docker configuration files
├── gatling/ # Load testing module (separate Maven project)
│ ├── docker-compose.yaml # Load test environment
│ ├── docker-compose.sqlite.yaml # SQLite load test environment
│ └── src/test/java/simulations/ # Gatling test scenarios
├── src/main/java/jasper/ # Main application source
│ ├── aop/ # Aspect-oriented programming
│ ├── client/ # External service clients
│ ├── component/ # Business logic components
│ ├── config/ # Spring configuration
│ ├── domain/ # JPA entities
│ ├── errors/ # Error handling
│ ├── management/ # Management endpoints
│ ├── plugin/ # Plugin system
│ ├── repository/ # Data access layer
│ ├── security/ # Authentication and authorization
│ ├── service/ # Service layer
│ ├── util/ # Utility classes
│ └── web/ # REST controllers
├── src/main/resources/ # Configuration and static resources
│ └── config/application-sqlite.yml # SQLite runtime profile
├── src/test/java/ # Unit and integration tests
├── docker-compose.yaml # Development environment
├── Dockerfile # Multi-stage production build
└── pom.xml # Maven configuration
Key Files:
src/main/java/jasper/JasperApplication.java- Main Spring Boot applicationsrc/main/java/jasper/domain/- Core entities (Ref, Ext, User, Plugin, Template)src/main/java/jasper/security/Auth.java- Tag-based access control implementationsrc/main/java/jasper/web/rest/- REST API controllerssrc/main/resources/config/application.yml- Main application configurationdocker-compose.yaml- Local development stack.github/workflows/test.yml- Main CI pipeline
Important Dependencies:
- Spring Boot 4.1.0 (Web MVC, JPA, Security, WebSocket, Actuator)
- Spring Cloud 2025.1.2 (OpenFeign, Resilience4j, Kubernetes)
- Java 25 (build target; Java 21 is the supported fallback with
-Djava.version=21) - PostgreSQL 18 (primary development database)
- SQLite JDBC 3.53.2.0 (embedded runtime and test database)
- Redis (caching and messaging via Spring Integration)
- Liquibase (database migrations)
- Caffeine (local caching)
- Bun 1.3.14 (JavaScript runtime in Docker images)
- Gatling 3.15.1 (load testing)
- Testcontainers 2.0.5 (integration testing)
Code Style Guidelines
Logging:
- All origin-specific log messages must prefix the message with the origin:
logger.info("{} Message", origin, ...) - The first placeholder
{}should always be for the origin in multi-tenant operations - Example:
logger.debug("{} Creating bulkhead with {} permits", origin, maxConcurrent) - This ensures consistent log filtering and debugging in multi-tenant environments
Locality:
- Keep a readable single-use expression at its call site instead of extracting it into a temporary variable
- Treat
src/main/java/jasper/security/Auth.javaas the authoritative security specification; avoid cosmetic refactors that reduce locality or obscure authorization decisions
Code Drift Check
When a branch already contains more than one commit, ALWAYS check for code drift before finishing. Code drift happens when a change is made and then undone in a later commit, but an irrelevant edit remains (e.g., leftover imports, renamed variables, reordered code, whitespace changes, or stray helper code from the reverted change). To check for drift:
- Diff the full branch against the merge base (e.g.,
git diff $(git merge-base HEAD origin/master)) - Review every hunk and confirm it is required by the task; remove any edits that no longer serve a purpose
Always reference this documentation when working with the Jasper codebase to ensure consistency and avoid common pitfalls.
Trust
Not scanned yet. Artifacts are graded after they are crawled, so a recently discovered one may have no result for a while.
Versions
git-789b837fcc582026-08-04