Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
6095599
refactor(domain): extract SearchQualityLevel enum with self-describin…
WilliamAGH Jan 25, 2026
eb5ce13
refactor(guided-learning): extract PdfCitationEnhancer and add lesson…
WilliamAGH Jan 25, 2026
1b00b40
feat(guided-learning): scope sessions per lesson to prevent conversat…
WilliamAGH Jan 25, 2026
94f2759
test(SearchQualityLevel): add unit tests and update controller for Op…
WilliamAGH Jan 25, 2026
f4d228b
docs: extract monolithic README into focused documentation files
WilliamAGH Jan 25, 2026
9d993c3
fix(domain): extract SUBSTANTIAL_CONTENT_THRESHOLD constant and dedup…
WilliamAGH Jan 25, 2026
cb226a4
fix(support): add UncheckedIOException to Javadoc, warn on size misma…
WilliamAGH Jan 25, 2026
17d3c2d
fix(web): add @ExceptionHandler for IllegalArgumentException to retur…
WilliamAGH Jan 25, 2026
f4d91b9
feat(domain): add RetrievedContent interface for framework-free domai…
WilliamAGH Jan 25, 2026
97d1853
feat(support): add DocumentContentAdapter to bridge Spring AI Documen…
WilliamAGH Jan 25, 2026
f9f851a
refactor(domain): remove Spring framework import, use RetrievedConten…
WilliamAGH Jan 25, 2026
975247a
refactor(service): use DocumentContentAdapter when calling SearchQual…
WilliamAGH Jan 25, 2026
97d4540
test(domain): update SearchQualityLevelTest to use DocumentContentAda…
WilliamAGH Jan 25, 2026
0def47c
refactor(web): extract helper methods to reduce method complexity in …
WilliamAGH Jan 25, 2026
5c0f0b4
docs(config): clarify no auto-fallback between LLM providers per LM2
WilliamAGH Jan 25, 2026
073f924
docs(readme): document JTokkit CL100K_BASE tokenizer for chunking
WilliamAGH Jan 25, 2026
2d80fdc
fix(support): guard page anchor estimation to Think Java PDF only
WilliamAGH Jan 25, 2026
51ec645
feat(guided): stream citations for guided lesson chat responses
WilliamAGH Jan 25, 2026
cd3fc85
fix(frontend): strip inline citation markers from rendered markdown
WilliamAGH Jan 25, 2026
33525bb
test(web): verify guided chat stream emits citation SSE event
WilliamAGH Jan 25, 2026
24f91ca
refactor(domain): use Optional returns and typed accessors in Retriev…
WilliamAGH Jan 25, 2026
51518d7
feat(frontend): add stable message IDs for Svelte list keying
WilliamAGH Jan 25, 2026
50a434f
feat(frontend): clear backend session when user clears chat
WilliamAGH Jan 25, 2026
61afd58
docs(service): add @throws IllegalArgumentException to GuidedChatProm…
WilliamAGH Jan 25, 2026
479bf8d
fix(test): improve GuidedSseCitationEventTest reliability and clarity
WilliamAGH Jan 25, 2026
04a40b5
fix(scripts): support local Qdrant without API key and custom REST port
WilliamAGH Jan 25, 2026
bf2a20e
fix(config): allow GITHUB_TOKEN or OPENAI_API_KEY for LLM provider
WilliamAGH Jan 25, 2026
4f0e472
chore: add LICENSE and CONTRIBUTING.md, improve test clarity
WilliamAGH Jan 25, 2026
cce3de9
refactor(frontend): remove streamingContent from composable, add abor…
WilliamAGH Jan 25, 2026
eb1bcc6
fix(frontend): defer syntax highlighting until stream completes
WilliamAGH Jan 25, 2026
f71db26
refactor(frontend): extract GuidedLessonChatPanel from LearnView
WilliamAGH Jan 25, 2026
d6d9e53
refactor(domain): inline message templates in SearchQualityLevel
WilliamAGH Jan 25, 2026
fe989e6
fix: use platform-independent line separators and improve test assert…
WilliamAGH Jan 25, 2026
8d29f30
test(frontend): simplify stream completion callback initialization
WilliamAGH Jan 25, 2026
f2d83cd
fix(config): correct Qdrant GHCR image path and reduce log verbosity
WilliamAGH Jan 25, 2026
34733c6
test(frontend): add SSE abort signal handling tests
WilliamAGH Jan 25, 2026
76205cc
build: add deterministic Java toolchain with Temurin and CI workflow
WilliamAGH Jan 25, 2026
386f959
style(frontend): normalize LearnView indentation to spaces
WilliamAGH Jan 25, 2026
2e80bf9
fix(build): align all Java version references to 25
WilliamAGH Jan 25, 2026
594c43a
fix(build): migrate from deprecated AdoptOpenJDK to Adoptium vendor spec
WilliamAGH Jan 25, 2026
a0a0f44
fix(spotbugs): return immutable snapshots from records to satisfy EI_…
WilliamAGH Jan 25, 2026
62151fb
build(java): add Spotless and Palantir Java formatting
WilliamAGH Jan 25, 2026
6bbe5a7
docs: update development guide to reflect actual build configuration
WilliamAGH Jan 25, 2026
b7e0ea7
a11y(frontend): add aria-labels to clear chat buttons for screen readers
WilliamAGH Jan 25, 2026
feff5b3
style(frontend): normalize LearnView indentation and fix floating pro…
WilliamAGH Jan 25, 2026
e2cfa52
test(frontend): improve SSE test reliability and add clear chat abort…
WilliamAGH Jan 25, 2026
db294f1
refactor(java): remove sensitive data from log statements
WilliamAGH Jan 25, 2026
61d49c7
refactor(java): remove redundant null checks per framework contracts
WilliamAGH Jan 25, 2026
5bb592b
refactor(frontend): remove inline citation marker stripping from mark…
WilliamAGH Jan 25, 2026
1250e7b
fix(build): configure Palantir formatter inside Spotless block
WilliamAGH Jan 25, 2026
9ef97f6
style(java): apply Palantir Java formatting across codebase
WilliamAGH Jan 25, 2026
a140f4a
fix(docs): correct mise URLs and add language tag to code block
WilliamAGH Jan 26, 2026
ab974f7
fix(docs): update Java version reference to 25
WilliamAGH Jan 26, 2026
a34571a
fix(docs): replace bold section headers with markdown headings in README
WilliamAGH Jan 26, 2026
4f4d045
fix(scripts): fix exit code masking and port handling in monitor_inde…
WilliamAGH Jan 26, 2026
af572b2
fix(scripts): ensure HTTPS Qdrant URL includes REST port in monitor_p…
WilliamAGH Jan 26, 2026
575a997
refactor(domain): extract prompt templates and keywords to constants …
WilliamAGH Jan 26, 2026
a558520
fix(build): support OPENAI_API_KEY in Makefile run and dev targets
WilliamAGH Jan 26, 2026
3146d57
refactor(service): inject RestTemplateBuilder in AuditService instead…
WilliamAGH Jan 26, 2026
8299e8a
fix(service): replace printf-style formatting in SLF4J log call
WilliamAGH Jan 26, 2026
1e58e01
fix(service): log full exception stack trace in GuidedTOCProvider
WilliamAGH Jan 26, 2026
2ba2ee3
security(web): restrict ErrorTestController to non-prod profiles
WilliamAGH Jan 26, 2026
53820f4
fix(test): enhance portability and safety in ExtractorQualityTest
WilliamAGH Jan 26, 2026
7d409c7
fix(test): enhance portability in StandaloneExtractionTest
WilliamAGH Jan 26, 2026
aeaaab9
fix(service): fail fast on guided TOC load failure to prevent silent …
WilliamAGH Jan 26, 2026
d6f30d3
style: apply spotless formatting to java sources
WilliamAGH Jan 26, 2026
57785fd
fix(docs): correct mise URL typo from jdnow to jdx
WilliamAGH Jan 26, 2026
db80e93
fix(GuidedTOCProvider): set tocLoaded only on success to preserve fai…
WilliamAGH Jan 26, 2026
6e940f7
fix(Makefile): add OPENAI_API_KEY fallback to dev-backend target
WilliamAGH Jan 26, 2026
50a1106
fix: pass OPENAI_API_KEY to run args
WilliamAGH Jan 26, 2026
34948de
chore: add all target for checkmake compliance
WilliamAGH Jan 26, 2026
bdb9a0d
docs: fix java -version grep to read stderr
WilliamAGH Jan 26, 2026
4883ad5
test: assert SEO metadata via DOM selectors
WilliamAGH Jan 26, 2026
5b10218
chore(ci): bump upload-artifact to v6
WilliamAGH Jan 26, 2026
d283bc6
test: add static index fixture for SeoControllerTest
WilliamAGH Jan 26, 2026
03d0327
chore: add prek hook config and install helper
WilliamAGH Jan 26, 2026
700af9d
style(test): reflow SeoControllerTest assertions
WilliamAGH Jan 26, 2026
ef3dd43
chore(dev): auto-format Java on pre-commit
WilliamAGH Jan 26, 2026
3099b2c
chore: improve dev tooling docs and guards
WilliamAGH Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
# Java Chat Application Environment Variables
# Java Chat environment variables
#
# Copy to .env:
# cp .env.example .env

# Environment Configuration
# Set to 'prod' for production (hides API key details in logs)
# Set to 'dev' for development (shows last 4 chars of API keys in logs)
SPRING_PROFILE=dev

# API Keys (Choose one of the following)
# Option 1: GitHub Models (Free tier available)
GITHUB_TOKEN=your_github_personal_access_token

# Option 2: OpenAI API
OPENAI_API_KEY=your_openai_api_key

# Optional: Override default model
OPENAI_MODEL=gpt-4o-mini

# Optional: Override base URL for API
# For GitHub Models: https://models.github.ai/inference
# For OpenAI: https://api.openai.com
OPENAI_BASE_URL=https://models.github.ai/inference

# Server Configuration
PORT=8085

# LLM providers (set one or both)
#
# GitHub Models (free tier available)
GITHUB_TOKEN=
# Optional overrides (used by Makefile + streaming SDK)
GITHUB_MODELS_BASE_URL=https://models.github.ai/inference
GITHUB_MODELS_CHAT_MODEL=gpt-5
#
# OpenAI (optional: can be used as primary or fallback)
OPENAI_API_KEY=
# For OpenAI: https://api.openai.com
OPENAI_BASE_URL=https://api.openai.com
OPENAI_MODEL=gpt-5.2
# OPENAI_REASONING_EFFORT=high

# Local Embedding Server (if you have one running)
APP_LOCAL_EMBEDDING_ENABLED=false
LOCAL_EMBEDDING_SERVER_URL=http://127.0.0.1:8088
APP_LOCAL_EMBEDDING_MODEL=text-embedding-qwen3-embedding-8b
APP_LOCAL_EMBEDDING_DIMENSIONS=4096
APP_LOCAL_EMBEDDING_USE_HASH_WHEN_DISABLED=true

# Qdrant Vector Database (if using)
# Qdrant Vector Database (local docker-compose defaults)
QDRANT_HOST=localhost
QDRANT_PORT=8086
QDRANT_SSL=false
QDRANT_PORT=8086 # gRPC (app)
QDRANT_REST_PORT=8087 # REST (scripts/monitors)
QDRANT_COLLECTION=java-chat
QDRANT_API_KEY=

# RAG Configuration
RAG_CHUNK_MAX_TOKENS=900
RAG_CHUNK_OVERLAP_TOKENS=150
RAG_TOP_K=12
RAG_RETURN_K=6
RAG_CITATIONS_K=3
RAG_CITATIONS_K=3
70 changes: 70 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Build & Test

on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev

jobs:
build:
runs-on: ubuntu-24.04

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up Temurin JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 25
cache: gradle

- name: Log system & Java info (drift detection)
run: |
echo "=== Environment Info ==="
uname -a
echo "=== Java Version ==="
java -version
echo "=== Gradle Version ==="
./gradlew --version

- name: Run tests
run: ./gradlew test --no-daemon

- name: Build application
run: ./gradlew build -x test --no-daemon

- name: Run static analysis
run: ./gradlew spotbugsMain pmdMain --no-daemon

- name: Upload test reports on failure
if: failure()
uses: actions/upload-artifact@v6
with:
name: test-results
path: build/test-results/
retention-days: 7

- name: Upload SpotBugs report on failure
if: failure()
uses: actions/upload-artifact@v6
with:
name: spotbugs-report
path: build/reports/spotbugs/
retention-days: 7

- name: Upload PMD report on failure
if: failure()
uses: actions/upload-artifact@v6
with:
name: pmd-report
path: build/reports/pmd/
retention-days: 7
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ build/
frontend/node_modules/
frontend/.svelte-kit/

# Local scratchpad (non-source artifacts)
tmp/

# Built frontend assets (generated by npm run build)
# Favicons in static/ are source files and should be committed
src/main/resources/static/index.html
Expand Down
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
repos:
- repo: local
hooks:
- id: spotless-java
name: Spotless Java (Gradle, auto-format)
entry: ./gradlew spotlessApply --no-daemon
language: system
pass_filenames: false
- id: frontend-check
name: Frontend check (Vite/Svelte)
entry: bash -lc "cd frontend && npm run check"
language: system
pass_filenames: false
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
java = temurin 25
41 changes: 41 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Contributing to Java Chat

Feedback and contributions are welcome. If you find a bug or want a feature, please open an issue in this repository.

## Getting started

1) Fork the repository
2) Clone your fork
3) Create a feature branch
4) Make your changes
5) Run checks locally:

```bash
make test
make build
make lint
```

6) Commit with a descriptive message
7) Push your branch and open a Pull Request

## Guidelines

- Use the deterministic toolchain: Gradle Wrapper + Gradle Toolchains + Temurin.
- Local Java is managed by mise/asdf via `.tool-versions` (see below). The CI uses the same vendor.
- We pin major Java version in Gradle toolchain and CI; patch is logged in CI and bumped intentionally.

- Keep PRs focused (one change per PR when possible).
- Add tests for new behavior.
- Update docs when you change workflows or endpoints.
- Don’t commit secrets (use `.env`, and keep `.env.example` up to date).

## Reporting issues

When reporting an issue, please include:

- Clear description of the problem
- Steps to reproduce
- Expected vs actual behavior
- OS, Java version, and how you’re running the app (`make dev`, `make run`, etc.)

4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ RUN npm run build
# ================================
# BACKEND BUILD STAGE
# ================================
FROM public.ecr.aws/docker/library/eclipse-temurin:21-jdk AS builder
FROM public.ecr.aws/docker/library/eclipse-temurin:25-jdk AS builder
WORKDIR /app

# Copy Gradle wrapper, build files, and static analysis configs
Expand All @@ -51,7 +51,7 @@ RUN ./gradlew clean build -x test --no-daemon && \
# ================================
# RUNTIME STAGE
# ================================
FROM public.ecr.aws/docker/library/eclipse-temurin:21-jre AS runtime
FROM public.ecr.aws/docker/library/eclipse-temurin:25-jre AS runtime

# Install curl for health check
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
Expand Down
9 changes: 9 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Copyright © 2026, William Callahan.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
No licensee or downstream recipient may use the Software (including any modified or derivative versions) to directly compete with the original Licensor by offering it to third parties as a hosted, managed, or Software-as-a-Service (SaaS) product or cloud service where the primary value of the service is the functionality of the Software itself.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

81 changes: 63 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,9 @@ export RED GREEN YELLOW CYAN NC
export PROJECT_ROOT := $(shell pwd)
export JAR_PATH = $(call get_jar)

.PHONY: all help clean build test lint format hooks run dev dev-backend compose-up compose-down compose-logs compose-ps health ingest citations fetch-all process-all full-pipeline frontend-install frontend-build

# Runtime arguments mapped from GitHub Models env vars
# - Requires GITHUB_TOKEN (PAT with models:read)
# - Base URL and model names have sensible defaults
# - CRITICAL: GitHub Models endpoint is https://models.github.ai/inference (NOT azure.com)
# - Model names differ by provider: GitHub Models uses gpt-5, OpenAI uses gpt-5.2
RUN_ARGS := \
--spring.ai.openai.api-key="$$GITHUB_TOKEN" \
--spring.ai.openai.base-url="$${GITHUB_MODELS_BASE_URL:-https://models.github.ai/inference}" \
--spring.ai.openai.chat.options.model="$${GITHUB_MODELS_CHAT_MODEL:-gpt-5}" \
--spring.ai.openai.embedding.options.model="$${GITHUB_MODELS_EMBED_MODEL:-text-embedding-3-small}"

.PHONY: help clean build test lint run dev dev-backend compose-up compose-down compose-logs compose-ps health ingest citations fetch-all process-all full-pipeline frontend-install frontend-build
all: help ## Default target (alias)

help: ## Show available targets
@grep -E '^[a-zA-Z0-9_.-]+:.*?## ' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}'
Expand All @@ -52,38 +42,80 @@ lint: ## Run static analysis (Java: SpotBugs + PMD, Frontend: svelte-check)
$(GRADLEW) spotbugsMain pmdMain
cd frontend && npm run check

format: ## Apply Java formatting (Palantir via Spotless)
$(GRADLEW) spotlessApply

hooks: ## Install git hooks via prek
@command -v prek >/dev/null 2>&1 || { echo "Error: 'prek' not found. Install it first: https://prek.j178.dev/" >&2; exit 1; }
prek install --install-hooks

run: build ## Run the packaged jar (loads .env if present)
@if [ -f .env ]; then set -a; source .env; set +a; fi; \
[ -n "$$GITHUB_TOKEN" ] || (echo "ERROR: GITHUB_TOKEN is not set. See README for setup." >&2; exit 1); \
if [ -z "$$GITHUB_TOKEN" ] && [ -z "$$OPENAI_API_KEY" ]; then \
echo "ERROR: Set GITHUB_TOKEN or OPENAI_API_KEY. See README and docs/configuration.md." >&2; \
exit 1; \
fi; \
SERVER_PORT=$${PORT:-$${port:-8085}}; \
if [ $$SERVER_PORT -lt 8085 ] || [ $$SERVER_PORT -gt 8090 ]; then echo "Requested port $$SERVER_PORT is outside allowed range 8085-8090; using 8085" >&2; SERVER_PORT=8085; fi; \
echo "Ensuring port $$SERVER_PORT is free..." >&2; \
PIDS=$$(lsof -ti tcp:$$SERVER_PORT 2>/dev/null || true); echo "Found PIDs on port $$SERVER_PORT: '$$PIDS'" >&2; if [ -n "$$PIDS" ]; then echo "Killing process(es) on port $$SERVER_PORT: $$PIDS" >&2; kill -9 $$PIDS 2>/dev/null || true; sleep 2; fi; \
echo "Binding app to port $$SERVER_PORT" >&2; \
APP_ARGS=(--server.port=$$SERVER_PORT); \
if [ -n "$$GITHUB_TOKEN" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$GITHUB_TOKEN" \
--spring.ai.openai.base-url="$${GITHUB_MODELS_BASE_URL:-https://models.github.ai/inference}" \
--spring.ai.openai.chat.options.model="$${GITHUB_MODELS_CHAT_MODEL:-gpt-5}" \
--spring.ai.openai.embedding.options.model="$${GITHUB_MODELS_EMBED_MODEL:-text-embedding-3-small}" \
); \
elif [ -n "$$OPENAI_API_KEY" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$OPENAI_API_KEY" \
); \
fi; \
# Add conservative JVM memory limits to prevent OS-level SIGKILL (exit 137) under memory pressure
# Tuned for local dev: override via JAVA_OPTS env if needed
JAVA_OPTS="$${JAVA_OPTS:- -XX:+IgnoreUnrecognizedVMOptions -Xms512m -Xmx1g -XX:+UseG1GC -XX:MaxRAMPercentage=70 -XX:MaxDirectMemorySize=256m -Dio.netty.handler.ssl.noOpenSsl=true -Dio.grpc.netty.shaded.io.netty.handler.ssl.noOpenSsl=true}"; \
java $$JAVA_OPTS -Djava.net.preferIPv4Stack=true -jar $(call get_jar) --server.port=$$SERVER_PORT $(RUN_ARGS) & disown
java $$JAVA_OPTS -Djava.net.preferIPv4Stack=true -jar $(call get_jar) "$${APP_ARGS[@]}" & disown

dev: frontend-build ## Start both Spring Boot and Vite dev servers (Ctrl+C stops both)
@echo "$(YELLOW)Starting full-stack development environment...$(NC)"
@echo "$(CYAN)Frontend: http://localhost:5173/$(NC)"
@echo "$(YELLOW)Backend API: http://localhost:8085/api/$(NC)"
@echo ""
@if [ -f .env ]; then set -a; source .env; set +a; fi; \
[ -n "$$GITHUB_TOKEN" ] || (echo "ERROR: GITHUB_TOKEN is not set. See README for setup." >&2; exit 1); \
if [ -z "$$GITHUB_TOKEN" ] && [ -z "$$OPENAI_API_KEY" ]; then \
echo "ERROR: Set GITHUB_TOKEN or OPENAI_API_KEY. See README and docs/configuration.md." >&2; \
exit 1; \
fi; \
trap 'kill 0' INT TERM; \
(cd frontend && npm run dev 2>&1 | awk '{print "\033[36m[vite]\033[0m " $$0; fflush()}') & \
(if [ -f .env ]; then set -a; source .env; set +a; fi; \
APP_ARGS=(--server.port=8085); \
if [ -n "$$GITHUB_TOKEN" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$GITHUB_TOKEN" \
--spring.ai.openai.base-url="$${GITHUB_MODELS_BASE_URL:-https://models.github.ai/inference}" \
--spring.ai.openai.chat.options.model="$${GITHUB_MODELS_CHAT_MODEL:-gpt-5}" \
--spring.ai.openai.embedding.options.model="$${GITHUB_MODELS_EMBED_MODEL:-text-embedding-3-small}" \
); \
elif [ -n "$$OPENAI_API_KEY" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$OPENAI_API_KEY" \
); \
fi; \
SPRING_PROFILES_ACTIVE=dev $(GRADLEW) bootRun \
--args="--server.port=8085 $(RUN_ARGS)" \
--args="$${APP_ARGS[*]}" \
-Dorg.gradle.jvmargs="-Xmx2g -Dspring.devtools.restart.enabled=true -Djava.net.preferIPv4Stack=true -Dio.netty.handler.ssl.noOpenSsl=true -Dio.grpc.netty.shaded.io.netty.handler.ssl.noOpenSsl=true" 2>&1 \
| awk '{print "\033[33m[java]\033[0m " $$0; fflush()}') & \
wait

dev-backend: ## Run only Spring Boot backend (dev profile)
@if [ -f .env ]; then set -a; source .env; set +a; fi; \
[ -n "$$GITHUB_TOKEN" ] || (echo "ERROR: GITHUB_TOKEN is not set. See README for setup." >&2; exit 1); \
if [ -z "$$GITHUB_TOKEN" ] && [ -z "$$OPENAI_API_KEY" ]; then \
echo "ERROR: Set GITHUB_TOKEN or OPENAI_API_KEY. See README and docs/configuration.md." >&2; \
exit 1; \
fi; \
SERVER_PORT=$${PORT:-$${port:-8085}}; \
LIVERELOAD_PORT=$${LIVERELOAD_PORT:-35730}; \
if [ $$SERVER_PORT -lt 8085 ] || [ $$SERVER_PORT -gt 8090 ]; then echo "Requested port $$SERVER_PORT is outside allowed range 8085-8090; using 8085" >&2; SERVER_PORT=8085; fi; \
Expand All @@ -93,8 +125,21 @@ dev-backend: ## Run only Spring Boot backend (dev profile)
if [ -n "$$PIDS" ]; then echo "Killing process(es) on port $$port: $$PIDS" >&2; kill -9 $$PIDS 2>/dev/null || true; sleep 1; fi; \
done; \
echo "Binding app (dev) to port $$SERVER_PORT, LiveReload on $$LIVERELOAD_PORT" >&2; \
APP_ARGS=(--server.port=$$SERVER_PORT --spring.devtools.livereload.port=$$LIVERELOAD_PORT); \
if [ -n "$$GITHUB_TOKEN" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$GITHUB_TOKEN" \
--spring.ai.openai.base-url="$${GITHUB_MODELS_BASE_URL:-https://models.github.ai/inference}" \
--spring.ai.openai.chat.options.model="$${GITHUB_MODELS_CHAT_MODEL:-gpt-5}" \
--spring.ai.openai.embedding.options.model="$${GITHUB_MODELS_EMBED_MODEL:-text-embedding-3-small}" \
); \
elif [ -n "$$OPENAI_API_KEY" ]; then \
APP_ARGS+=( \
--spring.ai.openai.api-key="$$OPENAI_API_KEY" \
); \
fi; \
SPRING_PROFILES_ACTIVE=dev $(GRADLEW) bootRun \
--args="--server.port=$$SERVER_PORT --spring.devtools.livereload.port=$$LIVERELOAD_PORT $(RUN_ARGS)" \
--args="$${APP_ARGS[*]}" \
-Dorg.gradle.jvmargs="-Xmx2g -Dspring.devtools.restart.enabled=true -Djava.net.preferIPv4Stack=true -Dio.netty.handler.ssl.noOpenSsl=true -Dio.grpc.netty.shaded.io.netty.handler.ssl.noOpenSsl=true"

frontend-install: ## Install frontend dependencies
Expand Down
Loading