9.7 KiB
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-securityis present inbackend/pom.xml(already included — confirm, no change needed) - T002 Verify Pinia is listed in
frontend/package.jsondependencies (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.usernameproperty tobackend/src/main/resources/application.yamlwith value${APP_AUTH_USERNAME:neurosurgeon}alongside the existingapp.auth.passwordentry - T004 Update
backend/src/main/java/com/aiteacher/config/SecurityConfig.javato inject@Value("${app.auth.username}")and pass it toUser.builder().username(username)instead of the hardcoded string"neurosurgeon" - T005 Create
backend/src/main/java/com/aiteacher/auth/AuthController.java—@RestControllerat/api/v1/auth, with a singleGET /checkmethod that accepts aPrincipalargument and returnsResponseEntity.ok(Map.of("username", principal.getName())) - T006 Create
frontend/src/stores/authStore.ts— Pinia store withusernameandpasswordrefs (initiallynull),isAuthenticatedcomputed,setCredentials(u, p)action, andclearCredentials()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, callauthStore.setCredentials(u, p), then callGET /api/v1/auth/checkvia theapiservice; on 200 navigate to/; on failure callauthStore.clearCredentials()and display the error - T008 [US1] Update
frontend/src/services/api.ts— remove the hardcodedauth: { username, password }field from the axios instance; add a request interceptor that readsauthStore.usernameandauthStore.passwordand setsconfig.authdynamically; add a response interceptor that on401callsauthStore.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 arouter.beforeEachguard that redirects to{ name: 'login' }whento.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— importuseAuthStoreanduseRouter; add a "Sign out" button to the navbar (visible only whenauthStore.isAuthenticated); clicking it callsauthStore.clearCredentials()thenrouter.push({ name: 'login' }); hide the navbar links (RouterLinkitems) 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— insetCredentials, write{ username, password }tosessionStorageunder a key (e.g.'auth'); inclearCredentials, callsessionStorage.removeItem('auth'); on store initialization (module load), read fromsessionStorageand pre-populateusernameandpasswordrefs if present - T012 [US3] Update
frontend/src/main.ts— after creating the app and mounting Pinia, callauthStore.restoreSession()(or inline the check): ifauthStore.isAuthenticated, callGET /api/v1/auth/check; if the response is401, callauthStore.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— removeVITE_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 (T003–T006) 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)
- Complete Phase 1: Confirm existing deps
- Complete Phase 2: Foundational — backend endpoint + auth store
- Complete Phase 3: US1 — login page, axios interceptors, router guard
- STOP and VALIDATE: Open incognito, verify redirect → login → success flow
- Demo / merge if MVP is sufficient
Incremental Delivery
- Phase 1 + Phase 2 → Foundation ready
- Phase 3 (US1) → Login gate works — MVP ✅
- Phase 4 (US2) → Logout works ✅
- Phase 5 (US3) → Session survives refresh ✅
- 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_PASSWORDshould be removed from.env.exampleonce T013 is done — do not remove it from any local.envfile before the login form is working (T007–T009 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