Files
ai-teacher/specs/003-basic-login/tasks.md
T
2026-04-06 14:29:53 +02:00

9.7 KiB
Raw Blame History

Tasks: Basic Login Protection

Input: Design documents from /specs/003-basic-login/
Prerequisites: plan.md spec.md research.md data-model.md contracts/ quickstart.md

Tests: Not requested — no test tasks included.

Organization: Tasks grouped by user story to enable independent implementation and testing.

Format: [ID] [P?] [Story] Description

  • [P]: Can run in parallel (different files, no dependencies on incomplete tasks)
  • [Story]: Which user story this task belongs to (US1, US2, US3)

Phase 1: Setup (Shared Infrastructure)

Purpose: No new project initialization needed — existing backend and frontend projects are in place. Phase 1 confirms the entry points for changes.

  • T001 Verify spring-boot-starter-security is present in backend/pom.xml (already included — confirm, no change needed)
  • T002 Verify Pinia is listed in frontend/package.json dependencies (already included — confirm, no change needed)

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Backend credential endpoint and frontend auth store — required by all three user stories.

⚠️ CRITICAL: No user story work can begin until this phase is complete.

  • T003 Add app.auth.username property to backend/src/main/resources/application.yaml with value ${APP_AUTH_USERNAME:neurosurgeon} alongside the existing app.auth.password entry
  • T004 Update backend/src/main/java/com/aiteacher/config/SecurityConfig.java to inject @Value("${app.auth.username}") and pass it to User.builder().username(username) instead of the hardcoded string "neurosurgeon"
  • T005 Create backend/src/main/java/com/aiteacher/auth/AuthController.java@RestController at /api/v1/auth, with a single GET /check method that accepts a Principal argument and returns ResponseEntity.ok(Map.of("username", principal.getName()))
  • T006 Create frontend/src/stores/authStore.ts — Pinia store with username and password refs (initially null), isAuthenticated computed, setCredentials(u, p) action, and clearCredentials() action (sessionStorage persistence added in Phase 5 / US3)

Checkpoint: Backend exposes GET /api/v1/auth/check; authStore is callable from any Vue component.


Phase 3: User Story 1 - Authenticate to Access the App (Priority: P1) 🎯 MVP

Goal: Unauthenticated users are redirected to /login; successful credential entry grants full app access.

Independent Test: Open the app in incognito → redirected to /login. Enter wrong credentials → error shown. Enter correct credentials → land on Library (/). Refresh the page → stays on Library (credentials held in-memory for now; persistence comes in US3).

Implementation for User Story 1

  • T007 [US1] Create frontend/src/views/LoginView.vue — centered card with username input, password input, submit button, and an error message area; on submit, call authStore.setCredentials(u, p), then call GET /api/v1/auth/check via the api service; on 200 navigate to /; on failure call authStore.clearCredentials() and display the error
  • T008 [US1] Update frontend/src/services/api.ts — remove the hardcoded auth: { username, password } field from the axios instance; add a request interceptor that reads authStore.username and authStore.password and sets config.auth dynamically; add a response interceptor that on 401 calls authStore.clearCredentials() and redirects to /login (replace the existing error-normalisation interceptor rather than adding a second one — keep error normalisation intact)
  • T009 [US1] Update frontend/src/router/index.ts — add a { path: '/login', name: 'login', component: LoginView } route; add a router.beforeEach guard that redirects to { name: 'login' } when to.name !== 'login' and !authStore.isAuthenticated

Checkpoint: US1 fully functional — incognito flow, failed login, and successful login all work independently.


Phase 4: User Story 2 - Log Out of the App (Priority: P2)

Goal: Authenticated users can log out, terminating their session and returning to /login.

Independent Test: Log in → click "Sign out" in the navbar → redirected to /login; navigating back to any protected route redirects to /login again.

Implementation for User Story 2

  • T010 [US2] Update frontend/src/App.vue — import useAuthStore and useRouter; add a "Sign out" button to the navbar (visible only when authStore.isAuthenticated); clicking it calls authStore.clearCredentials() then router.push({ name: 'login' }); hide the navbar links (RouterLink items) when on the login page by checking $route.name !== 'login'

Checkpoint: US2 fully functional — logout clears session and blocks re-entry without credentials.


Phase 5: User Story 3 - Session Persistence Across Browser Refresh (Priority: P3)

Goal: Authenticated users survive a page refresh without re-logging in; expired/invalid stored credentials redirect to /login.

Independent Test: Log in → refresh the browser → remain on the same page without re-entering credentials. Manually clear sessionStorage and refresh → redirected to /login.

Implementation for User Story 3

  • T011 [US3] Update frontend/src/stores/authStore.ts — in setCredentials, write { username, password } to sessionStorage under a key (e.g. 'auth'); in clearCredentials, call sessionStorage.removeItem('auth'); on store initialization (module load), read from sessionStorage and pre-populate username and password refs if present
  • T012 [US3] Update frontend/src/main.ts — after creating the app and mounting Pinia, call authStore.restoreSession() (or inline the check): if authStore.isAuthenticated, call GET /api/v1/auth/check; if the response is 401, call authStore.clearCredentials() so stale stored credentials are evicted before the router guard fires

Checkpoint: US3 fully functional — refresh persists login; stale or invalidated credentials are detected on load.


Phase 6: Polish & Cross-Cutting Concerns

Purpose: Documentation and cleanup that spans all user stories.

  • T013 [P] Update frontend/.env.example — remove VITE_APP_PASSWORD (the frontend no longer reads a password from env; add a comment explaining credentials are now entered via the login form)
  • T014 [P] Update README.md — add or update the Mermaid architecture diagram to show the login flow: browser → login form → /api/v1/auth/check → app; this satisfies Constitution Principle IV (diagram must be updated in the same PR as any architectural change)

Checkpoint: Feature complete — all three user stories functional, documentation current, obsolete env var removed.


Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies — confirm immediately
  • Foundational (Phase 2): Depends on Phase 1 — BLOCKS all user stories
  • US1 (Phase 3): Depends on Phase 2 completion
  • US2 (Phase 4): Depends on Phase 2 completion; integrates with authStore from Phase 2 and router from US1
  • US3 (Phase 5): Depends on Phase 2 completion; extends authStore from Phase 2
  • Polish (Phase 6): Depends on all desired stories complete

User Story Dependencies

  • US1 (P1): Depends only on Foundational — the primary blocker for all UI work
  • US2 (P2): Depends on Foundational and US1 (logout button lives in App.vue which needs the router guard from US1)
  • US3 (P3): Depends on Foundational only — authStore persistence is independent of the login form; can be developed in parallel with US1 if desired

Within Each User Story

  • Foundational tasks (T003T006) must all complete before US1 starts
  • T007 (LoginView) and T008 (api.ts) can be developed in parallel within US1; T009 (router guard) depends on T007 existing
  • US2 is a single task (T010) with no internal ordering complexity
  • T012 (main.ts restore check) depends on T011 (authStore persistence) within US3

Parallel Example: Foundational Phase

Parallelizable within Phase 2:
  T003 — application.yaml update
  T004 — SecurityConfig.java update
  T005 — AuthController.java (new file)
  T006 — authStore.ts (new file)
All four touch different files with no shared dependencies.

Parallel Example: User Story 1

Parallelizable within Phase 3:
  T007 — LoginView.vue (new file)
  T008 — api.ts update (different file)
Then sequentially:
  T009 — router/index.ts (depends on LoginView existing)

Implementation Strategy

MVP First (User Story 1 Only)

  1. Complete Phase 1: Confirm existing deps
  2. Complete Phase 2: Foundational — backend endpoint + auth store
  3. Complete Phase 3: US1 — login page, axios interceptors, router guard
  4. STOP and VALIDATE: Open incognito, verify redirect → login → success flow
  5. Demo / merge if MVP is sufficient

Incremental Delivery

  1. Phase 1 + Phase 2 → Foundation ready
  2. Phase 3 (US1) → Login gate works — MVP
  3. Phase 4 (US2) → Logout works
  4. Phase 5 (US3) → Session survives refresh
  5. Phase 6 → Documentation and cleanup

Notes

  • [P] tasks touch different files and have no dependency on an incomplete sibling task in the same phase
  • No tests included (not requested in the spec)
  • VITE_APP_PASSWORD should be removed from .env.example once T013 is done — do not remove it from any local .env file before the login form is working (T007T009 complete)
  • The 401 response interceptor in T008 handles the edge case where stored credentials become invalid server-side — no additional handling needed
  • Constitution IV requires the README Mermaid diagram to be updated in the same PR — T014 must not be skipped