fix: resolve all 10 review items from PR #76 (#77)

## Summary

Resolves all 10 review recommendations from the review on PR #76.

## Review Items Addressed

| # | Item | Status |
|---|------|--------|
| 1 | Unit tests for query handler |  Already done (30 tests) |
| 2 | Log exceptions in handler |  `ILogger<GetContextualRecommendationsQueryHandler>` added |
| 3 | Guard empty embedding text |  Early return + empty vector guard in `VectorSearchStore` |
| 4 | Refine collection creation error handling |  Logs creation events and non-fatal errors |
| 5 | Replace `Console.WriteLine` with `ILogger` |  Fixed in 7 components/pages |
| 6 | Abstract HTTP calls behind a service |  `IRecommendationService` + `RecommendationService` |
| 7 | Verify CSS uses design tokens |  `ContextualRecommendationsWidget.razor.css` uses `var(--nexus-*)` |
| 8 | Add loading spinner |  Animated spinner in `ContextualRecommendationsWidget` |
| 9 | Document XML comments |  `<summary>` docs on handler, interface, service |
| 10 | Benchmark vector search latency |  `Stopwatch` around embedding and Qdrant search |

## New Files
- `IRecommendationService.cs` — Application-layer abstraction
- `RecommendationService.cs` — WASM HTTP implementation (AOT-safe)
- `ContextualRecommendationsWidget.razor` — Dashboard UI widget with spinner
- `ContextualRecommendationsWidget.razor.css` — Design-token CSS

## Build
 `dotnet build NexusReader.slnx --no-restore` — 0 errors, 5 pre-existing warnings

Closes review: #76 (comment)

---------

Co-authored-by: Marek Jasiński <jasins.marek@gmail.com>
Reviewed-on: #77
Co-authored-by: Antigravity <antigravity@google.com>
Co-committed-by: Antigravity <antigravity@google.com>
This commit was merged in pull request #77.
This commit is contained in:
2026-06-06 13:38:34 +00:00
committed by Marek Jaisński
parent 94f6fe366d
commit f7dc3b3137
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
);
}