Files
ai-teacher/specs/005-native-image-deployment/spec.md
T
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

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.