Files
Adrien d8bcdce879 Squashed commit of the following:
commit 0d624137c2557c6eeb87020749e4977b821c2b5c
Author: Adrien <adrien.cesaro@proton.me>
Date:   Thu Apr 9 11:55:22 2026 +0200

    backend native image setup
2026-04-09 12:05:02 +02:00

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:

  1. Given a clean checkout with GraalVM installed, When the developer runs the native build command, Then a Docker image is produced without manual steps.
  2. 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.
  3. 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:

  1. Given a standard JDK (no GraalVM), When mvn package is run, Then a fat-jar is produced and runs normally.
  2. Given the existing Dockerfile, When docker build is 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:

  1. Given the docker-compose.yml, When docker compose up is 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 native Maven 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.yml MUST 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.