# Implementation Plan: CVE Tooltip Hover ## Overview Implement a hover tooltip for CVE badges in the Reporting Page findings table. The feature spans a backend endpoint (`GET /api/cves/:cveId/tooltip`) and a frontend `CveTooltip` portal component with in-memory caching and 300ms hover delay. Tasks are ordered backend-first, then frontend component, then integration, with property tests alongside each layer. ## Tasks - [x] 1. Add backend tooltip endpoint - [x] 1.1 Add `GET /api/cves/:cveId/tooltip` route inline in `backend/server.js` - Place it alongside existing CVE endpoints (after `/api/cves/:cveId/vendors`) - Validate `:cveId` against existing `CVE_ID_PATTERN`; return 400 for invalid format - Query: `SELECT cve_id, description, severity FROM cves WHERE cve_id = ? LIMIT 1` - If no row: return `{ exists: false }` with status 200 - If row found: truncate `description` to 300 chars + "…" if needed, return `{ exists: true, cve_id, description, severity }` - Protect with `requireAuth(db)` middleware - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_ - [ ]* 1.2 Write property test for tooltip endpoint data correctness - **Property 1: Tooltip endpoint returns correct data for existing CVEs** - Install `fast-check` as dev dependency in `frontend/` (shared test runner) - Generate random CVE records with description lengths 0–1000 and all 4 severity levels - Verify response shape, truncation at 300 chars, and prefix preservation - **Validates: Requirements 1.1, 1.3, 1.5** - [ ]* 1.3 Write property test for description truncation - **Property 2: Description truncation preserves content and enforces length** - Extract truncation logic into a testable pure function - Generate random strings of length 0–2000, verify length invariant and prefix match - **Validates: Requirements 1.5** - [x] 2. Checkpoint — Verify backend endpoint - Ensure all tests pass, ask the user if questions arise. - [x] 3. Create CveTooltip frontend component - [x] 3.1 Create `frontend/src/components/CveTooltip.js` - Portal-rendered component using `ReactDOM.createPortal` to `document.body` - Props: `cveId` (string|null), `anchorRect` (DOMRect|null), `cache` (useRef Map) - Internal state: `data`, `loading` - On `cveId` change: check cache → if miss, fetch from `/api/cves/:cveId/tooltip` with AbortController - If cached `exists: false` or fetch returns `exists: false`, render nothing - Show loading spinner (Loader from lucide-react) while fetching - Display: CVE ID in monospace, severity badge with design system colors, description text - Max-width 320px, dark theme gradient background, accent border, directional arrow - Position above anchor by default; flip below if insufficient viewport space above - Do not cache transient errors (network failures) - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 3.1, 3.2, 3.3, 3.4, 3.5_ - [ ]* 3.2 Write property test for tooltip positioning logic - **Property 3: Tooltip positioning flips based on available viewport space** - Extract positioning calculation into a pure function - Generate random anchorRect.top (0–2000), tooltip height (50–200), viewport height (400–1200) - Verify tooltip never overflows top or bottom of viewport - **Validates: Requirements 3.1, 3.2** - [ ]* 3.3 Write unit tests for CveTooltip component - Test loading state renders spinner - Test `exists: false` renders nothing - Test severity badge uses correct color per level - Test max-width constraint - Test directional arrow element is present - _Requirements: 2.4, 2.5, 2.6, 3.3, 3.5_ - [x] 4. Checkpoint — Verify CveTooltip component - Ensure all tests pass, ask the user if questions arise. - [x] 5. Integrate tooltip into ReportingPage - [x] 5.1 Add hover state and cache ref to ReportingPage - Add state: `tooltipCveId` (string|null), `tooltipAnchorRect` (DOMRect|null) - Add `useRef(new Map())` for tooltip cache - Add `useRef` for hover delay timer - Clear cache when findings data is re-synced (inside existing sync callback) - _Requirements: 4.1, 4.4, 5.1_ - [x] 5.2 Add mouseenter/mouseleave handlers to CVE badge spans - In the `renderCell` function for the `'cves'` column case, wrap each CVE badge `` with `onMouseEnter` and `onMouseLeave` - `onMouseEnter`: start 300ms setTimeout; on fire, set `tooltipCveId` and `tooltipAnchorRect` from `getBoundingClientRect()` - `onMouseLeave`: clear timeout, set `tooltipCveId` to null - _Requirements: 2.1, 2.2, 5.1, 5.2_ - [x] 5.3 Render CveTooltip instance in ReportingPage - Add single `` at the bottom of the ReportingPage return, passing `tooltipCveId`, `tooltipAnchorRect`, and cache ref - _Requirements: 2.1, 4.2, 4.3_ - [ ]* 5.4 Write property test for cache round-trip behavior - **Property 4: Cache round-trip — fetch then cache-hit avoids network call** - Generate random CVE IDs and response payloads, store in Map, verify lookups return identical objects - **Validates: Requirements 4.1, 4.2** - [ ]* 5.5 Write unit tests for hover delay and cache integration - Test tooltip appears after 300ms delay (use fake timers) - Test tooltip cancelled if mouseout before 300ms - Test cached `exists: false` suppresses tooltip and API call - Test cache cleared on data sync/refresh - _Requirements: 4.3, 4.4, 5.1, 5.2_ - [x] 6. Final checkpoint — Ensure all tests pass - Ensure all tests pass, ask the user if questions arise. ## Notes - Tasks marked with `*` are optional and can be skipped for faster MVP - Each task references specific requirements for traceability - Checkpoints ensure incremental validation - Property tests validate universal correctness properties from the design document - Unit tests validate specific examples and edge cases - The project uses plain JavaScript (no TypeScript), fast-check for PBT, and react-scripts test (Jest)