- audit_log table with action, resource, resourceId, description, ip, countryCode, meta
- AuditEventsService (EventEmitter), AuditRepository, AuditService, AuditInterceptor
- @Auditable decorator wired on all mutating endpoints across every controller
- auth events (login, logout, register, password change, failed login) emitted directly in AuthService with IP capture
- geoip-lite for offline IP-to-country resolution
- nightly retention cleanup via cron with configurable audit_retention_days setting
- superuser-only GET /audit-log endpoint with userId, action, resource, date range filters
- AuditLogPage.vue with table, filters, pagination, and failed-auth row highlighting
- regenerated baseline migration to include audit_log in 0000_baseline.sql
- detect HTTP 429 via fetchWithThrottle utility and throw ProviderThrottleError
- track per-provider cooldown windows with exponential backoff in ProviderThrottleTracker
- Google Books uses a conservative schedule (10m/30m/1h/2h/4h); others use default (2m/5m/10m/30m/1h)
- pipeline filters throttled providers before each book fetch
- orchestrator extends inter-book delay to 10-20s when any provider is throttled
- add displayOrder column to lenses and collections schema
- add POST /api/v1/{lenses,collections}/reorder endpoints (user-scoped)
- move Lens type to @projectx/types; add displayOrder to Collection type
- add useDraggableOrder composable with optimistic updates, debounce, rollback, and unmount cleanup
- wire VueDraggable into AppSidebar with per-section edit-mode toggle
- replace section header add/reorder buttons with a single kebab dropdown
- add split Read button on book detail page (primary format direct, dropdown for others)
- add useBookDownload composable with auth-aware blob download and ZIP export
- add BookDownloadButton component for detail page and files tab
- refactor useBookBulkActions to delegate export to useBookDownload
- add Open/Download submenus to book card dropdown
- group Edit/Refresh/Regenerate under Metadata submenu in book card
- set metadata fetch preferences defaults (goodreads-first provider order, saveProviderIds, genre merge)
- set appearance defaults: dark theme, vinyl pattern, brightness 50, updated card overlays
- set cover size 140px, grid gap 20px, new indicator threshold 7 days
- replace rating dots with colored star badge (per-rating color scale)
- set convert-to-kepub default to false
- add tags input to book edit page
- rearrange provider IDs in edit page to a single row
- make rating stars clickable in book details for direct updates
- always display rating in book details even if not set
- improve alignment of title, score badge, and provider icons
- Prettier was re-expanding the inline semi-colon separated handler back to multi-line on each commit, breaking the Vue compiler
- extract into a named function to avoid the issue