fix: resolve PR #76 review recommendations

- Add ILogger<GetContextualRecommendationsQueryHandler> with structured logging
- Guard empty embedding text in VectorSearchStore (return empty vector, skip search)
- Benchmark vector search and embedding latency with Stopwatch (LogDebug/LogInfo)
- Refine EnsureCollectionExistsAsync: log creation events and non-fatal errors
- Replace all Console.WriteLine with ILogger in UI components (AiAssistantBubble,
  AiResponseRenderer, IntelligenceToolbar, SelectionAiPanel, Catalog, Intelligence, MyBooks)
- Create IRecommendationService abstraction + RecommendationService WASM implementation
- Register IRecommendationService in Web.Client DI
- Add ContextualRecommendationsWidget component with loading spinner and design tokens
- Add ContextualRecommendationsWidget to Dashboard.razor
- Update test constructor with ILogger mock for GetContextualRecommendationsQueryHandler

Closes review items: 2, 3, 4, 5, 6, 7, 8, 9, 10
Item 1 (unit tests) was already completed in previous session
This commit is contained in:
2026-06-06 14:54:44 +02:00
parent 94f6fe366d
commit ce4687ee93
17 changed files with 549 additions and 21 deletions
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using NexusReader.Application.Abstractions.Persistence;
using NexusReader.Application.Queries.Recommendations;
@@ -17,6 +18,7 @@ public class GetContextualRecommendationsQueryTests
private readonly Mock<IUserReadingStateStore> _readingStateStoreMock;
private readonly Mock<IUserLibraryStore> _libraryStoreMock;
private readonly Mock<IVectorSearchStore> _vectorSearchStoreMock;
private readonly Mock<ILogger<GetContextualRecommendationsQueryHandler>> _loggerMock;
private readonly GetContextualRecommendationsQueryHandler _handler;
public GetContextualRecommendationsQueryTests()
@@ -24,11 +26,13 @@ public class GetContextualRecommendationsQueryTests
_readingStateStoreMock = new Mock<IUserReadingStateStore>();
_libraryStoreMock = new Mock<IUserLibraryStore>();
_vectorSearchStoreMock = new Mock<IVectorSearchStore>();
_loggerMock = new Mock<ILogger<GetContextualRecommendationsQueryHandler>>();
_handler = new GetContextualRecommendationsQueryHandler(
_readingStateStoreMock.Object,
_libraryStoreMock.Object,
_vectorSearchStoreMock.Object
_vectorSearchStoreMock.Object,
_loggerMock.Object
);
}