# 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.