Files
cve-dashboard/.kiro/specs/cve-tooltip-hover/tasks.md

108 lines
5.9 KiB
Markdown
Raw Normal View History

# 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 01000 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 02000, 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 (02000), tooltip height (50200), viewport height (4001200)
- 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 `<span>` 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 `<CveTooltip>` 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)