diff --git a/Dockerfile b/Dockerfile index 65461aa..d8bea2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,6 +27,7 @@ RUN npm run build # BACKEND BUILD STAGE # ================================ FROM public.ecr.aws/docker/library/eclipse-temurin:25-jdk AS builder +ARG SOURCE_COMMIT=unknown WORKDIR /app # 1. Gradle wrapper (rarely changes) @@ -51,13 +52,14 @@ COPY --from=frontend-builder /app/src/main/resources/static ./src/main/resources # 6. Build application with cache mount RUN --mount=type=cache,target=/root/.gradle \ - ./gradlew clean build -x test --no-daemon && \ + SOURCE_COMMIT="${SOURCE_COMMIT}" ./gradlew clean build -x test --no-daemon && \ cp $(ls build/libs/*.jar | grep -v '\-plain\.jar' | head -n 1) build/app.jar # ================================ # RUNTIME STAGE # ================================ FROM public.ecr.aws/docker/library/eclipse-temurin:25-jre AS runtime +ARG SOURCE_COMMIT=unknown # 1. System packages (never changes) - FIRST for maximum cache reuse RUN apt-get update && apt-get install -y --no-install-recommends curl \ @@ -79,6 +81,7 @@ ENV APP_KILL_ON_CONFLICT=false ENV DOCS_SNAPSHOT_DIR=/app/data/snapshots ENV DOCS_PARSED_DIR=/app/data/parsed ENV DOCS_INDEX_DIR=/app/data/index +ENV SOURCE_COMMIT=${SOURCE_COMMIT} # 5. Application JAR (changes every build) - LAST for optimal caching COPY --from=builder /app/build/app.jar app.jar diff --git a/build.gradle.kts b/build.gradle.kts index 637dd72..8d7da62 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,9 +12,17 @@ plugins { val spotbugsToolVersion = "4.9.8" val pmdToolVersion = "7.20.0" val palantirVersion = "2.85.0" +val sourceCommitEnvironmentVariable = "SOURCE_COMMIT" +val missingSourceCommit = "unknown" +val sourceCommit = providers.environmentVariable(sourceCommitEnvironmentVariable).orElse(missingSourceCommit) springBoot { mainClass.set("com.williamcallahan.javachat.JavaChatApplication") + buildInfo { + properties { + additional.put("commit", sourceCommit) + } + } } group = "com.williamcallahan" diff --git a/frontend/src/lib/components/CitationPanel.svelte b/frontend/src/lib/components/CitationPanel.svelte index 3363508..f894ab9 100644 --- a/frontend/src/lib/components/CitationPanel.svelte +++ b/frontend/src/lib/components/CitationPanel.svelte @@ -19,6 +19,16 @@ let { citations, visible = true, panelId }: Props = $props() let isExpanded = $state(false) + let citationListElement = $state(null) + + // The trigger usually sits at the very bottom of a scrollable container + // (chat messages, lesson panel, mobile drawer). The list expands downward, + // so without this the new content renders below the fold and stays hidden. + $effect(() => { + if (isExpanded && citationListElement) { + citationListElement.scrollIntoView({ block: 'nearest' }) + } + }) /** * Simple hash for deterministic ID generation from citation content. @@ -75,7 +85,7 @@ {#if isExpanded} -