commit 0d624137c2557c6eeb87020749e4977b821c2b5c Author: Adrien <adrien.cesaro@proton.me> Date: Thu Apr 9 11:55:22 2026 +0200 backend native image setup
6.6 KiB
Feature Specification: Native Image Deployment
Feature Branch: 005-native-image-deployment
Created: 2026-04-07
Status: Draft
Input: Prepare the application for deployment using GraalVM native image for the backend, built into a Docker image via Jib.
User Scenarios & Testing (mandatory)
User Story 1 - Build Native Docker Image (Priority: P1)
A developer or CI pipeline runs a single Maven command to produce a Docker image containing the native-compiled backend binary. The image starts in under one second and uses significantly less memory than the JVM fat-jar image.
Why this priority: This is the core deliverable — without a working native Docker image the entire feature has no value.
Independent Test: Run mvn -Pnative jib:dockerBuild (or equivalent), start the resulting
container, hit GET /api/v1/books, and receive a valid response. Startup log must show the server
is ready in under 1 second.
Acceptance Scenarios:
- Given a clean checkout with GraalVM installed, When the developer runs the native build command, Then a Docker image is produced without manual steps.
- Given the produced Docker image, When the container is started with the required environment variables, Then the backend starts, connects to PostgreSQL, and serves HTTP requests correctly.
- Given the produced Docker image, When a RAG chat request is made, Then it responds correctly (OpenAI call, pgvector retrieval, and Flyway migrations all work in native mode).
User Story 2 - JVM Mode Preserved (Priority: P2)
A developer who has not installed GraalVM can still build and run the backend the same way as today (fat-jar / existing Dockerfile), without any change to their workflow.
Why this priority: Preserving the developer experience for non-native builds ensures the team can keep iterating without a GraalVM prerequisite.
Independent Test: Run mvn package -DskipTests and start the resulting jar with java -jar —
the application starts and serves requests identically to before this feature.
Acceptance Scenarios:
- Given a standard JDK (no GraalVM), When
mvn packageis run, Then a fat-jar is produced and runs normally. - Given the existing Dockerfile, When
docker buildis run, Then a JVM-mode image is produced and works exactly as before.
User Story 3 - Docker Compose Full Stack (Priority: P3)
A developer can bring up the complete stack (PostgreSQL + native backend) with a single
docker compose up command for local integration testing.
Why this priority: Makes it easy to validate the native image against the real database before pushing to any environment.
Independent Test: Run docker compose up (with native image tag), wait for healthy status,
make a RAG request — all services communicate correctly.
Acceptance Scenarios:
- Given the docker-compose.yml, When
docker compose upis run with the native backend image, Then all services start, health checks pass, and the application is reachable.
Edge Cases
- What happens when a reflection-heavy library (PDFBox, AWS SDK) is called at runtime without proper native hints? → Must be caught at build time via native-image test or detected early via integration smoke test.
- What if GraalVM is not installed in CI? → Build must fail with a clear error message, not silently produce a JVM image.
- What if an environment variable required at runtime is missing? → Container must fail fast with a meaningful error (not a NullPointerException from missing reflection).
Requirements (mandatory)
Functional Requirements
- FR-001: The project MUST provide a
nativeMaven profile that compiles the backend to a standalone native executable using GraalVM. - FR-002: The native profile MUST include Spring Boot AOT processing to generate the reflection, serialization, and proxy hints required at compile time.
- FR-003: The Jib Maven plugin MUST be configured to package the native executable into a Docker image without requiring Docker daemon access during the build.
- FR-004: The resulting Docker image MUST start the backend in under 1 second on modern hardware (2+ CPU cores, 2 GB RAM).
- FR-005: All existing REST endpoints MUST function correctly in native mode (book upload, RAG chat, Flyway migrations, pgvector retrieval, Spring Security).
- FR-006: The JVM fat-jar build (default profile) MUST continue to work unchanged.
- FR-007: The README.md MUST be updated with native build instructions and updated architecture/deployment diagram.
- FR-008: The
docker-compose.ymlMUST be updated (or a companion file added) to support running the native Docker image alongside PostgreSQL.
Key Entities
- Native Profile: Maven build profile (
native) that activates AOT processing and GraalVM native compilation. - Docker Image: OCI image produced by Jib, containing the native executable and a minimal base OS layer.
- AOT Hints: Compile-time metadata (reflection, serialization, proxy) that replace runtime reflection for third-party libraries.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: The native Docker image starts and serves its first HTTP request in under 1 second on a machine with 2+ CPU cores and 2 GB RAM.
- SC-002: The native container's idle memory footprint is at least 40% lower than the equivalent JVM container running the same application.
- SC-003: All existing API endpoints return correct responses in native mode (0 regressions).
- SC-004: A developer with GraalVM installed can build the native Docker image with a single command documented in README.md.
- SC-005: The default JVM build and Dockerfile continue to work without any changes to the developer workflow.
Assumptions
- GraalVM 25 (CE or Oracle) will be available in CI and on developer machines that want to build native images.
- The native build is performed on Linux x86_64; cross-compilation for other architectures is out of scope for this feature.
- Spring Boot 4.0.5 and Spring AI 2.0.0-M4 have sufficient native image support for the features used (OpenAI chat/embedding, pgvector, Flyway, Spring Security, Spring Data JPA).
- The Docker registry target and image name/tag will be configured via Maven properties or environment variables, not hardcoded.
- Frontend deployment is out of scope for this feature; only the backend native image is addressed.
- The existing Dockerfile is kept as a fallback JVM image build; the Jib-built native image is the new primary artifact.