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
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
# Tasks: Native Image Deployment
|
||||
|
||||
**Input**: Design documents from `/specs/005-native-image-deployment/`
|
||||
**Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅
|
||||
|
||||
**Tests**: No test tasks — this feature has no unit/integration test requirements in the spec.
|
||||
Smoke testing is part of US1 implementation (T010, T011).
|
||||
|
||||
**Organization**: Tasks grouped by user story for independent implementation and verification.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete-task dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (US1, US2, US3)
|
||||
- Paths use `backend/` and repo root (web app structure per constitution)
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Verify prerequisites and baseline before touching any build files.
|
||||
|
||||
- [ ] T001 Verify GraalVM 25 CE or Oracle GraalVM 25 is installed: run `native-image --version` and confirm output shows GraalVM 25; document install command (`sdk install java 25-graalce`) if missing
|
||||
- [ ] T002 [P] Verify baseline JVM build passes: run `mvn package -DskipTests` inside `backend/` and confirm `target/ai-teacher-backend-*.jar` is produced
|
||||
|
||||
**Checkpoint**: GraalVM available, existing JVM build green — safe to modify build files
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Add AOT processing and native compilation support to the Maven build. These changes
|
||||
are prerequisites for all user stories.
|
||||
|
||||
**⚠️ CRITICAL**: US1 cannot start until T007 confirms the native executable is produced.
|
||||
|
||||
- [ ] T003 Add `<profile id="native">` skeleton to `backend/pom.xml` and wire `spring-boot-maven-plugin` `process-aot` goal to the `prepare-package` phase inside that profile
|
||||
- [ ] T004 Add `native-maven-plugin` 0.10.6 to the `native` profile in `backend/pom.xml` with executions `add-reachability-metadata` and `compile-no-fork` (phase `package`), image name `ai-teacher-backend`, and build args `--initialize-at-build-time=org.slf4j` and `-H:+ReportExceptionStackTraces`
|
||||
- [ ] T005 [P] Create `backend/src/main/java/com/aiteacher/config/NativeHintsConfig.java` implementing `RuntimeHintsRegistrar`: register resource pattern `org/apache/pdfbox/resources/**` and reflection for `org.apache.pdfbox.pdmodel.font.encoding.GlyphList` with `MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS`
|
||||
- [ ] T006 Add `@ImportRuntimeHints(NativeHintsConfig.class)` annotation to the main `@SpringBootApplication` class in `backend/src/main/java/com/aiteacher/`
|
||||
- [ ] T007 Run `mvn -Pnative package -DskipTests` inside `backend/` and confirm `target/ai-teacher-backend` native executable is produced; fix any AOT compilation errors before proceeding
|
||||
|
||||
**Checkpoint**: `target/ai-teacher-backend` exists and exits cleanly — US1 implementation can begin
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Build Native Docker Image (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: One command (`mvn -Pnative package jib:dockerBuild`) produces a local Docker image
|
||||
containing the native backend. Container starts in < 1 s and all REST endpoints work.
|
||||
|
||||
**Independent Test**: Start native container with DB env vars → `GET /api/v1/books` returns 200 →
|
||||
startup log shows ready in under 1 second.
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [ ] T008 [US1] Add `jib-maven-plugin` 3.4.5 to `backend/pom.xml` `<build><plugins>` section (default build, not inside `native` profile): configure `<from><image>gcr.io/distroless/base-nossl-debian12</image></from>`, `<to><image>ai-teacher-backend</image></to>`, exposed port `8080`, and `<pluginExtensions>` referencing `com.google.cloud.tools.jib.maven.extension.nativeimage.JibNativeImageExtension`; add `jib-native-image-extension-maven` 0.1.0 as plugin `<dependency>`
|
||||
- [ ] T009 [US1] Run `mvn -Pnative package jib:dockerBuild -DskipTests` inside `backend/` and confirm `docker images | grep ai-teacher-backend` shows the produced image
|
||||
- [ ] T010 [US1] Start the native container with required env vars (`SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME`, `SPRING_DATASOURCE_PASSWORD`, `OPENAI_API_KEY`) pointing to a local PostgreSQL; verify startup log shows "Started … in < 1.0 seconds" and `GET /api/v1/books` returns HTTP 200
|
||||
- [ ] T011 [US1] Run full smoke test against the running native container: `POST /api/v1/books` (PDF upload), `POST /api/v1/chat` (RAG query), `GET /api/v1/chat/history`, and HTTP Basic auth enforcement; for each `MissingResourceException` or `ClassNotFoundException` found, add the corresponding entry to `backend/src/main/java/com/aiteacher/config/NativeHintsConfig.java` and rebuild (T009 → T010 loop) until all pass
|
||||
|
||||
**Checkpoint**: Native Docker image starts < 1 s, all 5 endpoints work — US1 complete ✅
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — JVM Mode Preserved (Priority: P2)
|
||||
|
||||
**Goal**: Default Maven build and existing Dockerfile continue to work with no changes required
|
||||
from developers who do not have GraalVM installed.
|
||||
|
||||
**Independent Test**: `mvn package -DskipTests` produces a fat-jar; `docker build` using
|
||||
`backend/Dockerfile` produces a working JVM container.
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [ ] T012 [P] [US2] Verify `mvn package -DskipTests` (no `-Pnative`) inside `backend/` still produces `target/ai-teacher-backend-*.jar`; confirm the jar starts correctly with `java -jar`
|
||||
- [ ] T013 [P] [US2] Verify `docker build -t ai-teacher-backend-jvm backend/` using the existing `backend/Dockerfile` succeeds and the resulting JVM container starts and serves `GET /api/v1/books` correctly
|
||||
|
||||
**Checkpoint**: JVM path fully unchanged — US2 complete ✅
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Docker Compose Full Stack (Priority: P3)
|
||||
|
||||
**Goal**: `docker compose -f docker-compose.native.yml up` starts PostgreSQL + native backend
|
||||
together so developers can run the complete native stack locally with a single command.
|
||||
|
||||
**Independent Test**: `docker compose -f docker-compose.native.yml up` → all services healthy →
|
||||
`GET http://localhost:8080/api/v1/books` returns 200.
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [ ] T014 [US3] Create `docker-compose.native.yml` at repo root: include `postgres` service (same image and config as `docker-compose.yml`), add `backend` service using image `ai-teacher-backend:latest` with all required env vars sourced from `.env`, `depends_on` postgres with health-check condition, and port mapping `8080:8080`
|
||||
- [ ] T015 [P] [US3] Create `.env.example` at repo root listing all env vars needed by the native stack (`SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME`, `SPRING_DATASOURCE_PASSWORD`, `OPENAI_API_KEY`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`) with placeholder values and inline comments
|
||||
|
||||
**Checkpoint**: Full native stack starts via docker compose — US3 complete ✅
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Constitution IV gate (README must be updated in the same PR as architectural change)
|
||||
and final documentation alignment.
|
||||
|
||||
- [ ] T016 Update `README.md` at repo root: add a "Native Image Build" section with GraalVM install command (`sdk install java 25-graalce`), build command (`mvn -Pnative package jib:dockerBuild`), and run command (`docker compose -f docker-compose.native.yml up`); update the Mermaid architecture diagram to show the native build pipeline (Maven native profile → GraalVM native-image → Jib → Docker image)
|
||||
- [ ] T017 [P] Update `specs/005-native-image-deployment/quickstart.md` with any corrections or additions discovered during implementation (env var names, exact commands, troubleshooting entries)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies — start immediately
|
||||
- **Foundational (Phase 2)**: Requires Phase 1 completion — **BLOCKS all user stories**
|
||||
- **US1 (Phase 3)**: Requires Phase 2 (T007 must pass) — primary deliverable
|
||||
- **US2 (Phase 4)**: Requires Phase 2 (T003–T006 must not break JVM path) — can run in parallel with US1 after Phase 2
|
||||
- **US3 (Phase 5)**: Requires US1 completion (T009 must produce the Docker image)
|
||||
- **Polish (Phase 6)**: Requires US1, US2, US3 all complete
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **US1 (P1)**: Unblocked after Foundational — critical path
|
||||
- **US2 (P2)**: Unblocked after Foundational — can run in parallel with US1 (different verification commands, no file conflicts)
|
||||
- **US3 (P3)**: Depends on US1 (needs the Docker image to exist for docker-compose)
|
||||
|
||||
### Within US1
|
||||
|
||||
T008 (Jib config) → T009 (build image) → T010 (verify startup) → T011 (smoke test + hint fixes, may loop back to T009)
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- T001 and T002 (Phase 1): both can run in parallel
|
||||
- T003/T004 (pom.xml edits) are sequential (same file); T005 (new Java file) can run in parallel with T003/T004
|
||||
- T012 and T013 (US2 verification): parallel, different commands
|
||||
- T014 and T015 (US3 docker-compose + .env.example): parallel, different files
|
||||
- T016 and T017 (Polish): parallel, different files
|
||||
- US1 (Phase 3) and US2 (Phase 4) can run in parallel after Foundational completes
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: Foundational Phase
|
||||
|
||||
```bash
|
||||
# In parallel — different files, no dependencies between them:
|
||||
Task T005: "Create NativeHintsConfig.java in backend/src/main/java/com/aiteacher/config/"
|
||||
|
||||
# Sequential — same file (pom.xml):
|
||||
Task T003: "Add native profile skeleton with spring-boot-maven-plugin process-aot"
|
||||
Task T004: "Add native-maven-plugin 0.10.6 to native profile" # after T003
|
||||
```
|
||||
|
||||
## Parallel Example: After Foundational Completes
|
||||
|
||||
```bash
|
||||
# US1 and US2 can start simultaneously:
|
||||
Developer A → Phase 3 (US1): T008 → T009 → T010 → T011
|
||||
Developer B → Phase 4 (US2): T012, T013 (parallel)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1 Only)
|
||||
|
||||
1. Complete Phase 1: Setup (T001, T002)
|
||||
2. Complete Phase 2: Foundational (T003–T007) — **CRITICAL, do not skip T007**
|
||||
3. Complete Phase 3: US1 (T008–T011)
|
||||
4. **STOP and VALIDATE**: Native image starts < 1 s, all endpoints work
|
||||
5. This alone satisfies FR-001 through FR-006 and SC-001 through SC-003
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Phase 1 + Phase 2 → build toolchain ready
|
||||
2. Phase 3 (US1) → native Docker image working (**MVP**)
|
||||
3. Phase 4 (US2) → JVM fallback confirmed
|
||||
4. Phase 5 (US3) → full native stack via docker compose
|
||||
5. Phase 6 (Polish) → README updated (constitution IV gate — **required before merge**)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- [P] tasks operate on different files or independent commands — safe to run concurrently
|
||||
- US2 (T012, T013) can be verified at any time after Phase 2; they are quick sanity checks
|
||||
- The hint-fix loop in T011 is the most likely source of iteration — budget extra time
|
||||
- Constitution IV gate (README update, T016) is **mandatory** — PR cannot merge without it
|
||||
- `.env.example` (T015) should be committed; actual `.env` must be in `.gitignore`
|
||||
Reference in New Issue
Block a user