- add AppLayout.vue owning SidebarProvider, AppSidebar, SidebarInset, and AppHeader
- nest all authenticated views under AppLayout in the router
- leave reader and auth routes at the top level without the shell
- strip SidebarInset and AppHeader from all 8 views
- simplify App.vue to global overlays only
- add useRefreshingBooks composable for shared per-book spinner state
- show refresh spinner on BookCoverCard during any bulk operation
- bulk-refresh-metadata and bulk-re-extract-cover endpoints now stream SSE
- client reads SSE stream and updates each card cover+spinner one-by-one
- wire all missing SelectionActionBar events in LensView and CollectionView
- fix nested group ALL/ANY toggle visibility and empty-rules group handling
- add FilterSummary component with color-coded field/operator/value display
- add collapsible filter preview in LensView with header toggle
- raise MAX_DEPTH to 5 to match backend validation
- add ruleToParts helper for structured rule rendering
- update filter chip styling: emerald fields, muted operators, primary values
- style ALL/ANY badges with sky-blue and amber respectively
- add segmented sort chip with rose accent and icon
- rebuild @projectx/types package to include tag and collection in RuleField
- add SaveAsLensDialog component that takes current filter and sort as props
- wire Save as Lens button in HomeView filter panel header
- on save, creates lens with the active filter/sort and navigates to it
- add cover-fb2.ts: extract cover from <coverpage>/<binary> in FB2 XML
- add fb2-parser.ts: extract title, authors, series, language, year, genres from FB2 title-info
- wire FB2 into cover.ts extractor switch and metadata.service.ts extractMetadata
- wire FB2 into staging-metadata.service.ts for staging ingestion
- add fb2 to METADATA_FORMATS in scanner.service.ts and upload-processor.service.ts
- add MetadataService.saveExtractedCoverBytes() for saving cover bytes directly
- fix staging finalize: copy staging cover to book cover dir on finalize, overwriting stale covers
- add Regenerate Cover button to CoverEditorPanel with permission gate and cache busting
- add CardOverlayKey type and cardOverlays preference to useDisplaySettings, persisted in localStorage
- add series badge, progress bar, progress pill, format badge, rating dots, and new-book indicator overlays to BookCoverCard
- add format-colors.ts with per-format color map (epub, mobi, azw3, azw, fb2, txt, pdf, cbz, cbr, cb7)
- add Card Overlays toggle section to AppearanceSettings
- fix card click handling via handleCardClick to prevent button clicks from triggering book navigation
- add pointer-events-none to all decorative overlay elements
- add POST /api/books/:id/re-extract-cover endpoint delegating to bulkReExtractCover
- add Regenerate Cover dropdown item with loading state and live cover bump via bumpVersion
- enable pg_trgm extension in db module on startup
- add GIN trigram indexes on book_metadata title, series_name and authors name
- refactor book search query to use LEFT JOIN instead of correlated EXISTS subquery
- fix jwt-auth guard to use /api/v1/ prefix for password-change allowlist
- regenerate baseline migration to incorporate schema index changes
- fix AppHeader sticky z-index from z-10 to z-30 so search dropdown renders above book card series badges
- widen search input on focus (max-w-xs -> max-w-lg) with smooth transition
- fix result click to navigate to book detail page instead of library
- add keyboard navigation (arrow keys, enter, esc) with visual selection
- add Cmd+K / Ctrl+K shortcut to focus search from anywhere
- highlight matched text in title, author, and series fields
- show format badges (epub, pdf, mobi, etc.) per result row
- add row separators and larger cover thumbnails
- show "No results" only after debounce settles, not during typing
- extend search to match author names and series in addition to title
- add settled ref to useGlobalSearch to track fetch completion
- fix v-if -> v-show for grid/list view toggles in Home/Lens/CollectionView
- add tooltips to all header icons (search, upload, appearance, settings, theme toggle, sidebar trigger)
- fix appearance popover by moving Tooltip outside Popover
- add POST /api/books/export endpoint to zip and download books
- add POST /api/books/bulk-refresh-metadata and bulk-re-extract-cover endpoints
- add BulkBookIdsDto and ExportBooksDto
- add archiver dependency for zip streaming
- update theme CSS variables and component styles across client
- full email provider management (SMTP, test connection, share, default)
- recipient and recipient group management
- email templates with variable interpolation and system default
- user email preferences (provider, recipient, template defaults)
- send book via email from book list and cover card
- send log with pagination, resend on failure, delete entries
- admin email relay settings (SMTP relay, domain allow/blocklist)
- partial unique index to prevent duplicate system templates
- fix load-more pagination to append rather than replace entries
- add URI versioning: global prefix changed to api/v1, all frontend call sites updated
- add AbortSignal.timeout to all outbound fetch calls (10s API, 15s scrapers)
- add X-Request-Id response header and requestId field in error payloads
- add response compression via @fastify/compress (gzip + brotli)
- add security headers via @fastify/helmet with CSP for the Vite SPA
- tune pg pool: max 20, idle/connection/statement timeouts on app and migration pools
- add GET /api/v1/health endpoint via @nestjs/terminus with DB connectivity check
- Add providerIds (google/goodreads/amazon/hardcover/openLibrary) to BookDetail type, DTO, service save/load
- Expose provider ID fields in edit metadata form with editable inputs
- Auto-save provider ID on metadata apply from search drawer
- Polished metadata search: skeleton loaders, provider-colored pills/badges, result cards, diff panel
- Fix: provider ID only injected in patch when user has selected fields