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

190 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 (T003T006 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 (T003T007) — **CRITICAL, do not skip T007**
3. Complete Phase 3: US1 (T008T011)
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`