1 line
11 KiB
JSON
1 line
11 KiB
JSON
{"path":"NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs","purpose":"Handles ingestion of an EPUB into application storage and persistence: saves files via storage service, ensures/creates author, creates Ebook entity, and persists it returning the new Ebook Id or a failure result.","classification":{"role":"handler","layer":"application","confidence":0.95,"evidence":["Command pattern","Implements MediatR IRequestHandler (line 10)","Namespace NexusReader.Application.Commands.Library (line 8)","Calls repository and storage service abstractions to persist domain entities and files (lines 31, 52, 72)"]},"className":"IngestEbookCommandHandler","methods":[{"name":"IngestEbookCommandHandler","line":15,"endLine":21,"signature":"(ebookRepository: IEbookRepository, storageService: IBookStorageService) -> IngestEbookCommandHandler","purpose":"Constructor that receives and stores repository and storage service dependencies.","calls":[],"actions":[{"id":"assignment_19","kind":"mapping","label":"Assign injected dependencies to fields","line":19,"detail":"_ebookRepository = ebookRepository; _storageService = storageService;","visibility":"detail-only","confidence":0.7}]},{"name":"Handle","line":23,"endLine":81,"signature":"(request: IngestEbookCommand, cancellationToken: CancellationToken) -> Task<Result<Guid>>","purpose":"Orchestrates saving ebook files to storage, resolving/creating the author, creating and persisting the Ebook entity, and returning success/failure Result with the Ebook Id.","calls":[{"targetFile":"NexusReader.Application.Abstractions.Services/IBookStorageService.cs","targetMethod":"SaveEbookAsync","callLine":31,"paramSummary":"request.EpubData, filename = \"{request.Title}.epub\""},{"targetFile":"NexusReader.Application.Abstractions.Services/IBookStorageService.cs","targetMethod":"SaveCoverAsync","callLine":33,"paramSummary":"request.CoverImage, filename = \"{request.Title}_cover.jpg\" (conditional)"},{"targetFile":"NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","targetMethod":"FindAuthorByNameAsync","callLine":52,"paramSummary":"authorName (trimmed/defaulted), cancellationToken"},{"targetFile":"NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","targetMethod":"AddAuthor","callLine":56,"paramSummary":"new Author { Name = authorName }"},{"targetFile":"NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","targetMethod":"AddEbook","callLine":72,"paramSummary":"ebook (new Ebook entity with Title, Author, FilePath, CoverUrl, Description, UserId, TenantId, AddedDate)"},{"targetFile":"NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","targetMethod":"SaveChangesAsync","callLine":73,"paramSummary":"cancellationToken"}],"actions":[{"id":"try-block_28","kind":"mapping","label":"Save files to storage","line":28,"detail":"Attempts SaveEbookAsync and conditionally SaveCoverAsync; catches IOException and generic Exception separately to return storage failures.","visibility":"detail-only","confidence":0.7},{"id":"external-call_31","kind":"external-call","label":"Save EPUB file","line":31,"detail":"Calls storage service to persist epub; assigns returned path to epubPath.","visibility":"detail-only","confidence":0.7},{"id":"branch_32","kind":"branch","label":"Conditional cover save","line":32,"detail":"If present, saves cover and sets coverUrl; otherwise leaves coverUrl null.","conditionSummary":"request.CoverImage != null && request.CoverImage.Length > 0","outcomeLabels":["save cover (calls SaveCoverAsync)","no cover (coverUrl = null)"],"visibility":"detail-only","confidence":0.7},{"id":"catch_36","kind":"mapping","label":"Storage I/O failure handling","line":36,"detail":"Returns Result.Fail with message 'Storage I/O failure: ...'.","conditionSummary":"IOException from storage service","outcomeLabels":["return failure Result with error caused by exception"],"visibility":"detail-only","confidence":0.7},{"id":"handle_return_38_0","kind":"return","label":"Returns result","line":38,"detail":"return Result.Fail(new Error($\"Storage I/O failure: {ex.Message}\").CausedBy(ex));","visibility":"detail-only","confidence":0.7},{"id":"catch_40","kind":"mapping","label":"Storage generic failure handling","line":40,"detail":"Returns Result.Fail with message 'Storage failure: ...'.","conditionSummary":"Any Exception from storage service","outcomeLabels":["return failure Result with error caused by exception"],"visibility":"detail-only","confidence":0.7},{"id":"handle_return_42_1","kind":"return","label":"Returns result","line":42,"detail":"return Result.Fail(new Error($\"Storage failure: {ex.Message}\").CausedBy(ex));","visibility":"detail-only","confidence":0.7},{"id":"try-block_45","kind":"mapping","label":"Create/resolve author and persist ebook","line":45,"detail":"Resolves author by name (creates if missing), constructs Ebook entity, persists via repository and SaveChangesAsync; returns success Result or fails on exceptions.","visibility":"detail-only","confidence":0.7},{"id":"guard-clause_48","kind":"guard-clause","label":"Default author name","line":48,"detail":"Normalizes author name to non-empty value.","conditionSummary":"string.IsNullOrWhiteSpace(request.AuthorName)","outcomeLabels":["use 'Unknown Author'","use trimmed request.AuthorName"],"visibility":"detail-only","confidence":0.7},{"id":"external-call_52","kind":"external-call","label":"Find author by name (repository)","line":52,"detail":"Attempts case-insensitive repository lookup for existing Author.","visibility":"detail-only","confidence":0.7},{"id":"handle_repository-read_52_2","kind":"repository-read","label":"Reads repository or persistence state","line":52,"detail":"var author = await _ebookRepository.FindAuthorByNameAsync(authorName, cancellationToken);","visibility":"secondary-visible","confidence":0.86},{"id":"branch_53","kind":"branch","label":"Author creation fallback","line":53,"detail":"Adds new Author to repository when not found.","conditionSummary":"author == null","outcomeLabels":["create and add new Author","reuse existing Author"],"visibility":"detail-only","confidence":0.7},{"id":"handle_branch_53_3","kind":"branch","label":"Evaluates branch condition","line":53,"detail":"if (author == null)","conditionSummary":"author == null","outcomeLabels":["true","false"],"visibility":"secondary-visible","confidence":0.78},{"id":"persistence-write_72","kind":"mapping","label":"Add Ebook to repository","line":72,"detail":"Calls AddEbook with constructed Ebook entity.","visibility":"detail-only","confidence":0.7},{"id":"persistence-commit_73","kind":"mapping","label":"Commit repository changes","line":73,"detail":"Calls SaveChangesAsync to persist Author and Ebook.","visibility":"detail-only","confidence":0.7},{"id":"return_75","kind":"return","label":"Return success Result with Ebook Id","line":75,"detail":"Result.Ok(ebook.Id)","visibility":"detail-only","confidence":0.7},{"id":"handle_return_75_4","kind":"return","label":"Returns result","line":75,"detail":"return Result.Ok(ebook.Id);","visibility":"detail-only","confidence":0.7},{"id":"catch_77","kind":"mapping","label":"Database error handling","line":77,"detail":"Returns Result.Fail with 'Database error during ingestion: ...'.","conditionSummary":"Any Exception during repository operations","outcomeLabels":["return failure Result with database error"],"visibility":"detail-only","confidence":0.7},{"id":"handle_return_79_5","kind":"return","label":"Returns result","line":79,"detail":"return Result.Fail(new Error($\"Database error during ingestion: {ex.Message}\").CausedBy(ex));","visibility":"detail-only","confidence":0.7}]}],"types":[],"serviceRegistrations":[],"startupActions":[],"dependencies":["NexusReader.Application.Abstractions.Services/IBookStorageService.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","NexusReader.Domain.Entities/Author.cs","NexusReader.Domain.Entities/Ebook.cs","NexusReader.Application.Commands.Library/IngestEbookCommand.cs"],"patterns":["Mediator (MediatR) Command Handler","Repository","Unit of Work (SaveChangesAsync)"],"domainConcepts":["Ebook","Author","TenantId/UserId (multitenancy/audit metadata)"],"keyDetails":"Handler performs two-phase operation: file storage first (with distinct I/O error handling), then DB work (author resolution/creation and ebook persistence) with separate error mapping to Result failures; uses repository SaveChangesAsync to commit both author and ebook.","orchestrationMethods":[{"name":"Handle","line":23,"confidence":0.98,"reason":"Coordinates 6 downstream calls with 6 architectural actions.","actionKinds":["mapping","external-call","branch","return","guard-clause","repository-read"],"evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs","NexusReader.Application.Abstractions.Services/IBookStorageService.cs","NexusReader.Application.Abstractions.Services/IBookStorageService.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs"]}],"typedContracts":[],"persistenceInteractions":[{"methodName":"Handle","line":52,"kind":"persistence-read","detail":"var author = await _ebookRepository.FindAuthorByNameAsync(authorName, cancellationToken);","evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]}],"externalInteractions":[{"methodName":"Handle","line":31,"kind":"external-call","detail":"Calls storage service to persist epub; assigns returned path to epubPath.","evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]},{"methodName":"Handle","line":52,"kind":"external-call","detail":"Attempts case-insensitive repository lookup for existing Author.","evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]}],"evidenceAnchors":[{"kind":"orchestration-method","label":"Handle","line":23,"summary":"Coordinates 6 downstream calls with 6 architectural actions.","confidence":0.98,"evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs","NexusReader.Application.Abstractions.Services/IBookStorageService.cs","NexusReader.Application.Abstractions.Services/IBookStorageService.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs","NexusReader.Application.Abstractions.Persistence/IEbookRepository.cs"]},{"kind":"persistence","label":"Handle","line":52,"summary":"var author = await _ebookRepository.FindAuthorByNameAsync(authorName, cancellationToken);","confidence":0.82,"evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]},{"kind":"external-call","label":"Handle","line":31,"summary":"Calls storage service to persist epub; assigns returned path to epubPath.","confidence":0.8,"evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]},{"kind":"external-call","label":"Handle","line":52,"summary":"Attempts case-insensitive repository lookup for existing Author.","confidence":0.8,"evidencePaths":["NexusReader.Application/Commands/Library/IngestEbookCommandHandler.cs"]}]} |