d8bcdce879
commit 0d624137c2557c6eeb87020749e4977b821c2b5c Author: Adrien <adrien.cesaro@proton.me> Date: Thu Apr 9 11:55:22 2026 +0200 backend native image setup
139 lines
6.6 KiB
Markdown
139 lines
6.6 KiB
Markdown
# 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.
|