first implementation
This commit is contained in:
198
specs/001-neuro-rag-learning/tasks.md
Normal file
198
specs/001-neuro-rag-learning/tasks.md
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
|
||||
description: "Task list for Neurosurgeon RAG Learning Platform"
|
||||
---
|
||||
|
||||
# Tasks: Neurosurgeon RAG Learning Platform
|
||||
|
||||
**Input**: Design documents from `/specs/001-neuro-rag-learning/`
|
||||
**Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅, quickstart.md ✅
|
||||
|
||||
**Tests**: Not requested — smoke tests defined in quickstart.md are the validation gate (Principle V).
|
||||
|
||||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing.
|
||||
|
||||
## Format: `[ID] [P?] [Story?] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (US1, US2, US3)
|
||||
- File paths are relative to repository root
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Monorepo scaffolding, README, and local dev tooling.
|
||||
|
||||
- [x] T001 Create monorepo directory structure: `backend/`, `frontend/`, `README.md` at repo root
|
||||
- [x] T002 Initialize Spring Boot 4.0.5 backend Maven project with `pom.xml` in `backend/`; add Spring AI BOM 2.0.0-M4, `spring-ai-starter-vector-store-pgvector`, `spring-ai-pdf-document-reader`, `spring-ai-starter-openai`, Spring Security, Spring Data JPA, Flyway, PostgreSQL driver
|
||||
- [x] T003 [P] Initialize Vue 3 + Vite + TypeScript frontend project in `frontend/` via `npm create vue@latest`; add Axios and Pinia
|
||||
- [x] T004 [P] Create `docker-compose.yml` at repo root for local dev: PostgreSQL 16 with pgvector image (`pgvector/pgvector:pg16`), volume, env vars
|
||||
- [x] T005 [P] Add `README.md` with project description and Mermaid system-context diagram (copy diagram from `specs/001-neuro-rag-learning/quickstart.md`) — required by Constitution Principle IV
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Core infrastructure that ALL user stories depend on.
|
||||
|
||||
**⚠️ CRITICAL**: No user story work can begin until this phase is complete.
|
||||
|
||||
- [x] T006 Configure `backend/src/main/resources/application.properties`: datasource URL/credentials, Spring AI pgvector dimensions (1536) + COSINE_DISTANCE + HNSW + initialize-schema=true, OpenAI API key + model names, `app.auth.password` property
|
||||
- [x] T007 [P] Create `backend/src/main/java/com/aiteacher/config/SecurityConfig.java`: HTTP Basic auth, single in-memory user (`neurosurgeon` / `${app.auth.password}`), all requests authenticated, CSRF disabled (REST API)
|
||||
- [x] T008 [P] Create `backend/src/main/java/com/aiteacher/config/AiConfig.java`: declare `ChatClient` bean wrapping auto-configured `ChatModel`, document any Spring AI 2.x `@Bean` wiring required for `VectorStore` and `EmbeddingModel`
|
||||
- [x] T009 [P] Create Flyway migration `backend/src/main/resources/db/migration/V1__initial_schema.sql`: `book`, `chat_session`, `message` tables + `idx_message_session` index (DDL from data-model.md; do NOT create `vector_store` — Spring AI handles it)
|
||||
- [x] T010 [P] Create `backend/src/main/resources/topics.json` with 10–15 representative neurosurgery topics (id slug, name, description, category) covering Vascular, Oncology, Spine, Trauma domains
|
||||
- [x] T011 [P] Create `frontend/src/services/api.ts`: Axios instance with `baseURL` from `VITE_API_URL` env var, `auth` object for Basic credentials from `VITE_APP_PASSWORD` env var
|
||||
- [x] T012 [P] Configure Vue Router in `frontend/src/router/index.ts`: routes for `/` (UploadView), `/topics` (TopicsView), `/chat` (ChatView)
|
||||
- [x] T013 [P] Create `frontend/src/.env.example` and `frontend/src/App.vue` with top navigation bar linking to all three routes
|
||||
|
||||
**Checkpoint**: Foundation ready — user story implementation can begin.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Book Upload & Precise Embedding (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: User uploads a PDF, it is processed (text + diagram captions embedded into pgvector), and the book appears as "Ready" in the library.
|
||||
|
||||
**Independent Test**: Upload any medical PDF → observe status PENDING → PROCESSING → READY → query a topic question that can only be answered from that book and confirm a sourced answer is returned (Smoke Test 1, quickstart.md).
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [x] T014 [P] [US1] Create `backend/src/main/java/com/aiteacher/book/Book.java`: JPA entity matching data-model.md (`id`, `title`, `fileName`, `fileSizeBytes`, `pageCount`, `status`, `errorMessage`, `uploadedAt`, `processedAt`)
|
||||
- [x] T015 [P] [US1] Create `backend/src/main/java/com/aiteacher/book/BookStatus.java`: enum `PENDING`, `PROCESSING`, `READY`, `FAILED`
|
||||
- [x] T016 [P] [US1] Create `backend/src/main/java/com/aiteacher/book/BookRepository.java`: Spring Data JPA repository for `Book`
|
||||
- [x] T017 [US1] Create `backend/src/main/java/com/aiteacher/book/BookEmbeddingService.java`: use `PagePdfDocumentReader` to parse PDF page-by-page; add metadata (`book_id`, `book_title`, `page`, `chunk_type`); detect diagram captions via regex (`^(Figure|Fig\.|Table|Diagram)\s+[\d.]+`) and tag `chunk_type=diagram`; call `vectorStore.add(documents)` (depends on T014, T016)
|
||||
- [x] T018 [US1] Create `backend/src/main/java/com/aiteacher/book/BookService.java`: persist `Book` as PENDING, trigger async embedding via `BookEmbeddingService` (`@Async`), update status to PROCESSING/READY/FAILED, provide list/get/delete operations; on delete cascade remove vector chunks via `vectorStore.delete(filter on book_id)` (depends on T017)
|
||||
- [x] T019 [US1] Create `backend/src/main/java/com/aiteacher/book/BookController.java`: implement all four endpoints from `contracts/books-api.md` (`POST /api/v1/books`, `GET /api/v1/books`, `GET /api/v1/books/{id}`, `DELETE /api/v1/books/{id}`); validate PDF content-type; reject non-PDF with 400 (depends on T018)
|
||||
- [x] T020 [P] [US1] Create `frontend/src/stores/bookStore.ts` (Pinia): state for book list, actions `fetchBooks()`, `uploadBook(file)`, `deleteBook(id)` using `api.ts`
|
||||
- [x] T021 [P] [US1] Create `frontend/src/components/BookCard.vue`: display title, fileName, status badge (colour-coded), uploadedAt, delete button
|
||||
- [x] T022 [US1] Create `frontend/src/views/UploadView.vue`: file input (PDF only), upload button, progress/status message, book list using `BookCard`; poll book status every 5 s while any book is PENDING or PROCESSING (depends on T020, T021)
|
||||
|
||||
**Checkpoint**: User Story 1 fully functional — upload a PDF and observe it reach READY status.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Topic-Guided Summary (Priority: P2)
|
||||
|
||||
**Goal**: User selects a topic from the predefined list; system generates a sourced summary cross-referencing all READY books.
|
||||
|
||||
**Independent Test**: With ≥1 READY book, select a relevant topic → summary generated in < 30 s with source citations → select unrelated topic → system responds with "no relevant content found" (Smoke Test 2, quickstart.md).
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [x] T023 [P] [US2] Create `backend/src/main/java/com/aiteacher/topic/Topic.java`: Java record with fields `id`, `name`, `description`, `category`
|
||||
- [x] T024 [P] [US2] Create `backend/src/main/java/com/aiteacher/topic/TopicConfigLoader.java`: `@Component` that reads `topics.json` at startup using Jackson and exposes `List<Topic> getAll()` and `Optional<Topic> findById(String id)`
|
||||
- [x] T025 [US2] Create `backend/src/main/java/com/aiteacher/topic/TopicSummaryService.java`: use `ChatClient` with `QuestionAnswerAdvisor(vectorStore)` to generate a topic summary; build a system prompt instructing the LLM to answer only from retrieved context and cite sources; extract source metadata (`book_title`, `page`) from returned `ChatResponse`; return a DTO with `summary` string and `sources` list; if no READY books exist throw `NoKnowledgeSourceException` (depends on T024)
|
||||
- [x] T026 [US2] Create `backend/src/main/java/com/aiteacher/topic/TopicController.java`: `GET /api/v1/topics` and `POST /api/v1/topics/{id}/summary` per `contracts/topics-api.md`; map `NoKnowledgeSourceException` → 503 (depends on T025)
|
||||
- [x] T027 [P] [US2] Create `frontend/src/stores/topicStore.ts` (Pinia): state for topics list and active summary, actions `fetchTopics()`, `generateSummary(topicId)`
|
||||
- [x] T028 [P] [US2] Create `frontend/src/components/TopicCard.vue`: display topic name, description, category badge, "Generate Summary" button
|
||||
- [x] T029 [US2] Create `frontend/src/views/TopicsView.vue`: grid of `TopicCard` components; on summary request show loading spinner, then render summary text with collapsible sources list (book title + page); show friendly message when no books are available (depends on T027, T028)
|
||||
|
||||
**Checkpoint**: User Stories 1 AND 2 independently functional.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Knowledge Deepening Chat (Priority: P3)
|
||||
|
||||
**Goal**: User starts a chat session (optionally tied to a topic), asks multi-turn questions grounded in uploaded books; system declines gracefully for out-of-scope queries.
|
||||
|
||||
**Independent Test**: Start session → ask sourced question → confirm citation → ask follow-up referencing prior turn → confirm context maintained → ask out-of-scope question → confirm graceful refusal → clear conversation (Smoke Test 3, quickstart.md).
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [x] T030 [P] [US3] Create `backend/src/main/java/com/aiteacher/chat/ChatSession.java`: JPA entity (`id`, `topicId`, `createdAt`)
|
||||
- [x] T031 [P] [US3] Create `backend/src/main/java/com/aiteacher/chat/Message.java`: JPA entity (`id`, `sessionId` FK, `role`, `content`, `sources` JSONB, `createdAt`)
|
||||
- [x] T032 [P] [US3] Create `backend/src/main/java/com/aiteacher/chat/ChatSessionRepository.java` and `MessageRepository.java`: Spring Data JPA repositories
|
||||
- [x] T033 [US3] Create `backend/src/main/java/com/aiteacher/chat/ChatService.java`: create/delete sessions; send user message — retrieve full session history, build multi-turn prompt, call `ChatClient` with `QuestionAnswerAdvisor`; persist both the user message and the assistant response with source metadata; throw `NoKnowledgeSourceException` when no READY books (depends on T030, T031, T032)
|
||||
- [x] T034 [US3] Create `backend/src/main/java/com/aiteacher/chat/ChatController.java`: all four endpoints from `contracts/chat-api.md` (`POST /sessions`, `GET /sessions/{id}/messages`, `POST /sessions/{id}/messages`, `DELETE /sessions/{id}`) (depends on T033)
|
||||
- [x] T035 [P] [US3] Create `frontend/src/stores/chatStore.ts` (Pinia): state for active session and messages, actions `createSession(topicId?)`, `sendMessage(content)`, `loadMessages()`, `deleteSession()`
|
||||
- [x] T036 [P] [US3] Create `frontend/src/components/ChatMessage.vue`: render a single message bubble (user vs assistant styling); for assistant messages render inline source chips (book title + page)
|
||||
- [x] T037 [US3] Create `frontend/src/views/ChatView.vue`: topic selector (optional), "New Chat" button, scrollable message list using `ChatMessage`, text input + send button, "Clear conversation" button; auto-scroll to latest message (depends on T035, T036)
|
||||
|
||||
**Checkpoint**: All three user stories independently functional and testable.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Error handling, UX polish, Dockerfiles, and final smoke-test validation.
|
||||
|
||||
- [x] T038 [P] Add `@RestControllerAdvice` global exception handler in `backend/src/main/java/com/aiteacher/config/GlobalExceptionHandler.java`: map validation errors → 400, `NoKnowledgeSourceException` → 503, generic exceptions → 500; all responses use `{ "error": "..." }` shape from contracts
|
||||
- [x] T039 [P] Add loading states (spinner), empty-state messages, and API error toasts to all three Vue views (`UploadView`, `TopicsView`, `ChatView`)
|
||||
- [x] T040 [P] Create `backend/Dockerfile` (multi-stage: Maven build → JRE 21 runtime) and `frontend/Dockerfile` (Node 20 build → nginx serve)
|
||||
- [x] T041 [P] Run all three smoke tests from `specs/001-neuro-rag-learning/quickstart.md` against the running stack and confirm each passes
|
||||
- [x] T042 [P] Verify `README.md` Mermaid diagram renders correctly on GitHub and matches actual deployed architecture (Constitution Principle IV compliance check)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies — start immediately. T002, T003, T004, T005 can all run in parallel after T001.
|
||||
- **Foundational (Phase 2)**: Depends on T001–T005 completion. All T006–T013 can run in parallel after T002 and T003.
|
||||
- **User Story 1 (Phase 3)**: Depends on Phase 2 — BLOCKS Phases 4 and 5.
|
||||
- **User Story 2 (Phase 4)**: Depends on Phase 3 (needs READY books to exist and VectorStore to be populated).
|
||||
- **User Story 3 (Phase 5)**: Depends on Phase 2; can start in parallel with Phase 4 for back-end tasks (T030–T034); frontend (T035–T037) needs Phase 3 complete for book availability.
|
||||
- **Polish (Phase 6)**: Depends on all story phases complete.
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Entities/repositories before services
|
||||
- Services before controllers (backend)
|
||||
- Stores before views (frontend)
|
||||
- Backend and frontend tasks for the same story can proceed in parallel
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
```bash
|
||||
# Phase 1 — after T001:
|
||||
T002 (backend init) || T003 (frontend init) || T004 (docker-compose) || T005 (README)
|
||||
|
||||
# Phase 2 — after T002 + T003:
|
||||
T006 (app.properties) → T007 (security) || T008 (AI config) || T009 (Flyway) || T010 (topics.json)
|
||||
T011 (api.ts) || T012 (router) || T013 (App.vue)
|
||||
|
||||
# Phase 3 — US1 backend + frontend in parallel:
|
||||
T014 (Book entity) || T015 (enum) || T016 (repo) → T017 (EmbeddingService) → T018 (BookService) → T019 (BookController)
|
||||
T020 (bookStore) || T021 (BookCard) → T022 (UploadView)
|
||||
|
||||
# Phase 4 — US2:
|
||||
T023 (Topic record) || T024 (TopicConfigLoader) → T025 (TopicSummaryService) → T026 (TopicController)
|
||||
T027 (topicStore) || T028 (TopicCard) → T029 (TopicsView)
|
||||
|
||||
# Phase 5 — US3:
|
||||
T030 (ChatSession) || T031 (Message) || T032 (repos) → T033 (ChatService) → T034 (ChatController)
|
||||
T035 (chatStore) || T036 (ChatMessage) → T037 (ChatView)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1 Only)
|
||||
|
||||
1. Complete Phase 1: Setup
|
||||
2. Complete Phase 2: Foundational (CRITICAL)
|
||||
3. Complete Phase 3: User Story 1
|
||||
4. **STOP and VALIDATE**: Run Smoke Test 1 from quickstart.md
|
||||
5. Books are uploadable, embedded, and queryable — core infrastructure proven
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Setup + Foundational → infrastructure ready
|
||||
2. US1 → upload & embed books → **Demo: Library management works**
|
||||
3. US2 → topic summaries → **Demo: AI-generated summaries from books**
|
||||
4. US3 → chat → **Demo: Full interactive learning experience**
|
||||
5. Polish → production-ready POC
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- `[P]` tasks have no blocking dependencies on incomplete tasks in the same phase — safe to run in parallel
|
||||
- `[US1/2/3]` label maps task to specific user story for traceability
|
||||
- Backend and frontend phases within each story can run in parallel if two developers are available
|
||||
- Commit after each checkpoint to preserve independently testable increments
|
||||
- Tests are not generated (not requested); smoke tests in quickstart.md serve as the validation gate
|
||||
Reference in New Issue
Block a user