# Epic 3: Progress Logging & Pace Calculation **Epic Goal:** Implement the core value proposition by allowing users to log their current page number daily, calculating required pace vs. actual pace, and displaying clear status indicators, enabling users to track if they're on track to meet deadlines. ## Story 3.1: Log Progress API Endpoint As a **user**, I want **an API endpoint to log my current page for a book**, so that **my reading progress is tracked in the system**. **Acceptance Criteria:** 1. API endpoint created: `POST /api/books/:bookId/logs` 2. Endpoint accepts JSON request body: ```json { "currentPage": 150, "logDate": "2025-12-01" // Optional, defaults to today } ``` 3. Endpoint validates: - `bookId` exists in database - `currentPage` is numeric, >0, and ≤ book's totalPages - `logDate` is a valid date (defaults to today if not provided) - `currentPage` is >= last logged page for this book (can't go backward) 4. Endpoint creates or updates ReadingLog record: - If log exists for this book+date, update currentPage - If no log exists, create new ReadingLog record 5. Returns 201 (created) or 200 (updated) with the created/updated log object 6. Returns 400 error if validation fails with specific error message 7. Returns 404 error if book not found 8. Returns 500 error if database operation fails 9. Unit and integration tests written covering all cases ## Story 3.2: Pace Calculation Service As a **developer**, I want **a service that calculates required pace and actual pace**, so that **the application can show users if they're on track**. **Acceptance Criteria:** 1. Service module created in `backend/src/services/paceCalculationService.js` 2. Function `calculateRequiredPace(totalPages, currentPage, deadlineDate)` implemented: - Calculates pages remaining: `totalPages - currentPage` - Calculates days remaining: `deadlineDate - today` (in days) - Returns required pages/day: `pagesRemaining / daysRemaining` - Handles edge cases: - If deadline is today or past: returns very high number or "Overdue" - If already finished (currentPage >= totalPages): returns 0 - If days remaining = 0: returns pages remaining (all today) 3. Function `calculateActualPace(bookId, days = 7)` implemented: - Queries last N days of ReadingLogs for the book - Calculates pages read per day over that period (rolling average) - Formula: `(latestPage - pageNDaysAgo) / N` - Returns actual pages/day - If insufficient data (<2 logs), returns null or 0 4. Function `calculateStatus(requiredPace, actualPace)` implemented: - Compares required vs. actual pace - Returns status: "on-track", "slightly-behind", "behind" - Logic: - `actualPace >= requiredPace`: "on-track" - `actualPace >= requiredPace * 0.9`: "slightly-behind" (within 10%) - `actualPace < requiredPace * 0.9`: "behind" 5. Service includes comprehensive unit tests with various scenarios ## Story 3.3: Get Book Progress API Endpoint As a **user**, I want **an API endpoint that returns my book progress with pace calculations**, so that **the frontend can display whether I'm on track**. **Acceptance Criteria:** 1. Endpoint created: `GET /api/books/:bookId/progress` 2. Endpoint queries book details and all reading logs for the book 3. Endpoint uses paceCalculationService to calculate: - Current page (from latest log) - Pages remaining - Days remaining - Required pages/day - Actual pace (7-day average) - Status (on-track/slightly-behind/behind) 4. Returns JSON response: ```json { "bookId": 1, "currentPage": 150, "totalPages": 662, "pagesRemaining": 512, "deadlineDate": "2025-03-15", "daysRemaining": 45, "requiredPace": 11.4, "actualPace": 12.0, "status": "on-track", "lastLoggedDate": "2025-12-01" } ``` 5. Returns 404 if book not found 6. Returns 500 if calculation or database query fails 7. Handles cases where no logs exist yet (currentPage = 0, actualPace = null) 8. Integration test written ## Story 3.4: Enhanced Book List API with Progress Data As a **user**, I want **the book list API to include progress calculations**, so that **I can see my pace status for all books at once**. **Acceptance Criteria:** 1. Modify `GET /api/books` endpoint to include progress data for each book 2. For each book, calculate and include: - currentPage (from latest log, or 0 if no logs) - requiredPace - actualPace - status - daysRemaining - pagesRemaining 3. Response structure: ```json { "books": [ { "id": 1, "title": "The Name of the Wind", "author": "Patrick Rothfuss", "totalPages": 662, "coverUrl": "...", "deadlineDate": "2025-03-15", "currentPage": 150, "pagesRemaining": 512, "daysRemaining": 45, "requiredPace": 11.4, "actualPace": 12.0, "status": "on-track" } ] } ``` 4. Calculation logic reuses paceCalculationService functions 5. Optimized query to fetch all books and their latest logs efficiently (avoid N+1 queries) 6. Returns 500 if calculation fails, with error details 7. Integration test updated to verify progress data included ## Story 3.5: Log Progress Modal UI As a **user**, I want **a quick modal to log my current page**, so that **I can update my progress in just a few taps**. **Acceptance Criteria:** 1. Modal component created in `frontend/src/components/LogProgressModal.jsx` 2. Modal triggered by tapping a book card from the home screen 3. Modal displays: - Book title and cover (for context) - "What page are you on?" prompt - Number input field (autofocused, numeric keyboard on mobile) - Last logged: "Page X on [date]" (if exists) - "Save" button (primary CTA) - "Cancel" button or close icon 4. Input validation: - Must be a number - Must be > 0 and ≤ total pages - Must be ≥ last logged page (show error if trying to go backward) 5. Clicking "Save" calls `POST /api/books/:bookId/logs` with currentPage 6. Loading state shown while API call is in progress 7. Success: Modal closes, home screen refreshes to show updated progress 8. Error: Error message displayed in modal, user can retry 9. Modal is mobile-optimized (large touch targets, easy to dismiss) 10. Modal accessible via keyboard (Esc to close, Enter to submit) ## Story 3.6: Progress Visualization on Book Cards As a **user**, I want **to see my pace status directly on each book card**, so that **I can quickly understand if I'm on track without opening details**. **Acceptance Criteria:** 1. Book card component updated to display progress data from API 2. Each card shows: - **Required Pace:** "Target: 11 pages/day" - **Actual Pace:** "Your pace: 12 pages/day (last 7 days)" (or "No data yet" if insufficient logs) - **Pages Remaining:** "512 pages left" - **Days Remaining:** "45 days until deadline" 3. **Color-coded status indicator** (badge or border): - 🟢 Green: "On track" (status = "on-track") - 🟡 Yellow: "Slightly behind" (status = "slightly-behind") - 🔴 Red: "Behind pace" (status = "behind") 4. Status indicator includes both color AND text label (accessibility) 5. If no logs yet, show neutral state: "Start logging to track pace" 6. Component styling is mobile-responsive and readable on small screens 7. Progress data updates after logging a new entry (home screen refresh) ## Story 3.7: Book Detail Screen with Progress Details As a **user**, I want **a detailed view of a single book showing comprehensive progress information**, so that **I can dive deeper into my reading stats for that book**. **Acceptance Criteria:** 1. Book detail screen created in `frontend/src/pages/BookDetail.jsx` 2. Screen accessed by tapping on a book card (alternative to log modal, or secondary action) 3. Screen displays: - Book cover (large) - Title and author - Total pages and deadline date - **Progress Summary:** - Current page: "Page 150 of 662" - Progress bar showing % complete - Pages remaining and days remaining - **Pace Metrics:** - Required pace: "11.4 pages/day to finish on time" - Actual pace: "12.0 pages/day (last 7 days)" - Status indicator with color and text - **Last Logged:** "Last updated: Page 150 on Dec 1, 2025" 4. "Log Progress" button prominently displayed 5. "Edit Deadline" button (future story, can be placeholder) 6. "Remove Book" button (future story, can be placeholder) 7. Screen is mobile-responsive 8. Back button to return to home screen 9. Screen fetches data from `GET /api/books/:bookId/progress` ---