Conversation
- Rename all Professional references to Provider for consistency - Move enums to Domain/Enums folder with E prefix (EProviderType, EVerificationStatus, EDocumentType) - Move DocumentExtensions to Shared for reusability - Update all domain entities, events, repositories, and DTOs - Create Provider aggregate root with proper domain logic - Implement CQRS commands and queries structure - Update database schema to use 'providers' schema - Maintain Clean Architecture + CQRS compliance
WalkthroughAdds a complete Providers module (Domain, Application, Infrastructure, API, Tests), centralizes NuGet package versions and sources, introduces EF Core persistence and migrations under schema "providers", wires module into startup, extends shared auth/utilities, adds scripts/SQL and API client specs, and updates documentation. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant API as Providers API Endpoint
participant Dispatcher as CQRS Dispatcher
participant Handler as CreateProviderHandler
participant Repo as IProviderRepository
participant DB as ProvidersDbContext
Client->>API: POST /api/v1/providers
API->>Dispatcher: Dispatch(CreateProviderCommand)
Dispatcher->>Handler: HandleAsync(command)
Handler->>Repo: AddAsync(provider)
Repo->>DB: INSERT provider & owned collections
Handler-->>Dispatcher: Result<ProviderDto>
Dispatcher-->>API: Result
API-->>Client: 201 Created (ProviderDto)
sequenceDiagram
autonumber
actor Client
participant API as Providers API Endpoint
participant Dispatcher as CQRS Dispatcher
participant QueryHandler as GetProvidersQueryHandler
participant Service as IProviderQueryService
participant DB as ProvidersDbContext
Client->>API: GET /api/v1/providers?page=1
API->>Dispatcher: Dispatch(GetProvidersQuery)
Dispatcher->>QueryHandler: HandleAsync(query)
QueryHandler->>Service: GetProvidersAsync(filters, paging)
Service->>DB: Query (filters + paging)
DB-->>Service: PagedResult<Provider>
Service-->>QueryHandler: PagedResult<Provider>
QueryHandler-->>API: Result<PagedResult<ProviderDto>>
API-->>Client: 200 OK
sequenceDiagram
autonumber
participant Host as WebApplication
participant Module as ProvidersModule (UseProvidersModule)
participant Scope as DI Scope
participant Ctx as ProvidersDbContext
Host->>Module: UseProvidersModule()
Module->>Scope: CreateScope()
Scope->>Ctx: Database.Migrate()
alt Migration succeeds
Ctx-->>Module: Migrations applied
else Migration fails
Ctx->>Ctx: Database.EnsureCreated()
end
Module-->>Host: Map endpoints
Estimated code review effort🎯 5 (Critical) | ⏱️ ~150 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (8)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 28
🧹 Nitpick comments (19)
src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs (1)
7-13: LGTM! Clean CQRS command structure.The command follows the established CQRS pattern correctly with appropriate documentation and type safety using value objects.
One optional suggestion: Consider whether
QualificationNameshould have validation (e.g., not null/empty). However, since this validation may intentionally occur in the handler or domain layer, the current structure is acceptable.src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (1)
47-51: Consider more specific exception handling.The catch-all exception handler provides good logging but could be improved:
- Security consideration: Exposing
ex.Messagedirectly on line 50 might leak internal implementation details to clients- Error categorization: Domain validation failures (e.g., qualification not found) and infrastructure failures (e.g., database errors) are handled identically
Consider either:
- Using a more generic error message for the client
- Adding specific catches for expected domain exceptions
- Having the domain layer return
Resulttypes instead of throwing exceptionssrc/Aspire/MeAjudaAi.AppHost/Program.cs (2)
129-129: Improve readability of the boolean expression.The expression
!bool.TryParse(exposeHttpStr, out var exposeResult)||exposeResultis difficult to understand and is missing a space before||. While functionally correct (defaults totruewhen parsing fails or when the parsed value istrue), the logic is not immediately clear.Apply this diff for better readability:
- options.ExposeHttpEndpoint = !bool.TryParse(exposeHttpStr, out var exposeResult)||exposeResult; + options.ExposeHttpEndpoint = !bool.TryParse(exposeHttpStr, out var exposeResult) || exposeResult;Or for even better clarity, use explicit conditional logic:
- options.ExposeHttpEndpoint = !bool.TryParse(exposeHttpStr, out var exposeResult)||exposeResult; + options.ExposeHttpEndpoint = bool.TryParse(exposeHttpStr, out var exposeResult) ? exposeResult : true;
158-159: Track the TODO for Azure Container App Environment.The Azure Container App Environment initialization has been disabled with a TODO comment. This is acceptable for development but should be resolved before production deployment.
Ensure this TODO is tracked in your issue tracker. Would you like me to open a new issue to track this task?
src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (1)
22-33: Trim before validating the email.Today we validate
Trim(), so inputs with harmless leading/trailing spaces (common in form submissions) get rejected even though we later normalize them. Please normalize first, then run the emptiness and format checks against the trimmed value.Apply this diff to normalize before validating:
- public ContactInfo(string email, string? phoneNumber = null, string? website = null) + public ContactInfo(string email, string? phoneNumber = null, string? website = null) { - if (string.IsNullOrWhiteSpace(email)) - throw new ArgumentException("Email cannot be empty", nameof(email)); - - if (!IsValidEmail(email)) + var normalizedEmail = email?.Trim(); + + if (string.IsNullOrWhiteSpace(normalizedEmail)) + throw new ArgumentException("Email cannot be empty", nameof(email)); + + if (!IsValidEmail(normalizedEmail)) throw new ArgumentException("Invalid email format", nameof(email)); - Email = email.Trim(); + Email = normalizedEmail!; PhoneNumber = phoneNumber?.Trim(); Website = website?.Trim(); }src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (1)
40-47: Consider validating command fields before constructing the Qualification.The Qualification value object is constructed directly from command fields without validation. If the Qualification constructor enforces invariants and throws exceptions for invalid data, those exceptions will be caught by the general catch block below, potentially masking validation failures.
Consider adding explicit validation:
+ // Validate command fields + if (string.IsNullOrWhiteSpace(command.Name)) + { + logger.LogWarning("Invalid qualification name for provider {ProviderId}", command.ProviderId); + return Result<ProviderDto>.Failure("Qualification name is required"); + } + var qualification = new Qualification( command.Name, command.Description, command.IssuingOrganization, command.IssueDate, command.ExpirationDate, command.DocumentNumber );src/Modules/Providers/Application/Queries/GetProvidersByIdsQuery.cs (1)
10-10: Consider adding validation for the ProviderIds parameter.The query accepts an
IReadOnlyList<Guid>without validation. Consider whether the handler should validate:
- The collection is not null or empty
- Individual GUIDs are not
Guid.EmptyThis would provide clearer error messages and avoid unnecessary repository calls.
src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs (1)
12-12: Consider validating ProviderId is not Guid.Empty.The command accepts a
ProviderIdwithout validation. While the handler will likely fail when converting to theProviderIdvalue object, validating at the command level or in the handler would provide clearer error messages.src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs (1)
10-10: Consider validating ProviderId is not Guid.Empty.The query accepts a
ProviderIdwithout validation. While the handler creates aProviderIdvalue object that validates non-empty GUIDs (line 31 in the handler), validation at the query level or explicit validation in the handler would provide clearer error messages to API consumers.src/Modules/Providers/Application/Commands/AddDocumentCommand.cs (1)
11-15: Consider adding validation for command parameters.The command accepts parameters without validation:
ProviderIdcould beGuid.EmptyDocumentNumbercould be null or emptyConsider adding validation in the command handler to provide clear error messages before attempting domain operations.
src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (1)
27-48: Refine exception handling to distinguish validation errors from infrastructure failures.The current implementation catches all exceptions generically (line 43), which can hide validation failures. For example, if
query.ProviderIdisGuid.Empty, theProviderIdconstructor (line 31) throws anArgumentException, which is then caught and reported as a generic infrastructure error.Consider:
- Validating
query.ProviderId != Guid.Emptybefore creating the value object and returning a validation failure- Catching specific exception types (e.g.,
ArgumentExceptionfor validation vs. infrastructure exceptions)- Allowing programming errors (like
NullReferenceException) to propagate for easier debuggingApply this diff to add explicit validation:
public async Task<Result<ProviderDto?>> HandleAsync(GetProviderByIdQuery query, CancellationToken cancellationToken) { try { logger.LogInformation("Getting provider by ID {ProviderId}", query.ProviderId); + if (query.ProviderId == Guid.Empty) + { + logger.LogWarning("Invalid provider ID: empty GUID"); + return Result<ProviderDto?>.Failure("Provider ID cannot be empty"); + } + var providerId = new ProviderId(query.ProviderId); var provider = await providerRepository.GetByIdAsync(providerId, cancellationToken);src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs (1)
22-23: Consider deferring string formatting in logging.Using
string.Joindirectly in log statements creates strings even when the log level is disabled. For large collections of IDs, this could impact performance.Consider using structured logging or deferred formatting:
- logger.LogDebug("Retrieving providers by IDs: {ProviderIds}", - string.Join(", ", query.ProviderIds)); + logger.LogDebug("Retrieving providers by {Count} IDs", + query.ProviderIds.Count);Or use a scoped property if you need the actual IDs:
using (logger.BeginScope(new Dictionary<string, object> { ["ProviderIds"] = query.ProviderIds })) { logger.LogDebug("Retrieving providers by IDs"); // ... rest of code }Also applies to: 29-30
src/Modules/Providers/Application/Commands/UpdateProviderProfileCommand.cs (1)
10-15: Consider adding validation for the Name parameter.The
Nameparameter accepts any string without constraint. Consider validating that it's not empty or whitespace, either at the command level or ensuring the handler validates it.src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByCityEndpoint.cs (1)
77-84: Consider validating the city parameter.The city parameter from the route is directly converted to a query without validation. Consider adding validation to reject empty, whitespace, or invalid city values before dispatching the query.
Example validation:
private static async Task<IResult> GetProvidersByCityAsync( string city, IQueryDispatcher queryDispatcher, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(city)) + return Results.BadRequest("City parameter cannot be empty"); + var query = city.ToCityQuery(); var result = await queryDispatcher.QueryAsync<GetProvidersByCityQuery, Result<IReadOnlyList<ProviderDto>>>( query, cancellationToken); return Handle(result); }src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
15-31: Load environment-specific settings dynamically.Design-time tooling often runs with
DOTNET_ENVIRONMENT/ASPNETCORE_ENVIRONMENTset; hard-coding the Development profile makes staging/production appsettings invisible unless duplicated. Pull the environment name and add the matching json file when present.Apply this diff to respect the active environment:
+using System; + public class ProvidersDbContextFactory : IDesignTimeDbContextFactory<ProvidersDbContext> { public ProvidersDbContext CreateDbContext(string[] args) { - var configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: true) - .AddJsonFile("appsettings.Development.json", optional: true) - .AddEnvironmentVariables() - .Build(); + var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") + ?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); + + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true); + + if (!string.IsNullOrWhiteSpace(environment)) + { + configurationBuilder.AddJsonFile($"appsettings.{environment}.json", optional: true); + } + + var configuration = configurationBuilder + .AddEnvironmentVariables() + .Build();src/Modules/Providers/Infrastructure/Extensions.cs (1)
27-33: Fail fast when the connection string is missing.
configuration.GetConnectionString("DefaultConnection")can return null/empty, leading to a later Npgsql configuration failure that is harder to diagnose. Check immediately and throw a descriptive exception so misconfiguration is caught early.services.AddDbContext<ProvidersDbContext>(options => { var connectionString = configuration.GetConnectionString("DefaultConnection"); + if (string.IsNullOrWhiteSpace(connectionString)) + throw new InvalidOperationException("Connection string 'DefaultConnection' is not configured."); options.UseNpgsql(connectionString, npgsqlOptions => { npgsqlOptions.MigrationsAssembly(typeof(ProvidersDbContext).Assembly.FullName);src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs (1)
18-24: Consider making BusinessProfile nullable or removing the default.The default initialization creates a BusinessProfileDto with empty/null values that would fail validation. While this doesn't cause runtime issues (validation will catch it), it may be clearer to either make the property nullable (
BusinessProfileDto?) or require explicit initialization by removing the default value entirely.Apply this diff if you prefer nullable:
- public BusinessProfileDto BusinessProfile { get; init; } = new( - string.Empty, - null, - null, - new ContactInfoDto(string.Empty, null, null), - new AddressDto(string.Empty, string.Empty, null, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty) - ); + public BusinessProfileDto? BusinessProfile { get; init; }src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (1)
52-101: Reuse the ProviderMapper to avoid duplicating DTO constructionThis block reimplements the full
Provider→ProviderDtoprojection inline. We already haveProviderMapperin the application layer, so duplicating the mapping here increases drift risk when DTOs evolve (new fields, nullability tweaks, etc.). Please consider delegating to the mapper (e.g.,providerMapper.ToDto(provider)) so we keep a single source of truth for the transformation.src/Modules/Providers/Domain/Entities/Provider.cs (1)
313-323: GuardMarkAsDeletedagainst null inputs.Every other mutator defends against null arguments; here a null
dateTimeProviderwill throw aNullReferenceExceptioninstead of the expectedArgumentNullException. Add the same guard for consistency and clearer failures.public void MarkAsDeleted(IDateTimeProvider dateTimeProvider) { + ArgumentNullException.ThrowIfNull(dateTimeProvider); + if (IsDeleted) return;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
Directory.Packages.props(1 hunks)MeAjudaAi.sln(2 hunks)infrastructure/database/modules/providers/01-permissions.sql(1 hunks)nuget.config(1 hunks)src/Aspire/MeAjudaAi.AppHost/MeAjudaAi.AppHost.csproj(2 hunks)src/Aspire/MeAjudaAi.AppHost/Program.cs(2 hunks)src/Aspire/MeAjudaAi.ServiceDefaults/MeAjudaAi.ServiceDefaults.csproj(2 hunks)src/Bootstrapper/MeAjudaAi.ApiService/MeAjudaAi.ApiService.csproj(1 hunks)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs(3 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/DeleteProviderEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByIdEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByUserIdEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByCityEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByStateEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByTypeEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByVerificationStatusEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/RemoveDocumentEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProvidersModuleEndpoints.cs(1 hunks)src/Modules/Providers/API/Extensions.cs(1 hunks)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj(1 hunks)src/Modules/Providers/Application/Commands/AddDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/AddQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/CreateProviderCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/UpdateProviderProfileCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs(1 hunks)src/Modules/Providers/Application/DTOs/ProviderDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/AddDocumentRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateVerificationStatusRequest.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Mappers/ProviderMapper.cs(1 hunks)src/Modules/Providers/Application/MeAjudaAi.Modules.Providers.Application.csproj(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByIdsQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersQuery.cs(1 hunks)src/Modules/Providers/Application/Services/IProviderQueryService.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Domain/Entities/Provider.cs(1 hunks)src/Modules/Providers/Domain/Enums/EDocumentType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EVerificationStatus.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDeletedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderProfileUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderRegisteredDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderVerificationStatusUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs(1 hunks)src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj(1 hunks)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Address.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Document.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Qualification.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/MeAjudaAi.Modules.Providers.Infrastructure.csproj(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.Designer.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs(1 hunks)src/Modules/Providers/Tests/Builders/ProviderBuilder.cs(1 hunks)src/Modules/Providers/Tests/GlobalTestConfiguration.cs(1 hunks)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs(1 hunks)src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs(1 hunks)
⛔ Files not processed due to max files limit (31)
- src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/DeleteProviderCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByIdQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByUserIdQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
- src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs
- src/Modules/Providers/Tests/Unit/Domain/ValueObjects/DocumentTests.cs
- src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs
- src/Modules/Users/API/MeAjudaAi.Modules.Users.API.csproj
- src/Modules/Users/Application/MeAjudaAi.Modules.Users.Application.csproj
- src/Modules/Users/Infrastructure/MeAjudaAi.Modules.Users.Infrastructure.csproj
- src/Modules/Users/MeAjudaAi.Modules.Users.Tests/MeAjudaAi.Modules.Users.Tests.csproj
- src/Modules/Users/Tests/MeAjudaAi.Modules.Users.Tests.csproj
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/DTOs/ModuleProviderDto.cs
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/Enums.cs
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/IProvidersModuleApi.cs
- src/Shared/MeAjudai.Shared/Extensions/DocumentExtensions.cs
- src/Shared/MeAjudai.Shared/MeAjudaAi.Shared.csproj
- tests/MeAjudaAi.ApiService.Tests/MeAjudaAi.ApiService.Tests.csproj
- tests/MeAjudaAi.Architecture.Tests/MeAjudaAi.Architecture.Tests.csproj
- tests/MeAjudaAi.Architecture.Tests/ModuleApiArchitectureTests.cs
🧰 Additional context used
🧬 Code graph analysis (28)
src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Commands/AddDocumentCommand.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Commands/AddQualificationCommand.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
BusinessProfile(113-131)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (5)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)IEnumerable(48-53)ToString(55-55)src/Modules/Providers/Domain/ValueObjects/Address.cs (5)
Address(8-82)Address(22-31)Address(33-66)IEnumerable(68-78)ToString(80-81)
src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Extensions.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-43)IServiceCollection(20-42)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)IReadOnlyList(36-39)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
CreateProviderCommandHandler(21-71)
src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Domain/ValueObjects/Qualification.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Qualification(144-154)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (6)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)IEnumerable(44-51)src/Modules/Providers/Domain/ValueObjects/Address.cs (4)
IEnumerable(68-78)Address(8-82)Address(22-31)Address(33-66)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (4)
IEnumerable(48-53)ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/ValueObjects/Document.cs (3)
IEnumerable(53-57)Document(12-60)Document(20-24)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (4)
IEnumerable(50-58)Qualification(8-62)Qualification(20-23)Qualification(25-46)
src/Modules/Providers/Infrastructure/Extensions.cs (3)
src/Modules/Providers/Application/Extensions.cs (2)
Extensions(15-43)IServiceCollection(17-42)src/Shared/MeAjudai.Shared/Database/BaseDesignTimeDbContextFactory.cs (1)
IConfiguration(95-105)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
ProvidersDbContext(18-38)
src/Modules/Providers/Application/Commands/UpdateProviderProfileCommand.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)BusinessProfile(113-131)ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (2)
IEnumerable(44-51)ToString(53-54)
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (2)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/MeAjudai.Shared/Time/UuidGenerator.cs (1)
UuidGenerator(8-33)
src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)BusinessProfile(113-131)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (12)
Task(22-22)Task(30-30)Task(37-37)Task(44-44)Task(54-54)Task(62-62)Task(70-70)Task(78-78)Task(86-86)Task(94-94)Task(102-104)Task(112-114)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Application/DTOs/ProviderDto.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (8)
ContactInfoDto(58-65)AddressDto(70-82)BusinessProfileDto(44-53)DocumentDto(87-93)QualificationDto(98-108)ProviderDto(15-31)BusinessProfile(113-131)IReadOnlyList(36-39)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Modules/Providers/Application/Commands/CreateProviderCommand.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)BusinessProfile(113-131)ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Modules/Providers/Domain/ValueObjects/Address.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (2)
IEnumerable(44-51)ToString(53-54)
src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs (1)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Domain/ValueObjects/Document.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Document(136-139)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/MeAjudai.Shared/Extensions/DocumentExtensions.cs (2)
IsValidCpf(13-30)IsValidCnpj(35-52)
src/Modules/Providers/Domain/Entities/Provider.cs (7)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(12-60)Document(20-24)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)src/Shared/MeAjudai.Shared/Domain/BaseEntity.cs (2)
AddDomainEvent(15-15)MarkAsUpdated(17-17)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs (3)
ProviderDomainException(12-30)ProviderDomainException(18-20)ProviderDomainException(27-29)
src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)
🔇 Additional comments (40)
src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs (1)
1-30: LGTM! Clean domain exception implementation.The implementation follows standard .NET exception patterns correctly. The two constructors appropriately delegate to the base
DomainExceptionclass, and the XML documentation clearly describes the exception's purpose within the service provider domain context.infrastructure/database/modules/providers/01-permissions.sql (3)
12-12: Consider setting search_path for meajudaai_app_role.Line 12 sets
search_pathforproviders_roletoproviders, public, butmeajudaai_app_roledoes not receive an explicit search_path configuration. This asymmetry could lead to unexpected behavior ifmeajudaai_app_rolequeries require schema qualification.Clarify whether this is intentional (e.g., if the app role relies on default search_path or explicit schema names in queries) or if a matching configuration should be applied.
Also applies to: 15-17
1-21: Permissions structure is well-designed.The use of
ALTER DEFAULT PRIVILEGESto future-proof permissions, coupled with explicit DML-only grants (no DDL), demonstrates a solid understanding of PostgreSQL security best practices. The separation of permissions forproviders_roleandmeajudaai_app_rolealigns well with the module-based DDD architecture described in the PR.
3-5: ****The original concern about role existence verification is already properly handled. Both
providers_roleandmeajudaai_app_roleare created in the preceding00-roles.sqlmigration using idempotentDOblocks withIF NOT EXISTSchecks againstpg_catalog.pg_roles. The file naming convention (00-roles.sql before 01-permissions.sql) ensures correct migration sequencing. The permissions script can safely assume roles exist without explicit checks.The codebase design demonstrates defensive programming patterns and no action is required.
Likely an incorrect or invalid review comment.
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (4)
17-20: LGTM! Proper handler setup.The handler uses modern primary constructor syntax with appropriate dependency injection and internal visibility.
27-38: LGTM! Proper entity retrieval and validation.The provider retrieval logic correctly uses value objects, propagates the cancellation token, and handles the not-found case with appropriate logging.
42-45: LGTM! Proper persistence and DTO mapping.The update operation and DTO conversion follow the established patterns in the codebase, with proper async/await usage and consistent mapper usage.
40-40: The original review comment is incorrect. Error handling is properly implemented.The
RemoveQualificationmethod (Provider.cs, line 243) isvoidand throws domain exceptions to signal errors:
- Throws
ProviderDomainExceptionwhen the qualification is not found with message:"Qualification '{qualificationName}' not found"- The handler's try-catch block (lines 47-50) catches these exceptions and wraps them as
Result.Failure($"Error removing qualification: {ex.Message}")The resulting error message is specific:
"Error removing qualification: Qualification 'Certificação Inexistente' not found", not generic.Comprehensive unit tests confirm this behavior works correctly for all error scenarios (non-existent qualifications, invalid names, repository failures). This exception-based error handling is an established pattern in the domain layer.
Likely an incorrect or invalid review comment.
src/Modules/Providers/Domain/Enums/EDocumentType.cs (1)
1-14: LGTM!The enum is well-structured with appropriate document types for the Brazilian context (CPF, CNPJ, RG, CNH) plus international options. The explicit discriminants and the gap to
Other = 99provide good extensibility for future document types.src/Modules/Providers/Domain/Events/ProviderDeletedDomainEvent.cs (1)
1-17: LGTM!The domain event follows DDD best practices with appropriate parameters for tracking provider deletion. The nullable
DeletedByparameter correctly handles both user-initiated and system-initiated deletions.src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs (1)
1-14: LGTM!The command follows CQRS best practices with appropriate use of the
Result<T>pattern for functional error handling. The use ofEDocumentTypeensures type safety for document removal operations.src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs (1)
1-10: LGTM!The query follows CQRS patterns correctly with appropriate use of
IReadOnlyList<T>for immutable result sets. TheStateparameter as a string provides flexibility for various state representations.src/Modules/Providers/Application/Commands/AddQualificationCommand.cs (1)
1-18: LGTM!The command is well-structured with appropriate nullability for optional qualification details. Required fields (
ProviderId,Name) are non-nullable, while supporting details are correctly nullable, providing flexibility for various qualification types.src/Aspire/MeAjudaAi.ServiceDefaults/MeAjudaAi.ServiceDefaults.csproj (1)
12-22: Verification complete—no issues found.Central package management is properly configured. All 11 packages referenced in ServiceDefaults.csproj are defined in Directory.Packages.props with appropriate versions. The removal of explicit version attributes correctly delegates version management to the central configuration file.
src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj (1)
15-17: The project reference path is correct and requires no changes.The script output confirms the actual directory structure is
src/Shared/MeAjudai.Shared/MeAjudaAi.Shared.csproj. The path in the code (..\..\..\Shared\MeAjudai.Shared\MeAjudaAi.Shared.csproj) correctly references the existing directory and file. The review comment's concern about a typo was based on an incorrect assumption about the naming convention.Likely an incorrect or invalid review comment.
src/Modules/Providers/Domain/Enums/EProviderType.cs (1)
1-10: LGTM!The enum is clean, well-documented, and uses explicit numbering for database compatibility.
src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs (1)
1-10: LGTM!The query record follows CQRS patterns correctly and uses appropriate nullability (
ProviderDto?) to indicate the provider may not exist.src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (1)
2-2: LGTM!The Providers module integration follows the established pattern used by the Users module. The placement is consistent and appropriate.
Also applies to: 44-44, 54-54
src/Modules/Providers/Tests/Builders/ProviderBuilder.cs (3)
21-71: LGTM!The Faker configuration is well-structured and handles both constructor variants appropriately. The logic for applying documents, qualifications, and verification status after instantiation is clean and follows the builder pattern correctly.
73-137: LGTM!The fluent builder methods provide a clean and expressive API for test data construction. The convenience methods
AsIndividual()andAsCompany()are particularly nice touches.
139-159: LGTM!The default business profile generation creates realistic test data with all required components (address, contact info). The hardcoded values like "Centro" and "Brasil" are acceptable for test data.
src/Modules/Providers/Domain/Enums/EVerificationStatus.cs (1)
6-13: LGTM!The enum uses explicit integral values starting from 1, which provides stability for database storage and serialization while avoiding potential issues with the default value of 0.
src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs (1)
14-14: Verify audit requirements for the optional UpdatedBy parameter.The
UpdatedByparameter is nullable and optional. For verification status changes, audit trails are typically required to track who made the change. Ensure this aligns with your compliance and audit requirements.src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj (1)
1-28: LGTM!The project configuration follows modern .NET practices with strict warnings, analyzers enabled, and proper layered architecture references (API → Application/Infrastructure → Shared). The use of central package management (no explicit versions) promotes consistency across the solution.
src/Modules/Providers/Domain/Events/ProviderDocumentRemovedDomainEvent.cs (1)
13-18: LGTM!The domain event is well-structured as an immutable record with comprehensive XML documentation. It correctly captures the essential data for a document removal event.
src/Modules/Providers/Domain/Events/ProviderQualificationAddedDomainEvent.cs (1)
1-17: LGTM! Clean domain event implementation.The domain event follows DDD patterns correctly and is consistent with other events in the Providers module. Properties are well-documented and the structure is appropriate.
src/Modules/Providers/Domain/Events/ProviderDocumentAddedDomainEvent.cs (1)
1-18: LGTM! Well-structured domain event.The event follows the established pattern and correctly uses the EDocumentType enum for type safety.
src/Modules/Providers/Application/Commands/CreateProviderCommand.cs (1)
1-16: LGTM! Clean command definition.The command follows CQRS patterns correctly with appropriate properties and good documentation.
src/Modules/Providers/Domain/Events/ProviderQualificationRemovedDomainEvent.cs (1)
1-17: LGTM! Well-structured domain event.The removal event correctly mirrors the addition event, maintaining consistency in the domain event model.
src/Modules/Providers/Tests/GlobalTestConfiguration.cs (1)
1-12: LGTM! Standard xUnit collection definition.The test collection is properly configured to share the integration test fixture across tests.
src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs (1)
32-36: Good handling of not-found case.Returning
Success(null)appropriately distinguishes between a not-found result and an error condition, with proper warning-level logging.src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs (1)
11-11: LGTM! Clean query implementation.The query record follows CQRS patterns correctly and the enum parameter provides type safety.
src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs (1)
11-11: LGTM! Consistent query pattern.The implementation follows the same clean pattern as other query records in the module.
src/Modules/Providers/Application/DTOs/Requests/UpdateVerificationStatusRequest.cs (1)
9-20: LGTM! Well-structured request DTO.The request structure is clean with appropriate types and nullability.
src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs (1)
10-10: LGTM! Query follows established pattern.The query structure is consistent with other queries in the module. Input validation should be handled at the endpoint or handler level.
src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj (1)
45-45: The project reference at line 45 is correct and does not need to be changed.The verification shows that only
./tests/MeAjudaAi.Shared.Tests/MeAjudaAi.Shared.Tests.csprojexists in the repository. The suggested alternative path toMeAjudaAi.Shared.Tests.Base.csprojdoes not exist. The namespaceMeAjudaAi.Shared.Tests.Baselikely exists within the referenced project, not as a separate project file. The current reference is correct.Likely an incorrect or invalid review comment.
src/Modules/Providers/Application/DTOs/Requests/AddDocumentRequest.cs (1)
9-19: DTO aligns with existing request conventions.Extends the shared
Requestcontract, keepsNumbernon-null via default, and surfaces the enum cleanly—nothing else to change.src/Modules/Providers/Domain/Events/ProviderProfileUpdatedDomainEvent.cs (1)
13-19: Event payload looks complete.Captures aggregate identity, versioning, and updated fields including actor metadata—consistent with other domain events.
src/Modules/Providers/Application/Queries/GetProvidersQuery.cs (1)
16-22: Query surface matches handler expectations.Carries pagination and optional filters with nullable primitives—fits the CQRS contract without introducing null-risk.
src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs (1)
9-12: Command payload is appropriately scoped.
Guidplus optional actor aligns with the handler’s soft-delete workflow—no gaps spotted.
src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs
Show resolved
Hide resolved
src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs
Show resolved
Hide resolved
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs
Show resolved
Hide resolved
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Aspire/MeAjudaAi.ServiceDefaults/MeAjudaAi.ServiceDefaults.csproj (1)
26-26: Fix the typo in the Shared project reference path.The path contains "MeAjudai.Shared" but should be "MeAjudaAi.Shared" (missing "A" in "Ajuda"). This typo will cause a build failure.
Apply this diff:
- <ProjectReference Include="..\..\Shared\MeAjudai.Shared\MeAjudaAi.Shared.csproj" /> + <ProjectReference Include="..\..\Shared\MeAjudaAi.Shared\MeAjudaAi.Shared.csproj" />
♻️ Duplicate comments (28)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs (1)
18-29: Error message sanitization concern (see past review).This was previously flagged: returning
ex.Messagedirectly in the failure result can expose internal implementation details or sensitive information to clients. The past review recommends using a generic error message for clients while maintaining detailed logging.src/Modules/Providers/Infrastructure/MeAjudaAi.Modules.Providers.Infrastructure.csproj (1)
18-18: Fix the typo in the Shared project reference path.The path contains "MeAjudai.Shared" but should be "MeAjudaAi.Shared" (missing "A" in "Ajuda"). This typo will cause a build failure.
Apply this diff:
- <ProjectReference Include="..\..\..\Shared\MeAjudai.Shared\MeAjudaAi.Shared.csproj" /> + <ProjectReference Include="..\..\..\Shared\MeAjudaAi.Shared\MeAjudaAi.Shared.csproj" />src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs (1)
41-44: Stop returning internal exception messages to clients.
Result.Failureis exposingex.Message, leaking internal implementation details to API consumers. Swap in a stable, generic error message while keeping the detailed exception in the logs.Apply this diff:
- return Result<ProviderDto?>.Failure($"Error getting provider: {ex.Message}"); + return Result<ProviderDto?>.Failure("Error retrieving provider by user ID");src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
119-128: Don’t block on async factories in tests.Calling
.Resulton theValueTaskrisks deadlocks/hangs when the factory performs async work. Make the helper itself async andawaitthe factory.Apply this diff:
- public Task<T> GetOrCreateAsync<T>(string key, Func<CancellationToken, ValueTask<T>> factory, TimeSpan? expiration = null, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken cancellationToken = default) + public async Task<T> GetOrCreateAsync<T>(string key, Func<CancellationToken, ValueTask<T>> factory, TimeSpan? expiration = null, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken cancellationToken = default) { if (_cache.TryGetValue(key, out var existingValue)) { - return Task.FromResult((T)existingValue); + return (T)existingValue; } - var newValue = factory(cancellationToken).AsTask().Result; - _cache[key] = newValue!; - return Task.FromResult(newValue); + var newValue = await factory(cancellationToken); + _cache[key] = newValue!; + return newValue!; }src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs (1)
215-244: Enforce uniqueness for provider documents at the database level.
Documentonly has(ProviderId, Id)as key; concurrent inserts with the sameDocumentTypeslip through, breaking the domain invariant. Add a unique index on(ProviderId, DocumentType)inProviderConfigurationand regenerate the migration/snapshot.Suggested addition inside the
Documentsowned type:b1.ToTable("Document", "providers"); + b1.HasIndex("ProviderId", "DocumentType") + .IsUnique(); + b1.WithOwner() .HasForeignKey("ProviderId");src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
146-152: Don’t mask handler failures as “false”.Both existence checks turn any handler failure (e.g., DB outage) into
Success(false), misleading callers into believing the provider/user doesn’t exist. Propagate the failure instead.Apply this diff:
var result = await GetProviderByIdAsync(providerId, cancellationToken); - return result.Match( - onSuccess: provider => Result<bool>.Success(provider != null), - onFailure: _ => Result<bool>.Success(false) // Em caso de erro, assume que não existe - ); + return result.Match( + onSuccess: provider => Result<bool>.Success(provider != null), + onFailure: error => Result<bool>.Failure(error) + );var result = await GetProviderByUserIdAsync(userId, cancellationToken); - return result.Match( - onSuccess: provider => Result<bool>.Success(provider != null), - onFailure: _ => Result<bool>.Success(false) // Em caso de erro, assume que não é provider - ); + return result.Match( + onSuccess: provider => Result<bool>.Success(provider != null), + onFailure: error => Result<bool>.Failure(error) + );Also applies to: 155-161
src/Modules/Providers/Application/MeAjudaAi.Modules.Providers.Application.csproj (1)
19-19: Fix the typo in the Shared project reference path.The path contains "MeAjudai.Shared" but should be "MeAjudaAi.Shared" (missing "A"). This will cause a build failure.
Apply this diff:
- <ProjectReference Include="..\..\..\Shared\MeAjudai.Shared\MeAjudaAi.Shared.csproj" /> + <ProjectReference Include="..\..\..\Shared\MeAjudaAi.Shared\MeAjudaAi.Shared.csproj" />src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (1)
56-60: Avoid exposing internal error details in failure messages.Returning the full exception message (
ex.Message) to clients can expose internal implementation details, stack traces, or sensitive information.Consider returning a generic error message:
catch (Exception ex) { logger.LogError(ex, "Error adding qualification to provider {ProviderId}", command.ProviderId); - return Result<ProviderDto>.Failure($"Error adding qualification: {ex.Message}"); + return Result<ProviderDto>.Failure("An error occurred while adding the qualification. Please try again."); }src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (1)
47-51: Avoid exposing internal error details in failure messages.The catch block returns
ex.Messageto clients, which can leak internal implementation details or sensitive information. This issue was previously flagged and remains unresolved.Apply this diff to use a generic error message:
catch (Exception ex) { logger.LogError(ex, "Error deleting provider {ProviderId}", command.ProviderId); - return Result.Failure($"Error deleting provider: {ex.Message}"); + return Result.Failure("An error occurred while deleting the provider. Please try again."); }src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs (1)
35-40: Exception message exposure already flagged.The issue of exposing internal exception messages on line 38 has already been raised in a previous review. Please address the earlier feedback.
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (1)
27-28: Guard implicit Guid conversion against nullProviderId.If any caller runs
Guid id = provider?.Id;and the navigation resolves tonull, the implicit operator will dereferenceproviderIdand throw aNullReferenceException. Adding a null guard keeps the conversion safe and surfaces a clear argument error instead of an unexpected crash.Apply this diff:
- public static implicit operator Guid(ProviderId providerId) => providerId.Value; + public static implicit operator Guid(ProviderId? providerId) => + providerId?.Value ?? throw new ArgumentNullException(nameof(providerId));src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs (1)
34-39: Sanitize error messages returned to clients.Returning
ex.Messagedirectly could expose internal details. The exception should be logged but the client should receive a generic error message.Apply this diff:
catch (Exception ex) { logger.LogError(ex, "Error retrieving providers by IDs: {ProviderIds}", string.Join(", ", query.ProviderIds)); - return Result<IReadOnlyList<ProviderDto>>.Failure($"Error getting providers by IDs: {ex.Message}"); + return Result<IReadOnlyList<ProviderDto>>.Failure("Error retrieving providers by IDs"); }src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs (1)
27-28: Avoid exposing internal exception details in handler failures.Returning
ex.Messageto consumers can leak stack traces or database details. The detailed information is already logged, so return a generic error message instead.Apply this diff:
- return Result<IReadOnlyList<ProviderDto>>.Failure($"Error getting providers: {ex.Message}"); + return Result<IReadOnlyList<ProviderDto>>.Failure("Error getting providers.");src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (1)
37-40: Performance issue: Case-insensitive comparison prevents index usage.Using
ToLower()on both database column and filter prevents SQL Server from using indexes efficiently and may force client-side evaluation.Consider using EF Core's database functions:
- query = query.Where(p => p.Name.ToLower().Contains(nameFilter.ToLower())); + query = query.Where(p => EF.Functions.Like(p.Name, $"%{nameFilter}%"));Or, if using EF Core 5+ with a case-insensitive collation:
- query = query.Where(p => p.Name.ToLower().Contains(nameFilter.ToLower())); + query = query.Where(p => p.Name.Contains(nameFilter, StringComparison.OrdinalIgnoreCase));src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
50-51: Do not expose internal exception details to callers.Returning
ex.Messageleaks internal details that could expose sensitive information or implementation specifics. Keep detailed errors in logs only.Apply this diff:
logger.LogError(ex, "Error adding document to provider {ProviderId}", command.ProviderId); - return Result<ProviderDto>.Failure($"Error adding document: {ex.Message}"); + return Result<ProviderDto>.Failure("Error adding document.");src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs (1)
43-47: Do not expose internal exception details to callers.Returning
ex.Messageexposes internal implementation details (database errors, validation messages, etc.) to API consumers. Log the full exception but return a generic error message.Apply this diff:
logger.LogError(ex, "Error updating provider profile {ProviderId}", command.ProviderId); - return Result<ProviderDto>.Failure($"Error updating provider profile: {ex.Message}"); + return Result<ProviderDto>.Failure("Error updating provider profile.");src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (1)
47-50: Do not expose exception details to the client.The catch block currently returns
ex.Messagewhich may leak internal implementation details. This issue was already flagged in a previous review.src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (1)
1-2: Missing DTO namespace import.The types
BusinessProfileDto,ContactInfoDto, andAddressDtoused on lines 29-34 may not resolve without an explicit import. This issue was already flagged in a previous review.src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs (1)
52-67: Reintroduce database cleanup before arranging data.Without
await CleanupDatabase();, this test leaks providers from earlier tests, causing inconsistent counts (e.g., twoIndividualrows afterGetProvidersAsync_WithValidFilters). Call the cleanup helper at the start to restore isolation.Apply this diff:
public async Task GetProvidersAsync_WithTypeFilter_ShouldReturnOnlyMatchingType() { // Arrange + await CleanupDatabase(); // Garantir isolamento var queryService = GetService<IProviderQueryService>();src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
65-68: Return a sanitized failure message.
Result.Failure($"Error creating provider: {ex.Message}")leaks internal error details to clients. Keep the structured log, but return a user-safe string instead.Apply this diff:
catch (Exception ex) { logger.LogError(ex, "Error creating provider for user {UserId}", command.UserId); - return Result<ProviderDto>.Failure($"Error creating provider: {ex.Message}"); + return Result<ProviderDto>.Failure("Unable to create provider at this time. Please try again later."); }src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs (1)
84-89: Guard against accessingresult.Valueon failure.If the command fails,
Result.Valuethrows and turns intended 4xx responses into 500s. Branch onresult.IsSuccessbefore reading the value.Apply this diff:
- return Handle(result, "GetProviderById", new { id = result.Value?.Id }); + if (!result.IsSuccess || result.Value is not { } provider) + { + return Handle(result); + } + + return Handle(result, "GetProviderById", new { id = provider.Id });src/Modules/Providers/Domain/ValueObjects/Document.cs (1)
26-37: Normalize document numbers before validation/storage.
Number = number.Trim();preserves formatting, so"12345678909"and"123.456.789-09"survive as different values even though validation treats them equal. Normalize CPF/CNPJ to digits-only (and reuse for validation) before assigning/storing to avoid duplicate entries slipping through formatting differences.Apply this diff:
- Number = number.Trim(); - DocumentType = documentType; - - if (!IsValid()) - throw new ArgumentException($"Documento do tipo {documentType} com número {number} é inválido", nameof(number)); + var normalizedNumber = NormalizeNumber(number, documentType); + + if (string.IsNullOrWhiteSpace(normalizedNumber)) + throw new ArgumentException("Número do documento não pode ser vazio", nameof(number)); + + Number = normalizedNumber; + DocumentType = documentType; + + if (!IsValid()) + throw new ArgumentException($"Documento do tipo {documentType} com número {normalizedNumber} é inválido", nameof(number)); } + + private static string NormalizeNumber(string number, EDocumentType documentType) + { + var trimmed = number.Trim(); + + return documentType switch + { + EDocumentType.CPF or EDocumentType.CNPJ => new string(trimmed.Where(char.IsDigit).ToArray()), + _ => trimmed + }; + }src/Modules/Providers/Domain/ValueObjects/Qualification.cs (1)
52-57: Keep nullable date semantics in equality
GetEqualityComponentsstill normalizes null dates toDateTime.MinValue, so a realMinValuebecomes indistinguishable from “no date supplied”, breaking value-based equality and hash codes. Emit the nullable values as-is instead.(learn.microsoft.com)- yield return IssueDate ?? DateTime.MinValue; - yield return ExpirationDate ?? DateTime.MinValue; + yield return IssueDate; + yield return ExpirationDate;src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs (1)
79-84: Return ProblemDetails for 400 responses
The endpoint documentsProblemDetails, yet the guards emit plain textBadRequestbodies. Switch toTypedResults.Problemso payloads match the contract and benefit from the platform’s RFC 9457 support.(learn.microsoft.com)- if (page < 1) - return Results.BadRequest("Page must be greater than 0"); - - if (pageSize < 1 || pageSize > 100) - return Results.BadRequest("PageSize must be between 1 and 100"); + if (page < 1) + return TypedResults.Problem( + detail: "Page must be greater than 0", + statusCode: StatusCodes.Status400BadRequest); + + if (pageSize < 1 || pageSize > 100) + return TypedResults.Problem( + detail: "PageSize must be between 1 and 100", + statusCode: StatusCodes.Status400BadRequest);src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs (1)
25-28: Do not leak internal exception messages
Bubblingex.Messageto callers exposes implementation details and can reveal sensitive data. Log the exception, but return a generic failure text to the API surface.(medium.com)- logger.LogError(ex, "Error getting providers by verification status {Status}", query.Status); - return Result<IReadOnlyList<ProviderDto>>.Failure($"Error getting providers: {ex.Message}"); + logger.LogError(ex, "Error getting providers by verification status {Status}", query.Status); + return Result<IReadOnlyList<ProviderDto>>.Failure("An unexpected error occurred while retrieving providers.");src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
113-130: Null-guard DTO inputs before mapping
ToDomaindereferencesdto,dto.ContactInfo, anddto.PrimaryAddresswithout validation. A missing payload turns into an NRE instead of a clear argument error. Guard the inputs up front.public static BusinessProfile ToDomain(this BusinessProfileDto dto) { + ArgumentNullException.ThrowIfNull(dto); + ArgumentNullException.ThrowIfNull(dto.ContactInfo); + ArgumentNullException.ThrowIfNull(dto.PrimaryAddress); + return new BusinessProfile( dto.LegalName, new ContactInfo(dto.ContactInfo.Email, dto.ContactInfo.PhoneNumber, dto.ContactInfo.Website),src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
103-118: Replace unsupported EF Core cleanup calls
DatabaseFacadenever exposedExecuteSqlAsync, so these DELETE/TRUNCATE helpers fail to compile (the last review already flagged this). Switch toExecuteSqlRawAsyncto execute raw SQL safely.- await dbContext.Database.ExecuteSqlAsync($"DELETE FROM providers.\"Qualification\";"); - await dbContext.Database.ExecuteSqlAsync($"DELETE FROM providers.\"Document\";"); - await dbContext.Database.ExecuteSqlAsync($"DELETE FROM providers.providers;"); + await dbContext.Database.ExecuteSqlRawAsync(@"DELETE FROM providers.""Qualification"";"); + await dbContext.Database.ExecuteSqlRawAsync(@"DELETE FROM providers.""Document"";"); + await dbContext.Database.ExecuteSqlRawAsync(@"DELETE FROM providers.providers;"); @@ - await dbContext.Database.ExecuteSqlAsync($"TRUNCATE TABLE providers.\"Qualification\", providers.\"Document\", providers.providers RESTART IDENTITY CASCADE;"); + await dbContext.Database.ExecuteSqlRawAsync( + @"TRUNCATE TABLE providers.""Qualification"", providers.""Document"", providers.providers RESTART IDENTITY CASCADE;");src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (1)
154-178: Remove method not declared in the interface and add explicit ordering.This method has two issues:
GetPagedAsyncis implemented but not declared inIProviderRepository, violating the interface contract.- As previously flagged, the pagination query lacks explicit ordering, which can produce nondeterministic results.
First, add this method to the interface:
// In IProviderRepository.cs +/// <summary> +/// Busca prestadores de serviços com paginação. +/// </summary> +/// <param name="page">Número da página</param> +/// <param name="pageSize">Tamanho da página</param> +/// <param name="cancellationToken">Token de cancelamento</param> +/// <returns>Resultado paginado de prestadores de serviços</returns> +Task<PagedResult<Provider>> GetPagedAsync(int page, int pageSize, CancellationToken cancellationToken = default);Then, add explicit ordering before pagination:
var providers = await context.Providers .Include(p => p.Documents) .Include(p => p.Qualifications) .Where(p => !p.IsDeleted) + .OrderBy(p => p.Id.Value) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(cancellationToken);
🧹 Nitpick comments (6)
infrastructure/database/modules/providers/01-permissions.sql (1)
12-12: Consider settingsearch_pathformeajudaai_app_roleas well.Line 12 sets
search_pathonly forproviders_role. Ifmeajudaai_app_rolealso needs to query the providers schema without explicit schema qualification, consider adding:ALTER ROLE meajudaai_app_role SET search_path = providers, public;src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs (1)
9-12: Consider using the ProviderId value object for type safety.The command uses
Guiddirectly forProviderId. Consider using theProviderIdvalue object (fromsrc/Modules/Providers/Domain/ValueObjects/ProviderId.cs) instead for stronger type safety and domain alignment, as it provides validation and prevents empty GUIDs.Apply this diff if you want to use the value object:
+using MeAjudaAi.Modules.Providers.Domain.ValueObjects; + namespace MeAjudaAi.Modules.Providers.Application.Commands; /// <summary> /// Comando para exclusão lógica do prestador de serviços. /// </summary> public sealed record DeleteProviderCommand( - Guid ProviderId, + ProviderId ProviderId, string? DeletedBy = null ) : Command<Result>;src/Aspire/MeAjudaAi.AppHost/Program.cs (1)
129-129: Add space before the OR operator for readability.The expression is missing a space before
||, making it harder to parse visually.Apply this diff:
- options.ExposeHttpEndpoint = !bool.TryParse(exposeHttpStr, out var exposeResult)||exposeResult; + options.ExposeHttpEndpoint = !bool.TryParse(exposeHttpStr, out var exposeResult) || exposeResult;src/Modules/Providers/Application/Queries/GetProvidersQuery.cs (1)
16-22: Consider using enum types for Type and VerificationStatus filters.The
TypeandVerificationStatusparameters are defined asint?, which reduces type safety. Using dedicated enum types would provide better compile-time checking, improved IntelliSense support, and clearer intent.If enum types exist in the domain (e.g.,
EProviderType,EVerificationStatus), consider this refactor:public record GetProvidersQuery( int Page, int PageSize, string? Name = null, - int? Type = null, - int? VerificationStatus = null + EProviderType? Type = null, + EVerificationStatus? VerificationStatus = null ) : Query<Result<PagedResult<ProviderDto>>>;src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs (1)
11-189: LGTM! Comprehensive and well-structured entity configuration.The configuration properly maps the Provider aggregate with all its owned entities, applies appropriate constraints, and creates useful indexes. The UserId unique index correctly enforces one provider per user.
Optional: The enum conversions (lines 29-35, 37-43, 138-143) could use the simpler
HasConversion<string>()syntax introduced in recent EF Core versions, but the explicit approach is perfectly valid and more readable.src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (1)
75-94: Consider culture-invariant string comparison.The
ToLower()approach works but is not culture-invariant. For better consistency and correctness, consider usingEF.Functions.Collate()or case-insensitive comparison.Apply this diff to use culture-invariant comparison:
public async Task<IReadOnlyList<Provider>> GetByCityAsync(string city, CancellationToken cancellationToken = default) { return await context.Providers .Include(p => p.Documents) .Include(p => p.Qualifications) - .Where(p => !p.IsDeleted && p.BusinessProfile.PrimaryAddress.City.ToLower() == city.ToLower()) + .Where(p => !p.IsDeleted && EF.Functions.Collate(p.BusinessProfile.PrimaryAddress.City, "SQL_Latin1_General_CP1_CI_AS") == EF.Functions.Collate(city, "SQL_Latin1_General_CP1_CI_AS")) .ToListAsync(cancellationToken); } public async Task<IReadOnlyList<Provider>> GetByStateAsync(string state, CancellationToken cancellationToken = default) { return await context.Providers .Include(p => p.Documents) .Include(p => p.Qualifications) - .Where(p => !p.IsDeleted && p.BusinessProfile.PrimaryAddress.State.ToLower() == state.ToLower()) + .Where(p => !p.IsDeleted && EF.Functions.Collate(p.BusinessProfile.PrimaryAddress.State, "SQL_Latin1_General_CP1_CI_AS") == EF.Functions.Collate(state, "SQL_Latin1_General_CP1_CI_AS")) .ToListAsync(cancellationToken); }Or simply use
StringComparison.OrdinalIgnoreCaseif EF Core translates it properly in your version.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
Directory.Packages.props(1 hunks)MeAjudaAi.sln(3 hunks)infrastructure/database/modules/providers/01-permissions.sql(1 hunks)nuget.config(1 hunks)src/Aspire/MeAjudaAi.AppHost/MeAjudaAi.AppHost.csproj(2 hunks)src/Aspire/MeAjudaAi.AppHost/Program.cs(2 hunks)src/Aspire/MeAjudaAi.ServiceDefaults/MeAjudaAi.ServiceDefaults.csproj(2 hunks)src/Bootstrapper/MeAjudaAi.ApiService/MeAjudaAi.ApiService.csproj(1 hunks)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs(3 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/DeleteProviderEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByIdEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByUserIdEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByCityEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByStateEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByTypeEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersByVerificationStatusEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/RemoveDocumentEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProvidersModuleEndpoints.cs(1 hunks)src/Modules/Providers/API/Extensions.cs(1 hunks)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj(1 hunks)src/Modules/Providers/Application/Commands/AddDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/AddQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/CreateProviderCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/UpdateProviderProfileCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs(1 hunks)src/Modules/Providers/Application/DTOs/ProviderDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/AddDocumentRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateVerificationStatusRequest.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Mappers/ProviderMapper.cs(1 hunks)src/Modules/Providers/Application/MeAjudaAi.Modules.Providers.Application.csproj(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByIdsQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersQuery.cs(1 hunks)src/Modules/Providers/Application/Services/IProviderQueryService.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Domain/Entities/Provider.cs(1 hunks)src/Modules/Providers/Domain/Enums/EDocumentType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EVerificationStatus.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDeletedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderProfileUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderRegisteredDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderVerificationStatusUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs(1 hunks)src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj(1 hunks)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Address.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Document.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Qualification.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/MeAjudaAi.Modules.Providers.Infrastructure.csproj(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.Designer.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs(1 hunks)src/Modules/Providers/Tests/Builders/ProviderBuilder.cs(1 hunks)src/Modules/Providers/Tests/GlobalTestConfiguration.cs(1 hunks)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs(1 hunks)src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs(1 hunks)
⛔ Files not processed due to max files limit (31)
- src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/DeleteProviderCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByIdQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByUserIdQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
- src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs
- src/Modules/Providers/Tests/Unit/Domain/ValueObjects/DocumentTests.cs
- src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs
- src/Modules/Users/API/MeAjudaAi.Modules.Users.API.csproj
- src/Modules/Users/Application/MeAjudaAi.Modules.Users.Application.csproj
- src/Modules/Users/Infrastructure/MeAjudaAi.Modules.Users.Infrastructure.csproj
- src/Modules/Users/MeAjudaAi.Modules.Users.Tests/MeAjudaAi.Modules.Users.Tests.csproj
- src/Modules/Users/Tests/MeAjudaAi.Modules.Users.Tests.csproj
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/DTOs/ModuleProviderDto.cs
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/Enums.cs
- src/Shared/MeAjudai.Shared/Contracts/Modules/Providers/IProvidersModuleApi.cs
- src/Shared/MeAjudai.Shared/Extensions/DocumentExtensions.cs
- src/Shared/MeAjudai.Shared/MeAjudaAi.Shared.csproj
- tests/MeAjudaAi.ApiService.Tests/MeAjudaAi.ApiService.Tests.csproj
- tests/MeAjudaAi.Architecture.Tests/MeAjudaAi.Architecture.Tests.csproj
- tests/MeAjudaAi.Architecture.Tests/ModuleApiArchitectureTests.cs
🧰 Additional context used
🧬 Code graph analysis (28)
src/Modules/Providers/Application/Commands/AddQualificationCommand.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Commands/AddDocumentCommand.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Infrastructure/Extensions.cs (3)
src/Modules/Providers/Application/Extensions.cs (2)
Extensions(15-43)IServiceCollection(17-42)src/Shared/MeAjudai.Shared/Database/BaseDesignTimeDbContextFactory.cs (1)
IConfiguration(95-105)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
ProvidersDbContext(18-38)
src/Modules/Providers/Application/Commands/UpdateProviderProfileCommand.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)BusinessProfile(113-131)ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Commands/DeleteProviderCommand.cs (1)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs (2)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/DTOs/ProviderDto.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (8)
ContactInfoDto(58-65)AddressDto(70-82)BusinessProfileDto(44-53)DocumentDto(87-93)QualificationDto(98-108)ProviderDto(15-31)BusinessProfile(113-131)IReadOnlyList(36-39)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
IReadOnlyList(36-39)
src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Domain/ValueObjects/Qualification.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Qualification(144-154)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)
src/Modules/Providers/Domain/ValueObjects/Address.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (2)
IEnumerable(44-51)ToString(53-54)
src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (4)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)BusinessProfile(113-131)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (12)
Task(22-22)Task(30-30)Task(37-37)Task(44-44)Task(54-54)Task(62-62)Task(70-70)Task(78-78)Task(86-86)Task(94-94)Task(102-104)Task(112-114)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (1)
IEnumerable(44-51)
src/Modules/Providers/Application/Extensions.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-43)IServiceCollection(20-42)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)IReadOnlyList(36-39)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
CreateProviderCommandHandler(21-71)
src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
BusinessProfile(113-131)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (5)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)IEnumerable(48-53)ToString(55-55)src/Modules/Providers/Domain/ValueObjects/Address.cs (5)
Address(8-82)Address(22-31)Address(33-66)IEnumerable(68-78)ToString(80-81)
src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Domain/Entities/Provider.cs (7)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-29)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(12-60)Document(20-24)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)src/Shared/MeAjudai.Shared/Domain/BaseEntity.cs (2)
AddDomainEvent(15-15)MarkAsUpdated(17-17)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs (3)
ProviderDomainException(12-30)ProviderDomainException(18-20)ProviderDomainException(27-29)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (2)
src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/MeAjudai.Shared/Time/UuidGenerator.cs (1)
UuidGenerator(8-33)
src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (6)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-342)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)IEnumerable(44-51)src/Modules/Providers/Domain/ValueObjects/Address.cs (4)
IEnumerable(68-78)Address(8-82)Address(22-31)Address(33-66)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (4)
IEnumerable(48-53)ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/ValueObjects/Document.cs (3)
IEnumerable(53-57)Document(12-60)Document(20-24)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (4)
IEnumerable(50-58)Qualification(8-62)Qualification(20-23)Qualification(25-46)
src/Modules/Providers/Domain/ValueObjects/Document.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Document(136-139)src/Shared/MeAjudai.Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/MeAjudai.Shared/Extensions/DocumentExtensions.cs (2)
IsValidCpf(13-30)IsValidCnpj(35-52)
src/Modules/Providers/Application/Commands/CreateProviderCommand.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)BusinessProfile(113-131)ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)
src/Bootstrapper/MeAjudaAi.ApiService/MeAjudaAi.ApiService.csproj
Outdated
Show resolved
Hide resolved
src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs
Show resolved
Hide resolved
src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs
Show resolved
Hide resolved
src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (9)
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (1)
56-60: Consider distinguishing validation errors from unexpected exceptions.Currently, domain validation errors (e.g., empty qualification name, invalid dates from the
Qualificationconstructor, or business rule violations fromProvider.AddQualification) are caught and returned with the same generic message as unexpected exceptions. Users would benefit from seeing specific validation messages.Consider this pattern:
catch (Exception ex) { logger.LogError(ex, "Error adding qualification to provider {ProviderId}", command.ProviderId); - return Result<ProviderDto>.Failure("An error occurred while adding the qualification"); + + // Surface validation and business rule violations to the caller + return ex switch + { + ArgumentException argEx => Result<ProviderDto>.Failure(argEx.Message), + ProviderDomainException domainEx => Result<ProviderDto>.Failure(domainEx.Message), + _ => Result<ProviderDto>.Failure("An error occurred while adding the qualification") + }; }This approach provides actionable feedback for validation errors while still protecting against exposing unexpected exception details.
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (1)
47-51: Consider differentiating domain exceptions for better UX.While the current generic error handling is secure and consistent with the codebase, you could optionally provide more specific feedback for known domain exceptions (e.g., "Qualification not found", "Cannot modify deleted provider") while keeping generic messages for unexpected exceptions. This would improve the user experience by giving actionable feedback.
Example approach:
catch (Exception ex) { - logger.LogError(ex, "Error removing qualification from provider {ProviderId}", command.ProviderId); - return Result<ProviderDto>.Failure("An error occurred while removing the qualification"); + logger.LogError(ex, "Error removing qualification from provider {ProviderId}", command.ProviderId); + + return ex switch + { + ProviderDomainException domainEx => Result<ProviderDto>.Failure(domainEx.Message), + ArgumentException => Result<ProviderDto>.Failure("Invalid qualification name provided"), + _ => Result<ProviderDto>.Failure("An error occurred while removing the qualification") + }; }Note: This pattern could be applied consistently across all command handlers for a uniform approach.
src/Aspire/MeAjudaAi.AppHost/Program.cs (1)
185-185: Unused variable assignment.The
apiServicevariable is assigned but never used in the method. If you don't need to reference this variable later, consider keeping the discarded assignment (_) for clarity.Apply this diff if the variable is not needed:
- var apiService = builder.AddProject<Projects.MeAjudaAi_ApiService>("apiservice") + _ = builder.AddProject<Projects.MeAjudaAi_ApiService>("apiservice")src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs (1)
99-100: Consider using the inherited BadRequest helper for consistency.The null check properly addresses the previous review concern. However, the code uses
Results.BadRequest("Request body is required")instead of the inheritedBadRequest(string message)helper from BaseEndpoint, which wraps the response in a standardizedResponse<object>format for API consistency.Apply this diff to use the inherited helper:
- if (request is null) - return Results.BadRequest("Request body is required"); + if (request is null) + return BadRequest("Request body is required");Note: UpdateProviderProfileEndpoint uses the same
Results.BadRequestpattern, so this is consistent within the module but could be unified across all endpoints for better response format consistency.src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs (1)
97-111: Consider capturing the admin's identity for audit trailing.For administrative actions like verification status updates, it's important to track who performed the change. The endpoint should extract the current admin's user ID from HttpContext and include it in the command.
Apply this diff to add audit trailing:
private static async Task<IResult> UpdateVerificationStatusAsync( Guid id, [FromBody] UpdateVerificationStatusRequest request, + HttpContext context, ICommandDispatcher commandDispatcher, CancellationToken cancellationToken) { if (request is null) return Results.BadRequest("Request body is required"); - var command = request.ToCommand(id); + var updatedBy = GetUserId(context); + var command = request.ToCommand(id, updatedBy); var result = await commandDispatcher.SendAsync<UpdateVerificationStatusCommand, Result<ProviderDto>>( command, cancellationToken); return Handle(result); }Note: This assumes
ToCommandcan accept an optionalupdatedByparameter. If the request mapper extension doesn't support this, you may need to update the command directly after creation:var command = request.ToCommand(id) with { UpdatedBy = GetUserId(context) };src/Modules/Providers/Domain/Enums/EProviderType.cs (1)
13-14: Consider adding XML documentation for enum members.The
Nonemember has documentation, butIndividualandCompanylack XML comments. Adding brief descriptions would improve API discoverability and maintain consistency.+ /// <summary> + /// Prestador individual (pessoa física) + /// </summary> Individual = 1, + /// <summary> + /// Empresa prestadora (pessoa jurídica) + /// </summary> Company = 2src/Modules/Providers/Domain/Enums/EVerificationStatus.cs (1)
13-17: Consider adding XML documentation for verification statuses.Only
Nonehas documentation. Adding descriptions for each status would clarify the verification workflow.+ /// <summary> + /// Aguardando verificação + /// </summary> Pending = 1, + /// <summary> + /// Verificação em andamento + /// </summary> InProgress = 2, + /// <summary> + /// Verificado com sucesso + /// </summary> Verified = 3, + /// <summary> + /// Verificação rejeitada + /// </summary> Rejected = 4, + /// <summary> + /// Verificação suspensa + /// </summary> Suspended = 5src/Modules/Providers/Domain/Enums/EDocumentType.cs (1)
13-18: Consider documenting document types for clarity.Adding descriptions would help developers unfamiliar with Brazilian document types understand each identifier.
+ /// <summary> + /// Cadastro de Pessoa Física (Brazilian individual taxpayer ID) + /// </summary> CPF = 1, + /// <summary> + /// Cadastro Nacional da Pessoa Jurídica (Brazilian company taxpayer ID) + /// </summary> CNPJ = 2, + /// <summary> + /// Registro Geral (Brazilian national ID card) + /// </summary> RG = 3, + /// <summary> + /// Carteira Nacional de Habilitação (Brazilian driver's license) + /// </summary> CNH = 4, + /// <summary> + /// Passaporte internacional + /// </summary> Passport = 5, + /// <summary> + /// Outro tipo de documento + /// </summary> Other = 99src/Modules/Providers/Infrastructure/Extensions.cs (1)
27-34: Consider rejecting whitespace-only connection strings too.
string.IsNullOrEmptylets a whitespace-only value slip through; switching tostring.IsNullOrWhiteSpacepreserves the diagnostics while preventing an unusable connection string from reaching Npgsql.- if (string.IsNullOrEmpty(connectionString)) + if (string.IsNullOrWhiteSpace(connectionString))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
Directory.Packages.props(2 hunks)MeAjudaAi.sln(2 hunks)nuget.config(1 hunks)src/Aspire/MeAjudaAi.AppHost/Program.cs(1 hunks)src/Bootstrapper/MeAjudaAi.ApiService/MeAjudaAi.ApiService.csproj(1 hunks)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs(3 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs(1 hunks)src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj(1 hunks)src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/ModuleProviderDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/GlobalSuppressions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Mappers/ProviderMapper.cs(1 hunks)src/Modules/Providers/Application/MeAjudaAi.Modules.Providers.Application.csproj(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Domain/Entities/Provider.cs(1 hunks)src/Modules/Providers/Domain/Enums/EDocumentType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EVerificationStatus.cs(1 hunks)src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj(1 hunks)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Document.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Qualification.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/MeAjudaAi.Modules.Providers.Infrastructure.csproj(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.Designer.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs(1 hunks)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs(1 hunks)src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs(1 hunks)src/Modules/Users/API/MeAjudaAi.Modules.Users.API.csproj(1 hunks)src/Modules/Users/Tests/MeAjudaAi.Modules.Users.Tests.csproj(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/Modules/Providers/Application/GlobalSuppressions.cs
🚧 Files skipped from review as they are similar to previous changes (19)
- src/Modules/Providers/API/MeAjudaAi.Modules.Providers.API.csproj
- src/Modules/Providers/Domain/MeAjudaAi.Modules.Providers.Domain.csproj
- src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs
- src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs
- src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs
- src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs
- src/Bootstrapper/MeAjudaAi.ApiService/Program.cs
- src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs
- src/Modules/Providers/Application/Mappers/ProviderMapper.cs
- src/Modules/Providers/Domain/Repositories/IProviderRepository.cs
- src/Modules/Providers/Application/Extensions.cs
- src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs
- src/Bootstrapper/MeAjudaAi.ApiService/MeAjudaAi.ApiService.csproj
- src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs
- src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj
- src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs
🧰 Additional context used
🧬 Code graph analysis (32)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs (2)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Infrastructure/Extensions.cs (5)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
ProvidersDbContext(18-38)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (1)
ProviderRepository(18-202)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (1)
ProviderQueryService(17-72)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs (4)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs (10)
Task(16-16)Task(21-21)Task(26-26)Task(31-31)Task(36-36)Task(41-41)Task(46-46)Task(51-51)Task(56-56)Task(61-61)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderBasicDto(265-276)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (4)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)ProviderMapper(10-158)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs (1)
Task(71-97)
src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs (1)
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
ProvidersIntegrationTestBase(15-122)
src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs (4)
src/Shared/Endpoints/BaseEndpoint.cs (1)
BaseEndpoint(10-130)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs (2)
Map(39-68)Task(90-104)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (4)
BusinessProfileDto(44-53)BusinessProfile(113-134)ContactInfoDto(58-65)AddressDto(70-82)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
BusinessProfile(85-91)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (1)
BusinessProfile(20-40)
src/Modules/Providers/Domain/ValueObjects/Qualification.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Qualification(147-157)src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Shared/Database/DapperConnection.cs (1)
GetConnectionString(11-22)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-50)IServiceCollection(20-49)tests/MeAjudaAi.Shared.Tests/Extensions/MockInfrastructureExtensions.cs (2)
IServiceCollection(18-42)IServiceCollection(79-110)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
TestInfrastructureOptions(20-41)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (4)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)BusinessProfile(113-134)src/Modules/Providers/API/Endpoints/ProviderAdmin/CreateProviderEndpoint.cs (1)
Task(79-95)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (14)
Task(22-22)Task(30-30)Task(37-37)Task(44-44)Task(54-54)Task(64-64)Task(72-72)Task(80-80)Task(88-88)Task(96-96)Task(104-104)Task(112-114)Task(122-124)Task(134-134)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Application/DTOs/ModuleProviderDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderDto(245-260)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs (1)
src/Shared/Endpoints/BaseEndpoint.cs (1)
BaseEndpoint(10-130)
src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
RemoveDocument(202-216)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (6)
ProviderDto(15-31)IReadOnlyList(36-39)BusinessProfile(113-134)BusinessProfileDto(44-53)ContactInfoDto(58-65)AddressDto(70-82)src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs (10)
Task(16-16)Task(21-21)Task(26-26)Task(31-31)Task(36-36)Task(41-41)Task(46-46)Task(51-51)Task(56-56)Task(61-61)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (2)
src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/Time/UuidGenerator.cs (1)
UuidGenerator(8-33)
src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (2)
ModuleProviderDto(245-260)ModuleProviderBasicDto(265-276)
src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Document(139-142)src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (6)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
RemoveQualification(243-260)
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)Qualification(147-157)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)src/Modules/Providers/Domain/Entities/Provider.cs (1)
AddQualification(222-237)
src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs (2)
src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.Designer.cs (1)
DbContext(14-309)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)
src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs (3)
src/Shared/Endpoints/BaseEndpoint.cs (1)
BaseEndpoint(10-130)src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs (2)
Map(38-71)Task(93-107)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateProviderProfileEndpoint.cs (2)
Map(39-68)Task(90-104)
src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.Designer.cs (2)
src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs (1)
DbContext(13-306)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.cs (1)
AddDocumentTypeUniqueConstraint(8-29)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Users/Application/Services/UsersModuleApi.cs (1)
ModuleApi(17-217)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (4)
ProviderDto(15-31)IReadOnlyList(36-39)BusinessProfile(113-134)Document(139-142)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
ProviderDto(263-298)src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs (10)
Task(16-16)Task(21-21)Task(26-26)Task(31-31)Task(36-36)Task(41-41)Task(46-46)Task(51-51)Task(56-56)Task(61-61)
src/Modules/Providers/Domain/Entities/Provider.cs (11)
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (1)
Provider(288-318)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (3)
Provider(359-367)BusinessProfile(20-40)IDateTimeProvider(13-18)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfile(113-134)Document(139-142)Qualification(147-157)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
BusinessProfile(85-91)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(13-97)Document(21-25)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)src/Shared/Domain/BaseEntity.cs (2)
AddDomainEvent(15-15)MarkAsUpdated(17-17)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs (3)
ProviderDomainException(12-30)ProviderDomainException(18-20)ProviderDomainException(27-29)
src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs (6)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs (1)
Task(97-111)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
Task(25-53)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
UpdateVerificationStatus(267-282)
src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (4)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
DateTime(81-81)src/Modules/Providers/Domain/Entities/Provider.cs (11)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)UpdateProfile(151-171)Delete(294-308)AddDocument(177-196)RemoveDocument(202-216)AddQualification(222-237)RemoveQualification(243-260)UpdateVerificationStatus(267-282)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(13-97)Document(21-25)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (3)
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (2)
ProvidersIntegrationTestBase(15-122)BusinessProfile(85-91)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (6)
UpdateProfile(151-171)Delete(294-308)Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs (2)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
🪛 GitHub Check: build-and-test
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
[warning] 92-92:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
[warning] 92-92:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
🪛 GitHub Check: Code Quality Checks
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
[warning] 92-92:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
[warning] 92-92:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Security Scan
🔇 Additional comments (40)
src/Modules/Users/API/MeAjudaAi.Modules.Users.API.csproj (1)
18-19: All verification checks passed—no issues found.The two new ProjectReferences follow the standardized clean architecture pattern used across modules. Both the Application and Shared projects exist at the specified paths, and the dependency structure matches the Providers module exactly (both API layers depend on Application, Infrastructure, and Shared). The relative paths are correct and consistent throughout the codebase.
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs (1)
11-30: LGTM! Previous security concern has been addressed.The handler implementation is clean and follows best practices. The past review comment regarding exposure of internal exception details has been properly addressed—line 28 now returns a generic error message while preserving detailed logging for internal debugging.
The implementation correctly:
- Uses structured logging for observability
- Propagates cancellation tokens
- Applies the Result pattern for error handling
- Maintains proper separation between repository access and DTO mapping
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs (1)
11-40: LGTM! Previous security concern has been addressed.The handler implementation is clean and follows best practices. The previous issue regarding exception message exposure (line 38) has been properly fixed—the code now returns a generic error message to clients while still logging the full exception details for debugging.
The implementation demonstrates:
- Proper dependency injection using primary constructor
- Appropriate logging at Debug and Error levels
- Correct cancellation token propagation
- Clean separation between logged details (for operators) and returned messages (for clients)
src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (2)
47-51: Previous security concern has been addressed.The exception handling now correctly returns a generic error message to the client while preserving detailed server-side logging. This prevents information leakage and matches the pattern used in AddDocumentCommandHandler.
17-52: Implementation looks solid.The handler follows established CQRS patterns, includes appropriate structured logging, handles errors safely, and is consistent with the existing AddDocumentCommandHandler. The domain-driven design with value objects and repository pattern is properly applied.
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs (2)
25-29: Great job addressing the previous security concern!The exception handling now correctly returns a generic error message to callers while still logging the full exception details for diagnostics. This prevents information leakage while maintaining observability.
11-23: LGTM! Clean CQRS implementation.The handler follows best practices:
- Primary constructor with clear dependencies
- Proper async/await with cancellation token support
- Appropriate logging at Information level for operational visibility
- Clean separation using the mapper extension method
The implementation correctly integrates with the repository layer and produces the expected DTO results.
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (3)
17-21: LGTM! Clean handler structure.The use of primary constructor syntax, sealed modifier, and proper dependency injection follows modern C# best practices.
27-54: LGTM! Solid implementation following CQRS patterns.The handler correctly:
- Retrieves and validates provider existence
- Constructs the Qualification value object with all required fields
- Delegates domain logic to the entity
- Persists changes through the repository
- Returns strongly-typed results
The flow matches established patterns in the codebase.
56-60: Previous issue resolved – generic error message now returned.Good work addressing the prior feedback about not exposing exception details in failure messages. The handler now returns a generic, user-safe error message while preserving full diagnostics in logs.
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (3)
1-21: LGTM! Clean handler structure.The class follows modern C# patterns with primary constructor, appropriate encapsulation (internal sealed), and minimal dependencies. Documentation is clear and complete.
25-45: LGTM! Solid command handling flow.The implementation correctly follows the established pattern from other handlers:
- Proper logging at appropriate levels
- ProviderId value object validation
- Null check with early return
- Domain method invocation
- Repository persistence
- CancellationToken propagation
47-51: Previous security concern addressed! ✅The exception handling now correctly returns a sanitized, client-safe error message while logging the full exception details. This matches the pattern established in
AddDocumentCommandHandlerand prevents leaking internal details.src/Aspire/MeAjudaAi.AppHost/Program.cs (1)
182-184: No action required—code correctly handles Aspire version compatibility.The
AddAzureContainerAppEnvironmentAPI was introduced in Aspire 9.2, but this project uses Aspire 9.0.0-preview.5.24523.6, which predates that release. The commented-out code with the TODO is appropriate—it documents a known limitation and serves as a placeholder for when the project upgrades to Aspire 9.2 or later. The code should remain as-is until the dependency is updated.src/Modules/Providers/API/Endpoints/ProviderAdmin/AddDocumentEndpoint.cs (2)
38-71: Excellent endpoint configuration and documentation.The Map method is well-structured with comprehensive OpenAPI documentation, proper authorization, and clear response contracts. The detailed description covering supported document types, validations, and use cases will be valuable for API consumers.
102-106: Clean CQRS implementation with proper command dispatch.The handler correctly converts the request to a command, dispatches it through the command dispatcher with appropriate typing, and handles the result using the inherited Handle method. The implementation follows the established patterns well.
src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs (1)
17-53: LGTM! Previous issues have been resolved.Both critical issues from the previous review have been successfully addressed:
- Line 41 now correctly passes
command.UpdatedByto the domain method for proper audit trailing- Line 51 returns a sanitized error message without exposing internal exception details
The handler implementation is clean, follows CQRS patterns, and properly uses structured logging throughout.
src/Modules/Providers/API/Endpoints/ProviderAdmin/UpdateVerificationStatusEndpoint.cs (1)
38-74: LGTM! Well-configured endpoint with comprehensive documentation.The endpoint configuration is excellent:
- RESTful route pattern with proper GUID constraint
- AdminOnly authorization is appropriate for this sensitive operation
- Comprehensive OpenAPI documentation explaining status types and their effects
- Proper HTTP status codes documented
src/Modules/Users/Tests/MeAjudaAi.Modules.Users.Tests.csproj (1)
13-13: xUnit v3 consolidation looks good.The consolidation of xunit.v3 as a primary reference aligns with the central package management strategy and xUnit v3 migration.
src/Modules/Providers/Infrastructure/MeAjudaAi.Modules.Providers.Infrastructure.csproj (2)
18-18: Shared project reference path is correct.The project reference path correctly points to
MeAjudaAi.Shared.csproj. The previous typo concern appears to be resolved.
23-25: Empty Migrations folder is expected for new EF Core projects.The empty folder placeholder for
Persistence\Migrations\is standard practice for EF Core Infrastructure projects before migrations are generated.nuget.config (2)
6-6: Verify "Highest" dependency version strategy.Setting
dependencyVersiontoHighestmeans NuGet will automatically select the highest available version when resolving dependencies, which may result in unexpected version bumps during package restore. Ensure this aligns with your versioning strategy, especially given the central package management inDirectory.Packages.props.
21-36: Remove this review comment — it is based on an incorrect understanding of NuGet's package source mapping behavior.NuGet evaluates packageSourceMapping patterns by specificity: exact ID patterns win first, then prefix (wildcard) patterns with longer prefixes take precedence over shorter prefixes, and the global "*" has the lowest precedence. The configuration shown does not have a conflict—the specific patterns like
Microsoft.EntityFrameworkCore.*will correctly take precedence over the global*pattern for nuget.org, so packages will resolve from the intended sources (dotnet-public or aspire) as configured.Likely an incorrect or invalid review comment.
src/Modules/Providers/Application/MeAjudaAi.Modules.Providers.Application.csproj (2)
19-19: Shared project reference path is correct.The project reference path correctly points to
MeAjudaAi.Shared.csproj. The previous typo concern appears to be resolved.
10-15: InternalsVisibleTo configuration looks good.The InternalsVisibleTo attributes are properly configured for test access and dynamic proxy generation (Moq/Castle.Core).
MeAjudaAi.sln (3)
62-83: Providers module structure is well-organized.The new Providers module follows the established modular architecture pattern with proper separation of concerns across Domain, Application, Infrastructure, API, and Tests layers.
89-93: Verify necessity of x64/x86 platform configurations.The addition of x64 and x86 platform configurations (in addition to Any CPU) increases the solution's complexity. For .NET 9 applications, "Any CPU" is typically sufficient unless there are specific native dependencies or platform-specific requirements.
Consider whether these additional platform configurations are necessary for your use case.
352-363: NestedProjects hierarchy is correctly structured.The Providers module hierarchy is properly nested within the Modules folder structure, maintaining consistency with the Users module organization.
Directory.Packages.props (3)
10-139: Excellent categorization and organization.The reorganization into clear categories (ASP.NET Core, Entity Framework Core, Microsoft Extensions, OpenTelemetry, Testing, etc.) significantly improves maintainability and makes version management much clearer.
53-53: Multiple preview and beta packages in use.Several packages are using preview or beta versions:
Microsoft.Extensions.ServiceDiscovery(9.0.1-preview.1.24557.2)Azure.Monitor.OpenTelemetry.AspNetCore(1.4.0-beta.1)OpenTelemetry.Instrumentation.EntityFrameworkCore(1.10.0-beta.1)Preview and beta packages may contain bugs, have breaking changes in future releases, and may not be supported in production environments. Ensure this aligns with your deployment strategy and consider the stability requirements for your application.
Also applies to: 56-56, 61-61
120-132: All Aspire packages are using preview versions.All Aspire.* packages are using version 9.0.0-preview.5.24523.6, which is a preview release. While this is expected for the Aspire framework at this stage, be aware that preview versions may have:
- Breaking changes in future releases
- Potential stability issues
- Limited production support
Ensure this aligns with your project timeline and deployment plans.
src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.cs (1)
13-18: LGTM! Unique constraint properly enforces document type invariant.The composite unique index on
(ProviderId, document_type)prevents duplicate document types per provider at the database level, addressing race conditions in concurrent operations.src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (1)
27-31: Null guard properly implemented.The implicit operator now includes
ArgumentNullException.ThrowIfNullat line 29, preventing null dereference issues raised in the previous review.src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (1)
43-47: Exception handling properly sanitized.Line 46 returns a generic error message instead of exposing
ex.Message, addressing the security concern from the previous review while maintaining detailed logging.src/Modules/Providers/Infrastructure/Persistence/Migrations/ProvidersDbContextModelSnapshot.cs (1)
240-241: Unique constraint reflected in model snapshot.The unique index on
(ProviderId, DocumentType)(lines 240-241) confirms that the database-level invariant requested in the previous review is now enforced.src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
65-69: Exception message properly sanitized.Line 68 returns a user-safe generic message rather than
ex.Message, resolving the information leakage concern from the previous review.src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
8-38: Immutability + required members look solid.The record keeps the cross-module contract explicit and immutable—exactly what we want for module boundaries.
src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (1)
53-55: Thanks for delegating to ProviderMapper.Centralizing the projection keeps DTO shape changes in one place and eliminates the inline duplication from earlier revisions.
src/Modules/Providers/Application/DTOs/ModuleProviderDto.cs (1)
8-58: Comprehensive module DTO reads cleanly.Required init-only members make the boundary payload explicit and immutable, which is perfect for cross-module contracts.
src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs (1)
12-126: Great job enforcing test isolation.Clearing the schema at the start of every scenario keeps the filter and pagination checks deterministic—even when the suite runs out of order.
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
133-143: Method not declared in interface.
GetAllAsyncis implemented but not declared inIProviderRepository, violating the interface contract. This issue was raised in a previous review.
188-192: Overload not declared in interface.
DeleteAsync(Provider provider, ...)is implemented but not declared inIProviderRepository. This issue was raised in a previous review.
🧹 Nitpick comments (2)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (1)
25-31: Consider making BusinessProfile nullable instead of providing empty defaults.The default initialization creates a
BusinessProfileDtowith mostly empty or null values. This can be problematic because:
- The object passes null checks but may fail domain validation due to empty required fields (like
LegalName,- It's unclear whether an empty
BusinessProfileis intentionally provided or accidentally omitted- The complex nested initialization with 8 parameters reduces readability
Consider one of these alternatives:
- Make the property nullable and default to
null:public BusinessProfileDto? BusinessProfile { get; init; }- Remove the default initialization entirely to make it required
- Ensure validation explicitly handles and rejects empty string values in required fields
This would make the intent clearer and produce better validation error messages.
Apply this diff to make BusinessProfile nullable:
- public BusinessProfileDto BusinessProfile { get; init; } = new( - string.Empty, - null, - null, - new ContactInfoDto(string.Empty, null, null), - new AddressDto(string.Empty, string.Empty, null, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty) - ); + public BusinessProfileDto? BusinessProfile { get; init; }src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
252-267: Consider clarifying document selection logic.Line 259 uses
FirstOrDefault()to select a document number. If a provider has multiple documents, this arbitrarily picks the first. If there's a concept of a "primary" document, consider selecting it explicitly; otherwise, this approach is acceptable for a basic DTO.Example of explicit primary document selection:
- Document = providerDto.Documents?.FirstOrDefault()?.Number ?? string.Empty, + Document = providerDto.Documents?.FirstOrDefault(d => d.IsPrimary)?.Number + ?? providerDto.Documents?.FirstOrDefault()?.Number + ?? string.Empty,(Only apply if a
IsPrimaryflag or similar exists in your domain model.)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (4)
BusinessProfileDto(44-53)BusinessProfile(113-134)ContactInfoDto(58-65)AddressDto(70-82)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
BusinessProfile(85-91)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (1)
BusinessProfile(20-40)
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (4)
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (2)
ProvidersIntegrationTestBase(15-122)BusinessProfile(85-91)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
Task(23-27)Task(32-38)Task(43-50)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (7)
UpdateProfile(151-171)Delete(294-308)Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)UpdateVerificationStatus(267-282)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-43)src/Modules/Users/Application/Services/UsersModuleApi.cs (1)
ModuleApi(17-217)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (4)
ProviderDto(15-31)IReadOnlyList(36-39)BusinessProfile(113-134)Document(139-142)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
ProviderDto(263-298)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (15)
Task(23-27)Task(32-38)Task(43-50)Task(55-61)Task(66-70)Task(75-82)Task(87-94)Task(99-108)Task(113-122)Task(127-131)Task(136-143)Task(148-170)Task(175-183)Task(188-192)Task(197-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
🔇 Additional comments (8)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (2)
1-3: Previous issue resolved.The missing DTO namespace import has been added, resolving the compilation issue from the previous review.
10-11: Previous issue resolved.The shadowing
UserIdproperty has been removed, ensuring the inheritedRequest.UserIdis used correctly.src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (2)
319-323: Verification status fix confirmed.The helper now correctly applies the requested verification status before returning the provider, resolving the issue flagged in the previous review.
23-283: Well-structured integration tests.The test suite comprehensively exercises repository operations with proper isolation (CleanupDatabase), scoped services, and clear AAA structure. Each test validates a specific scenario with appropriate assertions.
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
80-80: Case-insensitive comparison fixed.Previous issue resolved: now using
EF.Functions.ILikefor PostgreSQL-translatable case-insensitive filtering instead ofStringComparison.OrdinalIgnoreCase.Also applies to: 92-92
160-160: Pagination ordering added.Previous issue resolved: explicit
OrderBy(p => p.Id)ensures deterministic pagination results.src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (2)
81-107: Health check logic correctly implemented.The past review concern about false negatives has been resolved. The method now correctly treats both
Success(null)andFailure(404)as passing checks (lines 90-91, 93-94), while only flagging non-404 failures as infrastructure problems. This ensures health probes accurately reflect system availability.
171-187: Existence checks now correctly propagate failures.The past review concern about masking handler failures has been resolved. Both
ProviderExistsAsync(line 176) andUserIsProviderAsync(line 185) now propagate infrastructure failures instead of converting them toSuccess(false). Callers can now distinguish between "provider not found" and "database unavailable," preventing silent data corruption during outages.
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
147-154: Remove method not declared in the interface.
GetAllAsyncis implemented but not declared inIProviderRepository, violating the interface contract. This issue was flagged in a previous review and remains unresolved.Additionally, returning all providers without pagination poses a performance risk as the dataset grows. Consider either:
- Removing this method and directing callers to use
GetPagedAsync, or- Adding it to the interface with clear documentation about performance implications
If you need to add it to the interface:
// In IProviderRepository.cs /// <summary> /// Busca todos os prestadores de serviços não excluídos. /// </summary> /// <remarks> /// ⚠️ ATENÇÃO: Este método retorna todos os registros sem paginação. /// Use GetPagedAsync para grandes volumes de dados. /// </remarks> /// <param name="cancellationToken">Token de cancelamento</param> /// <returns>Lista de todos os prestadores de serviços não excluídos</returns> Task<IReadOnlyList<Provider>> GetAllAsync(CancellationToken cancellationToken = default);
199-203: Remove method not declared in the interface.The
DeleteAsync(Provider provider, CancellationToken)overload is implemented but not declared inIProviderRepository, violating the interface contract. This issue was flagged in a previous review and remains unresolved.Either add this method signature to the interface:
// In IProviderRepository.cs /// <summary> /// Remove um prestador de serviços do repositório (exclusão física). /// </summary> /// <param name="provider">Prestador a ser removido</param> /// <param name="cancellationToken">Token de cancelamento da operação</param> Task DeleteAsync(Provider provider, CancellationToken cancellationToken = default);Or remove this overload and update callers to use
DeleteAsync(ProviderId id, CancellationToken)instead.
🧹 Nitpick comments (3)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
43-50: Consider adding explicit ordering for deterministic results.While not as critical as pagination, returning unordered results can lead to non-deterministic behavior when the same query is executed multiple times. Consider adding an
OrderByclause for consistency.public async Task<IReadOnlyList<Provider>> GetByIdsAsync(IReadOnlyList<Guid> ids, CancellationToken cancellationToken = default) { return await context.Providers .Include(p => p.Documents) .Include(p => p.Qualifications) .Where(p => ids.Contains(p.Id.Value) && !p.IsDeleted) + .OrderBy(p => p.Id.Value) .ToListAsync(cancellationToken); }
86-154: Consider adding explicit ordering to list-returning queries.Several methods return lists without explicit ordering (
GetByCityAsync,GetByStateAsync,GetByVerificationStatusAsync,GetByTypeAsync,GetAllAsync), which can produce non-deterministic results across calls. While not as critical as pagination, adding consistent ordering improves predictability.Example for
GetByCityAsync:public async Task<IReadOnlyList<Provider>> GetByCityAsync(string city, CancellationToken cancellationToken = default) { return await context.Providers .Include(p => p.Documents) .Include(p => p.Qualifications) .Where(p => !p.IsDeleted && EF.Functions.ILike(p.BusinessProfile.PrimaryAddress.City, city)) + .OrderBy(p => p.Id.Value) .ToListAsync(cancellationToken); }Apply similar changes to other list-returning methods for consistency.
34-169: Consider extracting repeated Include logic.The eager loading pattern for
DocumentsandQualificationsis repeated in 11 methods. Consider creating a private helper method to reduce duplication and centralize the query configuration.+ private IQueryable<Provider> GetProvidersQuery() => + context.Providers + .Include(p => p.Documents) + .Include(p => p.Qualifications); + public async Task<Provider?> GetByIdAsync(ProviderId id, CancellationToken cancellationToken = default) { - return await context.Providers - .Include(p => p.Documents) - .Include(p => p.Qualifications) + return await GetProvidersQuery() .FirstOrDefaultAsync(p => p.Id == id && !p.IsDeleted, cancellationToken); }Apply this refactor to all query methods that use the same Include pattern.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByDocumentQuery.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs (2)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (13)
Task(33-77)Task(82-108)Task(110-121)Task(123-139)Task(141-151)Task(153-166)Task(168-180)Task(182-189)Task(191-198)Task(200-212)Task(214-226)Task(228-242)Task(244-258)
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (1)
Provider(288-326)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (4)
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
Task(22-22)Task(30-30)Task(37-37)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (1)
Provider(288-326)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Users/Application/Services/UsersModuleApi.cs (1)
ModuleApi(17-217)
src/Modules/Providers/Application/Extensions.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-50)IServiceCollection(20-49)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (1)
DeleteProviderCommandHandler(17-53)
src/Modules/Providers/Application/Queries/GetProviderByDocumentQuery.cs (1)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
ProviderDto(266-301)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (13)
Task(33-77)Task(82-108)Task(110-121)Task(123-139)Task(141-151)Task(153-166)Task(168-180)Task(182-189)Task(191-198)Task(200-212)Task(214-226)Task(228-242)Task(244-258)
🪛 GitHub Actions: MeAjudaAi CI Pipeline
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs
[error] 143-143: WHITESPACE: Fix whitespace formatting. Replace 10 characters with '\n\s\s\s\s\s\s\s\s'.
🪛 GitHub Check: build-and-test
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
[warning] 95-95:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
[warning] 95-95:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
🪛 GitHub Check: Code Quality Checks
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs
[warning] 95-95:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
[warning] 95-95:
Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
🔇 Additional comments (2)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
1-213: Great progress on addressing previous feedback!The pagination ordering issue (line 171) and the
StringComparison.OrdinalIgnoreCasetranslation problems (lines 91, 103) have been successfully resolved. The use ofEF.Functions.ILikefor case-insensitive comparisons and explicitOrderBybefore pagination are correct approaches.However, two interface contract violations from the previous review still remain and need attention.
159-181: Pagination implementation is now correct.The explicit
OrderBy(p => p.Id)at line 171 addresses the previous review feedback. The comparison works correctly due to the implicit operator inProviderId, though you could use.OrderBy(p => p.Id.Value)for explicitness if preferred.
src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 20
♻️ Duplicate comments (3)
src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderBasicDto.cs (1)
1-39: Critical: Duplicate DTO definition (see related file).This DTO duplicates
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cswith incompatible enum types. The duplication creates a fragile casting pattern between different enum types.One of these definitions should be removed to establish a single source of truth. Since this file is in
Shared.Contracts, it's the more appropriate location for inter-module communication. Consider keeping this version and removing the Providers.Application copy.src/Modules/Providers/Domain/ValueObjects/Qualification.cs (1)
50-58: Simplify nullable date equality components.Lines 55-56 use
typeof(DateTime?)as a sentinel for null dates, which unnecessarily complicates equality logic and could cause two Qualifications with different nullable date values to be considered equal if both are null (they'd share the same Type reference). The ValueObject base class acceptsIEnumerable<object>, and nullable values can be yielded directly.Apply this diff:
protected override IEnumerable<object> GetEqualityComponents() { yield return Name; yield return Description ?? string.Empty; yield return IssuingOrganization ?? string.Empty; - yield return (object?)IssueDate ?? typeof(DateTime?); - yield return (object?)ExpirationDate ?? typeof(DateTime?); + yield return IssueDate; + yield return ExpirationDate; yield return DocumentNumber ?? string.Empty; }src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
215-229: Add validation before enum casting to prevent silent data corruption.Line 220 casts
EProviderTypevia(int)typewithout validation. The Shared enum defines Cooperative (3) and Freelancer (4), but the Domain enum only has None, Individual, and Company. Casting unsupported values will produce invalid enum values, causing silent failures.Add enum validation:
public async Task<Result<IReadOnlyList<ModuleProviderBasicDto>>> GetProvidersByTypeAsync( EProviderType type, CancellationToken cancellationToken = default) { + // Validate the enum value is supported by the domain + if (!Enum.IsDefined(typeof(Modules.Providers.Domain.Enums.EProviderType), (int)type)) + { + return Result<IReadOnlyList<ModuleProviderBasicDto>>.Failure( + Error.Validation($"Provider type '{type}' is not supported by the domain")); + } + var domainType = (Modules.Providers.Domain.Enums.EProviderType)(int)type;
🧹 Nitpick comments (9)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
27-33: Harden the connection string guard
string.IsNullOrEmptylets whitespace-only values through, which still breakUseNpgsql. Preferstring.IsNullOrWhiteSpaceto catch that edge case up front.src/Modules/Providers/Application/Queries/GetProvidersQuery.cs (1)
16-22: Consider using enum types instead of nullable ints for Type and VerificationStatus.The
TypeandVerificationStatusparameters are defined asint?, which loses compile-time type safety. SinceEProviderTypeandEVerificationStatusenums exist in the domain, consider using them directly here to prevent invalid values and improve code clarity.Apply this diff:
public record GetProvidersQuery( int Page, int PageSize, string? Name = null, - int? Type = null, - int? VerificationStatus = null + EProviderType? Type = null, + EVerificationStatus? VerificationStatus = null ) : Query<Result<PagedResult<ProviderDto>>>;And add the necessary using:
using MeAjudaAi.Modules.Providers.Application.DTOs; +using MeAjudaAi.Modules.Providers.Domain.Enums; using MeAjudaAi.Shared.Contracts;src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (1)
25-25: Consider making BusinessProfile required instead of nullable.Since
BusinessProfileis essential for creating a provider (as evidenced by the domain validation inBusinessProfile.cs), consider using therequiredmodifier instead of allowing null. This moves validation to compile-time and aligns with the domain's invariants.Apply this diff:
- public BusinessProfileDto? BusinessProfile { get; init; } + public required BusinessProfileDto BusinessProfile { get; init; }src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs (1)
18-24: Replace invalid default initializer with required modifier.The default initializer creates a
BusinessProfileDtowith empty strings and nested empty objects that would fail domain validation (e.g., empty email, empty street). This creates an invalid state that will be rejected at the domain layer.Consider using the
requiredmodifier instead, which enforces that callers must provide a valid value and moves validation to compile-time.Apply this diff:
/// <summary> /// Perfil de negócio atualizado do prestador. /// </summary> - public BusinessProfileDto BusinessProfile { get; init; } = new( - string.Empty, - null, - null, - new ContactInfoDto(string.Empty, null, null), - new AddressDto(string.Empty, string.Empty, null, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty) - ); + public required BusinessProfileDto BusinessProfile { get; init; }src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs (2)
145-146: Use consistent table naming convention.The Documents collection is mapped to a table named
"Document"(singular), while the main entity uses"providers"(plural). This inconsistency can cause confusion. Consider using plural form for all table names.Apply this diff:
- doc.ToTable("Document", "providers"); + doc.ToTable("Documents", "providers");
151-176: Add explicit table configuration for Qualifications collection.The Qualifications owned collection lacks an explicit
ToTable()call and composite key configuration, unlike the Documents collection (lines 145-148). This inconsistency may lead to EF Core generating a default table name that doesn't align with your naming conventions.Add explicit table configuration after line 176:
qual.Property(q => q.DocumentNumber) .HasMaxLength(50) .HasColumnName("document_number"); + + qual.HasKey("ProviderId", "Id"); + qual.ToTable("Qualifications", "providers"); + qual.WithOwner().HasForeignKey("ProviderId"); });src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByIdQueryHandlerTests.cs (1)
35-53: Tighten the mock to the actual ProviderIdRight now both the setup and the verify rely on
It.IsAny<ProviderId>(), so the test would still pass if the handler ever stopped passing the query’s ID through. Please pin those expectations to the specificproviderIdgenerated in the arrange block so we’ll catch regressions where the wrong identifier is used.- _providerRepositoryMock - .Setup(r => r.GetByIdAsync(It.IsAny<ProviderId>(), It.IsAny<CancellationToken>())) + _providerRepositoryMock + .Setup(r => r.GetByIdAsync( + It.Is<ProviderId>(id => id.Value == providerId), + It.IsAny<CancellationToken>())) .ReturnsAsync(provider); … - _providerRepositoryMock.Verify( - r => r.GetByIdAsync(It.IsAny<ProviderId>(), It.IsAny<CancellationToken>()), + _providerRepositoryMock.Verify( + r => r.GetByIdAsync( + It.Is<ProviderId>(id => id.Value == providerId), + It.IsAny<CancellationToken>()), Times.Once);Same idea applies to the not-found test below.
src/Modules/Providers/Tests/Unit/Application/Commands/DeleteProviderCommandHandlerTests.cs (1)
42-67: Assert the clock abstraction is exercisedIf the handler ever stopped calling
IDateTimeProvider.CurrentDate(), this test would still pass. Add aVerifyon the mock (and optionally assertDeletedAt == fixedDate) so we lock in the expectation that deletions are timestamped via the abstraction._dateTimeProviderMock .Setup(d => d.CurrentDate()) .Returns(fixedDate); … _providerRepositoryMock.Verify( r => r.UpdateAsync(It.Is<Provider>(p => p.IsDeleted), It.IsAny<CancellationToken>()), Times.Once); + _dateTimeProviderMock.Verify(d => d.CurrentDate(), Times.Once); + provider.DeletedAt.Should().Be(fixedDate);src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
250-267: Consider formalizing primary document selection.Line 258-259 includes a TODO noting that taking the first document is temporary. This could lead to inconsistent behavior if document order changes.
Consider either:
- Adding a
IsPrimaryflag to the Document entity, or- Defining a consistent ordering rule (e.g., by DocumentType priority or creation date)
This can be deferred to a future iteration if the current behavior is acceptable.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
.editorconfig(1 hunks)src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs(1 hunks)src/Modules/Providers/API/Extensions.cs(1 hunks)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/Application/Commands/AddDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/AddQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs(1 hunks)src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs(1 hunks)src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/ModuleProviderDto.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/AddDocumentRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/UpdateVerificationStatusRequest.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/GlobalSuppressions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Mappers/ProviderMapper.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByDocumentQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByIdsQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs(1 hunks)src/Modules/Providers/Application/Queries/GetProvidersQuery.cs(1 hunks)src/Modules/Providers/Application/Services/IProviderQueryService.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Domain/Entities/Provider.cs(1 hunks)src/Modules/Providers/Domain/Enums/EDocumentType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Domain/Enums/EVerificationStatus.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDeletedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderDocumentRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderProfileUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationAddedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderQualificationRemovedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderRegisteredDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Events/ProviderVerificationStatusUpdatedDomainEvent.cs(1 hunks)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs(1 hunks)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Address.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Document.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs(1 hunks)src/Modules/Providers/Domain/ValueObjects/Qualification.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs(1 hunks)src/Modules/Providers/Tests/Builders/ProviderBuilder.cs(1 hunks)src/Modules/Providers/Tests/GlobalTestConfiguration.cs(1 hunks)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs(1 hunks)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs(1 hunks)src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/DeleteProviderCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByIdQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByUserIdQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/DocumentTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs(1 hunks)src/Shared/Authorization/EPermission.cs(1 hunks)src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderBasicDto.cs(1 hunks)src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderDto.cs(1 hunks)src/Shared/Contracts/Modules/Providers/EProviderType.cs(1 hunks)src/Shared/Contracts/Modules/Providers/EVerificationStatus.cs(1 hunks)src/Shared/Contracts/Modules/Providers/IProvidersModuleApi.cs(1 hunks)src/Shared/Extensions/DocumentExtensions.cs(1 hunks)
⛔ Files not processed due to max files limit (9)
- src/Shared/GlobalSuppressions.cs
- temp_test/Program.cs
- temp_test/TestBusinessProfile.csproj
- tests/MeAjudaAi.Architecture.Tests/ModuleApiArchitectureTests.cs
- tests/MeAjudaAi.E2E.Tests/Modules/Providers/ProvidersEndToEndTests.cs
- tests/MeAjudaAi.E2E.Tests/Modules/Providers/ProvidersModuleTests.cs
- tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs
- tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDbContextTests.cs
- tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs
🚧 Files skipped from review as they are similar to previous changes (34)
- src/Modules/Providers/Domain/Events/ProviderVerificationStatusUpdatedDomainEvent.cs
- src/Modules/Providers/Application/Queries/GetProviderByDocumentQuery.cs
- src/Modules/Providers/Application/Commands/RemoveQualificationCommand.cs
- src/Modules/Providers/Application/Commands/AddDocumentCommand.cs
- src/Modules/Providers/Domain/ValueObjects/Address.cs
- src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs
- src/Modules/Providers/Application/Queries/GetProviderByUserIdQuery.cs
- src/Modules/Providers/Application/GlobalSuppressions.cs
- src/Modules/Providers/Infrastructure/Persistence/Migrations/20251101130231_AddDocumentTypeUniqueConstraint.cs
- src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs
- src/Modules/Providers/Infrastructure/Persistence/Migrations/20251031190904_InitialCreate.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs
- src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProvidersEndpoint.cs
- src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs
- src/Modules/Providers/Domain/Events/ProviderDeletedDomainEvent.cs
- src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs
- src/Modules/Providers/Application/Commands/AddQualificationCommand.cs
- src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs
- src/Modules/Providers/Domain/Enums/EProviderType.cs
- src/Modules/Providers/Domain/Events/ProviderRegisteredDomainEvent.cs
- src/Modules/Providers/Application/Queries/GetProvidersByStateQuery.cs
- src/Modules/Providers/Tests/MeAjudaAi.Modules.Providers.Tests.csproj
- src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs
- src/Modules/Providers/Domain/Events/ProviderDocumentAddedDomainEvent.cs
- src/Modules/Providers/Domain/Events/ProviderQualificationAddedDomainEvent.cs
- src/Modules/Providers/Application/DTOs/ModuleProviderDto.cs
- src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs
- src/Modules/Providers/Domain/Enums/EVerificationStatus.cs
- src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs
- src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs
- src/Modules/Providers/Domain/Events/ProviderProfileUpdatedDomainEvent.cs
🧰 Additional context used
🧬 Code graph analysis (59)
src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (2)
src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Shared/Time/UuidGenerator.cs (1)
UuidGenerator(8-33)
src/Modules/Providers/Application/Queries/GetProvidersByIdsQuery.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
IReadOnlyList(36-39)
src/Modules/Providers/Application/Commands/RemoveDocumentCommand.cs (3)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
RemoveDocumentCommand(148-151)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderDto(250-267)
src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs (1)
UpdateProviderProfileCommandHandler(15-49)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)ContactInfoDto(58-65)AddressDto(70-82)
src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (6)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
RemoveDocumentCommand(148-151)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
RemoveDocument(202-216)
src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
BusinessProfile(113-134)src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (5)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)IEnumerable(48-53)ToString(55-55)src/Modules/Providers/Domain/ValueObjects/Address.cs (5)
Address(8-82)Address(22-31)Address(33-66)IEnumerable(68-78)ToString(80-81)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Shared/Database/DapperConnection.cs (1)
GetConnectionString(11-22)
src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
IReadOnlyList(36-39)
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (1)
RemoveQualificationCommandHandler(17-53)
src/Modules/Providers/Tests/Unit/Application/Commands/DeleteProviderCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (1)
DeleteProviderCommandHandler(17-53)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderBasicDto(272-283)
src/Modules/Providers/Application/Services/IProviderQueryService.cs (1)
tests/MeAjudaAi.Shared.Tests/Extensions/TestCancellationExtensions.cs (1)
CancellationToken(13-13)
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (1)
RemoveDocumentCommandHandler(17-53)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
RemoveDocumentCommand(148-151)
src/Modules/Providers/Application/Extensions.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-50)IServiceCollection(20-49)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (1)
GetProviderByIdQueryHandler(17-49)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (1)
DeleteProviderCommandHandler(17-53)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)BusinessProfile(113-134)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (13)
Task(22-22)Task(30-30)Task(37-37)Task(44-44)Task(54-54)Task(62-62)Task(70-70)Task(78-78)Task(86-86)Task(94-94)Task(102-102)Task(110-112)Task(120-122)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Application/Contracts/IProvidersModuleApi.cs (2)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (2)
ModuleProviderDto(250-267)ModuleProviderBasicDto(272-283)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
IReadOnlyList(36-39)
src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
CreateProviderCommandHandler(21-71)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)ContactInfoDto(58-65)AddressDto(70-82)
src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs (1)
UpdateVerificationStatusCommandHandler(17-54)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs (1)
GetProvidersByTypeQueryHandler(11-31)
src/Modules/Providers/Application/DTOs/Requests/UpdateProviderProfileRequest.cs (1)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (3)
BusinessProfileDto(44-53)ContactInfoDto(58-65)AddressDto(70-82)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs (1)
GetProvidersByStateQueryHandler(11-37)
src/Modules/Providers/Application/Queries/GetProviderByIdQuery.cs (3)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProviderByIdQuery(77-80)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Tests/GlobalTestConfiguration.cs (1)
tests/MeAjudaAi.Shared.Tests/GlobalTestConfiguration.cs (1)
SharedIntegrationTestFixture(30-44)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
ProviderDto(15-31)ProviderMapper(10-158)
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
RemoveQualification(243-260)
src/Modules/Providers/Application/Queries/GetProvidersByCityQuery.cs (2)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProvidersByCityQuery(97-100)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Infrastructure/Extensions.cs (5)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
ProvidersDbContext(18-38)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (1)
ProviderRepository(18-187)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (1)
ProviderQueryService(17-72)
src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs (5)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (1)
Provider(288-326)src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (2)
Provider(359-367)BusinessProfile(20-40)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
BusinessProfile(113-134)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByUserIdQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByUserIdQueryHandler.cs (1)
GetProviderByUserIdQueryHandler(16-47)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (13)
Task(33-77)Task(82-108)Task(110-119)Task(121-130)Task(132-142)Task(144-153)Task(155-167)Task(169-176)Task(178-185)Task(187-199)Task(201-213)Task(215-229)Task(231-245)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProviderByIdQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (1)
GetProviderByIdQueryHandler(17-49)
src/Modules/Providers/Application/Queries/GetProvidersByVerificationStatusQuery.cs (2)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProvidersByVerificationStatusQuery(127-130)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (1)
AddQualificationCommandHandler(17-62)
src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderBasicDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderBasicDto(272-283)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs (1)
GetProvidersByCityQueryHandler(16-41)
src/Shared/Contracts/Modules/Providers/IProvidersModuleApi.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (2)
ModuleProviderDto(250-267)ModuleProviderBasicDto(272-283)
src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
AddDocumentCommandHandler(17-54)
src/Modules/Providers/Application/Queries/GetProvidersByTypeQuery.cs (2)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProvidersByTypeQuery(117-120)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByCityQueryHandler.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)
src/Modules/Providers/Domain/Entities/Provider.cs (8)
src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (3)
Provider(359-367)BusinessProfile(20-40)IDateTimeProvider(13-18)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (3)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(13-97)Document(21-25)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)src/Shared/Domain/BaseEntity.cs (2)
AddDomainEvent(15-15)MarkAsUpdated(17-17)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (3)
ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/Exceptions/ProviderDomainException.cs (3)
ProviderDomainException(12-30)ProviderDomainException(18-20)ProviderDomainException(27-29)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs (1)
GetProvidersByVerificationStatusQueryHandler(11-31)
src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Qualification(147-157)src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
DateTime(81-81)
src/Modules/Providers/Application/Handlers/Commands/UpdateVerificationStatusCommandHandler.cs (4)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
UpdateVerificationStatus(267-282)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Users/Application/Services/UsersModuleApi.cs (1)
ModuleApi(17-217)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (4)
ProviderDto(15-31)IReadOnlyList(36-39)BusinessProfile(113-134)Document(139-142)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
ProviderDto(266-301)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-93)Task(98-104)Task(109-117)Task(122-130)Task(135-139)Task(144-164)Task(169-177)Task(182-186)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Tests/Builders/ProviderBuilder.cs (1)
src/Modules/Providers/Domain/Entities/Provider.cs (3)
AddDocument(177-196)AddQualification(222-237)UpdateVerificationStatus(267-282)
src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (4)
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (2)
ProvidersIntegrationTestBase(15-122)BusinessProfile(85-91)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
Task(31-35)Task(40-44)Task(49-55)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (7)
UpdateProfile(151-171)Delete(294-308)Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)UpdateVerificationStatus(267-282)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (6)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/ValueObjects/BusinessProfile.cs (4)
BusinessProfile(9-55)BusinessProfile(20-25)BusinessProfile(27-42)IEnumerable(44-51)src/Modules/Providers/Domain/ValueObjects/Address.cs (4)
IEnumerable(68-78)Address(8-82)Address(22-31)Address(33-66)src/Modules/Providers/Domain/ValueObjects/ContactInfo.cs (4)
IEnumerable(48-53)ContactInfo(8-56)ContactInfo(17-20)ContactInfo(22-33)src/Modules/Providers/Domain/ValueObjects/Document.cs (3)
IEnumerable(90-94)Document(13-97)Document(21-25)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (4)
IEnumerable(50-58)Qualification(8-62)Qualification(20-23)Qualification(25-46)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs (5)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProvidersByStateQuery(107-110)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
IReadOnlyList(36-39)ProviderDto(15-31)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (5)
Task(33-77)Task(82-108)Task(110-119)Task(121-130)Task(132-142)
src/Modules/Providers/Application/Commands/UpdateVerificationStatusCommand.cs (3)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
UpdateVerificationStatusCommand(64-70)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByIdQueryHandler.cs (6)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(15-44)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-50)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProviderByIdQuery(77-80)src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
ProviderDto(15-31)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (5)
Task(33-77)Task(82-108)Task(110-119)Task(121-130)Task(132-142)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByIdsQueryHandler.cs (1)
GetProvidersByIdsQueryHandler(11-41)
src/Modules/Providers/Tests/Integration/ProviderQueryServiceIntegrationTests.cs (1)
src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
ProvidersIntegrationTestBase(15-122)
src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (2)
src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
src/Modules/Providers/Application/DTOs/Requests/CreateProviderRequest.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (2)
BusinessProfileDto(44-53)BusinessProfile(113-134)src/Modules/Providers/Tests/Integration/ProvidersIntegrationTestBase.cs (1)
BusinessProfile(85-91)
src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
src/Modules/Providers/Application/Mappers/ProviderMapper.cs (1)
Document(139-142)src/Shared/Domain/ValueObject.cs (1)
ValueObject(3-32)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (4)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Tests/Integration/ProviderRepositoryIntegrationTests.cs (1)
Provider(288-326)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
Task(22-22)Task(30-30)Task(37-37)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
src/Modules/Providers/Tests/Unit/Domain/Entities/ProviderTests.cs (4)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
DateTime(81-81)src/Modules/Providers/Domain/Entities/Provider.cs (11)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)UpdateProfile(151-171)Delete(294-308)AddDocument(177-196)RemoveDocument(202-216)AddQualification(222-237)RemoveQualification(243-260)UpdateVerificationStatus(267-282)src/Modules/Providers/Domain/ValueObjects/Document.cs (2)
Document(13-97)Document(21-25)src/Modules/Providers/Domain/ValueObjects/Qualification.cs (3)
Qualification(8-62)Qualification(20-23)Qualification(25-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs
Outdated
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs
Outdated
Show resolved
Hide resolved
...roviders/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (3)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
1-40: Critical: Temporary duplicate DTO should not be merged.This file explicitly marks itself as temporary (line 7) and duplicates
ModuleProviderBasicDtoalready defined insrc/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderBasicDto.cs. As noted in the previous review, the two DTOs use incompatible enum types (Providers.Domain.Enumsvs.Shared.Contracts.Modules.Providersenums), forcing fragile enum casts inProvidersModuleApi.cs.Merging temporary code with acknowledged duplication introduces technical debt and maintenance risk. Before merging this PR, either:
- Resolve the namespace conflict and remove this temporary file, using only the shared contract DTO, or
- Create a tracking issue and provide a clear timeline for removal.
src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs (1)
179-208: Previous issue resolved.The test now correctly asserts the generic error message returned by the handler. The assertion at line 203 properly uses
Containto check for the expected error message, matching the handler's exception handling behavior.src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
215-229: Critical: Unsafe enum cast will fail for Cooperative and Freelancer types.Line 220 blindly casts the shared
EProviderTypeenum to the domain enum via(int)type. However, the shared enum defines five values (None=0, Individual=1, Company=2, Cooperative=3, Freelancer=4) while the domain enum only recognizes three (None, Individual, Company). Passing Cooperative or Freelancer will cast to invalid domain enum values, causing query errors or silent data corruption.Apply one of these fixes:
Option 1 (preferred): Add validation before casting
public async Task<Result<IReadOnlyList<ModuleProviderBasicDto>>> GetProvidersByTypeAsync( EProviderType type, CancellationToken cancellationToken = default) { - // Mapear o enum compartilhado para o enum do domínio - var domainType = (Modules.Providers.Domain.Enums.EProviderType)(int)type; + // Validate and map the shared enum to the domain enum + var domainType = type switch + { + EProviderType.None => Modules.Providers.Domain.Enums.EProviderType.None, + EProviderType.Individual => Modules.Providers.Domain.Enums.EProviderType.Individual, + EProviderType.Company => Modules.Providers.Domain.Enums.EProviderType.Company, + EProviderType.Cooperative or EProviderType.Freelancer => + throw new ArgumentException($"Provider type {type} is not yet supported in the domain layer", nameof(type)), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Invalid provider type") + }; var query = new GetProvidersByTypeQuery(domainType); var result = await getProvidersByTypeHandler.HandleAsync(query, cancellationToken);Option 2: Add Cooperative=3 and Freelancer=4 to the domain enum in
src/Modules/Providers/Domain/Enums/EProviderType.cs.Option 3: Remove Cooperative and Freelancer from the shared enum if they're not yet supported.
🧹 Nitpick comments (6)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
37-54: Consider extracting the DbContext removal logic into a helper method.The removal pattern is duplicated for both
UsersDbContextandProvidersDbContext. While functional, extracting this into a generic helper method would reduce duplication and make future additions easier.Example refactor:
+ // Helper to remove DbContext registrations + void RemoveDbContext<TContext>() where TContext : DbContext + { + var optionsDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<TContext>)); + if (optionsDescriptor != null) + services.Remove(optionsDescriptor); + + var contextDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(TContext)); + if (contextDescriptor != null) + services.Remove(contextDescriptor); + } + // Substitute database with test container - Remove all DbContext related services - var usersDbContextDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<UsersDbContext>)); - if (usersDbContextDescriptor != null) - services.Remove(usersDbContextDescriptor); - - var providersDbContextDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ProvidersDbContext>)); - if (providersDbContextDescriptor != null) - services.Remove(providersDbContextDescriptor); - - // Also remove the actual DbContext services if they exist - var usersDbContextService = services.SingleOrDefault(d => d.ServiceType == typeof(UsersDbContext)); - if (usersDbContextService != null) - services.Remove(usersDbContextService); - - var providersDbContextService = services.SingleOrDefault(d => d.ServiceType == typeof(ProvidersDbContext)); - if (providersDbContextService != null) - services.Remove(providersDbContextService); + RemoveDbContext<UsersDbContext>(); + RemoveDbContext<ProvidersDbContext>();src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (1)
167-193: Remove redundant test.This test duplicates the "SP" case already covered by the theory test
HandleAsync_WithDifferentStates_ShouldWorkat line 131. Consider removing this test to reduce redundancy.Apply this diff to remove the redundant test:
- [Fact] - public async Task HandleAsync_WithStateAbbreviation_ShouldWork() - { - // Arrange - var state = "SP"; - var providers = new List<Provider> - { - ProviderBuilder.Create().WithId(Guid.NewGuid()) - }; - - var query = new GetProvidersByStateQuery(state); - - _providerRepositoryMock - .Setup(r => r.GetByStateAsync(state, It.IsAny<CancellationToken>())) - .ReturnsAsync(providers); - - // Act - var result = await _handler.HandleAsync(query, CancellationToken.None); - - // Assert - result.IsSuccess.Should().BeTrue(); - result.Value.Should().HaveCount(1); - - _providerRepositoryMock.Verify( - r => r.GetByStateAsync(state, It.IsAny<CancellationToken>()), - Times.Once); - } -src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs (2)
72-82: Consider verifying nested DTO properties.The assertions validate top-level properties but don't verify that
BusinessProfile,ContactInfo, andAddressdetails are correctly mapped in the returned DTO. Additionally, you could verify thatGetByUserIdAsyncwas called as expected.Example enhancement:
result.Value.Type.Should().Be(command.Type); +result.Value.BusinessProfile.Should().NotBeNull(); +result.Value.BusinessProfile.LegalName.Should().Be(businessProfileDto.LegalName); +result.Value.BusinessProfile.ContactInfo.Email.Should().Be(businessProfileDto.ContactInfo.Email); _providerRepositoryMock.Verify( + r => r.GetByUserIdAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()), + Times.Once); +_providerRepositoryMock.Verify( r => r.AddAsync(It.IsAny<Provider>(), It.IsAny<CancellationToken>()), Times.Once);
33-52: Consider extracting repeated test data to a helper method.The
businessProfileDtosetup is duplicated across all four tests. Extracting this to a private helper method or test fixture would improve maintainability and reduce repetition.Example refactor:
private static BusinessProfileDto CreateTestBusinessProfile(string? website = "https://www.provider.com") { return new BusinessProfileDto( LegalName: "Test Company", FantasyName: null, Description: null, ContactInfo: new ContactInfoDto( Email: "test@provider.com", PhoneNumber: "+55 11 99999-9999", Website: website ), PrimaryAddress: new AddressDto( Street: "Test Street", Number: "123", Complement: null, Neighborhood: "Centro", City: "Test City", State: "TS", ZipCode: "12345-678", Country: "Brasil" ) ); }Then use:
var businessProfileDto = CreateTestBusinessProfile();orCreateTestBusinessProfile(website: null)in each test.Also applies to: 88-107, 136-155, 187-206
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs (1)
97-127: Consider documenting the implicit exception behavior.The test correctly expects the generic error message, which implies that
RemoveDocumentthrows an exception when the document doesn't exist. Adding a comment explaining this expected domain behavior would improve test clarity.Consider adding a comment like:
[Fact] public async Task HandleAsync_WhenDocumentNotFound_ShouldReturnFailureResult() { // Arrange var providerId = Guid.NewGuid(); - var provider = ProviderBuilder.Create().WithId(providerId); // Sem documentos + var provider = ProviderBuilder.Create().WithId(providerId); // Provider without documents - RemoveDocument will throwsrc/Modules/Providers/Application/Extensions.cs (1)
18-27: LGTM! DI registrations are correct.The service registrations properly wire the query handler and module API. Both registrations use appropriate scoped lifetimes for per-request operations.
Consider removing or clarifying the comment at line 20 ("Manual registration for GetProvidersQuery to test if it's assembly loading issue") if the assembly loading issue has been resolved, as it may confuse future maintainers about why this specific registration is "manual."
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs(1 hunks)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs(1 hunks)src/Shared/Authorization/AuthorizationExtensions.cs(1 hunks)src/Shared/Authorization/PermissionRequirement.cs(1 hunks)src/Shared/Authorization/RequirePermissionAttribute.cs(1 hunks)src/Shared/Contracts/Modules/Providers/EProviderType.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByCityQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryHandlerTests.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/UpdateVerificationStatusCommandHandlerTests.cs
🧰 Additional context used
🧬 Code graph analysis (17)
src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/AddQualificationCommandHandler.cs (1)
AddQualificationCommandHandler(17-62)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs (1)
Theory(56-66)
src/Shared/Authorization/AuthorizationExtensions.cs (1)
src/Shared/Authorization/PermissionExtensions.cs (1)
EPermission(42-56)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
tests/MeAjudaAi.Shared.Tests/Base/DatabaseTestBase.cs (1)
DbContextOptions(52-59)tests/MeAjudaAi.E2E.Tests/Base/E2ETestBase.cs (1)
DbContextOptions(268-274)
src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs (2)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (13)
Task(33-77)Task(82-108)Task(110-119)Task(121-130)Task(132-142)Task(144-153)Task(155-167)Task(169-176)Task(178-185)Task(187-199)Task(201-213)Task(215-229)Task(231-245)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
Task(22-22)Task(30-30)Task(37-37)
src/Modules/Providers/Application/Extensions.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-50)IServiceCollection(20-49)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (1)
GetProvidersQueryHandler(23-78)
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (1)
RemoveQualificationCommandHandler(17-53)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs (1)
Theory(56-66)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (3)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs (1)
GetProvidersByStateQueryHandler(11-37)src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (13)
Task(33-77)Task(82-108)Task(110-119)Task(121-130)Task(132-142)Task(144-153)Task(155-167)Task(169-176)Task(178-185)Task(187-199)Task(201-213)Task(215-229)Task(231-245)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProvidersByStateQuery(107-110)
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/RemoveDocumentCommandHandler.cs (1)
RemoveDocumentCommandHandler(17-53)
src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Commands/AddDocumentCommandHandler.cs (1)
AddDocumentCommandHandler(17-54)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
AddDocumentCommand(49-56)
src/Shared/Authorization/RequirePermissionAttribute.cs (1)
src/Shared/Authorization/PermissionExtensions.cs (1)
EPermission(42-56)
src/Shared/Authorization/PermissionRequirement.cs (1)
src/Shared/Authorization/PermissionExtensions.cs (1)
EPermission(42-56)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByTypeQueryHandler.cs (1)
GetProvidersByTypeQueryHandler(11-31)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByVerificationStatusQueryHandler.cs (1)
GetProvidersByVerificationStatusQueryHandler(11-31)
src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs (1)
UpdateProviderProfileCommandHandler(15-49)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderBasicDto(272-283)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(16-28)src/Modules/Users/Application/Services/UsersModuleApi.cs (1)
ModuleApi(17-217)src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs (1)
Task(29-63)
src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs (1)
src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
CreateProviderCommandHandler(21-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: build-and-test
- GitHub Check: Security Scan
🔇 Additional comments (48)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (3)
3-3: LGTM!The import is necessary for the ProvidersDbContext integration and follows the existing pattern.
62-66: LGTM!The
ProvidersDbContextregistration correctly mirrors theUsersDbContextpattern, using the shared test database connection and enabling sensitive data logging for debugging.
84-88: Verify that bypassing migrations in tests is intentional.The code uses
EnsureCreatedAsync()to initialize the database schema, which creates the schema directly from the EF Core model without running migrations. This means the integration tests won't validate that your actual migrations work correctly in production.If migration testing is important, consider using
Database.MigrateAsync()instead. However, if you're testing migrations separately or this approach aligns with your testing strategy, the current implementation is fine.src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (8)
11-22: LGTM!The test class setup is clean and follows standard unit testing patterns with proper mock initialization.
24-53: LGTM!The test correctly verifies the happy path scenario with multiple providers.
55-78: LGTM!Good edge case test for empty results.
80-101: LGTM!The error message assertion is correct and matches the handler implementation. The past review concern has been resolved.
103-128: LGTM!Good test for verifying the handler works with larger result sets.
130-165: LGTM!Good parameterized test covering multiple state abbreviations.
195-222: LGTM!Good test for verifying the handler works with full state names in addition to abbreviations.
224-246: LGTM!Good test verifying cancellation token propagation.
src/Modules/Providers/Tests/Unit/Application/Commands/UpdateProviderProfileCommandHandlerTests.cs (5)
12-26: LGTM! Clean test setup.The test class setup follows standard patterns with proper mock initialization and handler instantiation.
28-88: LGTM! Comprehensive happy path test.The test correctly validates the success case with appropriate assertions for both the result status and returned provider data, plus proper verification of repository interactions.
90-143: LGTM! Proper not-found scenario coverage.The test correctly validates the provider-not-found case with appropriate error message assertion and verification that no update is attempted.
145-201: LGTM! Validation edge cases covered.The parameterized test properly covers empty and whitespace name scenarios, with correct expectations that domain validation will throw and the handler will catch with a generic error message.
203-252: LGTM! Exception handling test is now correct.The test properly validates exception handling with the correct error message assertion. The previous issue flagged in past reviews (assertion expecting "Database error" in the message) appears to have been resolved, as the test now correctly expects only the generic error message that matches the handler's actual behavior.
src/Modules/Providers/Tests/Unit/Application/Commands/CreateProviderCommandHandlerTests.cs (5)
13-27: LGTM! Clean test setup.The test class setup is well-structured with appropriate mocks and trait annotations.
61-67: Previous critical issue has been resolved!The mock setup now correctly targets
GetByUserIdAsyncto match the handler implementation. The test logic is sound and properly exercises the success path.
116-118: LGTM! Duplicate provider check is correct.The test properly verifies that when a provider already exists, the handler returns a failure result without attempting to add a new provider.
164-170: Previous critical issue has been resolved!The mock setup now correctly targets
GetByUserIdAsyncto match the handler implementation. The exception handling test properly verifies the failure path.
215-217: Previous critical issue has been resolved!The mock setup now correctly targets
GetByUserIdAsyncto match the handler implementation. The parameterized test properly validates domain-level name constraints.src/Modules/Providers/Tests/Unit/Application/Commands/AddDocumentCommandHandlerTests.cs (6)
28-63: LGTM! Well-structured success path test.The test correctly validates the happy path scenario with proper mock setup, assertions, and verification of repository interactions.
65-94: LGTM! Correct provider not found handling.The test properly validates the failure scenario when a provider doesn't exist, with accurate error message assertion and verification that UpdateAsync is not called.
96-129: Previous issue fixed! Test now correctly validates invalid document handling.The error message assertion on line 120 now correctly expects "An error occurred while adding the document", matching the handler's actual error message. The parameterized test provides good coverage of invalid input scenarios.
131-156: Previous issue fixed! Exception handling test now correct.The assertion on line 151 has been corrected to match the handler's actual behavior. The handler logs the exception details but returns a generic error message, which the test now properly validates.
158-191: Previous issue fixed! Duplicate document test now correct.The assertion on line 182 has been corrected to expect "An error occurred while adding the document", matching the handler's error message. The test properly validates that adding duplicate document types is prevented.
1-192: Excellent work addressing all previous review feedback!All three error message assertion issues identified in the past review have been successfully resolved. The test suite now correctly validates the handler's behavior with assertions that match the actual error messages returned by
AddDocumentCommandHandler. The tests are well-structured, follow the AAA pattern, and provide comprehensive coverage of success, failure, and edge cases.src/Modules/Providers/Tests/Unit/Application/Commands/AddQualificationCommandHandlerTests.cs (5)
16-25: LGTM!The test setup follows standard testing patterns with appropriate mock initialization and handler instantiation.
27-66: LGTM!The test comprehensively validates the success scenario, including proper repository interactions and result state.
68-101: LGTM!The test correctly validates the provider-not-found scenario, including appropriate error message and repository interaction verification.
103-141: LGTM!The parameterized test correctly validates that invalid qualification data results in failure. The assertion at line 132 properly expects the generic error message that the handler returns when catching exceptions from domain validation.
143-177: LGTM!The test correctly validates the invalid dates scenario. The assertion at line 168 properly expects the generic error message returned by the handler when domain validation fails.
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveDocumentCommandHandlerTests.cs (5)
21-26: LGTM! Test setup is correct.The constructor properly initializes mocks and the handler under test.
28-65: LGTM! Valid command test is comprehensive.The test correctly validates the success path, including proper verification of repository interactions.
67-95: LGTM! Provider-not-found scenario is correctly tested.The test properly validates that when a provider doesn't exist, the handler returns the appropriate failure result and doesn't attempt to update.
129-153: LGTM! Previous issue has been resolved.The test now correctly asserts the sanitized error message without checking for the underlying exception details. This properly validates that the handler doesn't leak implementation details to clients.
155-195: LGTM! Good use of theory test for multiple document types.The parameterized test efficiently validates that both CPF and CNPJ documents can be removed successfully, with appropriate document numbers for each type.
src/Modules/Providers/Application/Handlers/Queries/GetProviderByDocumentQueryHandler.cs (4)
1-10: LGTM!The imports are appropriate and include all necessary dependencies for the query handler implementation.
11-22: LGTM!The class declaration follows modern C# patterns with primary constructor syntax, and the XML documentation clearly describes the handler's purpose and responsibilities.
33-43: Good PII protection, but consider correlation ID for observability.The normalization and removal of document values from logs appropriately addresses the GDPR/PII concerns from the previous review. However, the correlation ID logging suggested in the past review is not present.
Without correlation IDs, it will be difficult to trace a specific request through logs, especially when multiple searches happen concurrently. Consider adding correlation ID tracking either:
- By adding a
CorrelationIdproperty toGetProviderByDocumentQuery- Or by using ambient context (e.g., from HTTP headers via middleware)
Can you verify whether correlation ID tracking is handled at a higher level (e.g., middleware or logging configuration), or if it should be added to the query type?
45-62: LGTM!The repository interaction, result handling, and exception management are well-implemented:
- The normalized document is used for the query
- The not-found case appropriately returns a successful result with null
- Success case logs only the ProviderId (not PII)
- Exception handling provides a safe fallback without exposing sensitive information
src/Shared/Authorization/AuthorizationExtensions.cs (1)
50-58: LGTM! Policy filtering correctly excludes EPermission.None.The LINQ filter ensures that no authorization policy is created for
EPermission.None, which complements the runtime guards inRequirePermissionAttributeandPermissionRequirement. This creates a cohesive defense-in-depth approach.src/Shared/Authorization/PermissionRequirement.cs (1)
25-29: Add unit test to verify the EPermission.None guard throws ArgumentException.The guard implementation is correct, but test coverage is missing. Existing tests in
PermissionAuthorizationIntegrationTests.csandPermissionArchitectureTests.csdo not cover the constructor validation forEPermission.None. Add a unit test to verify thatnew PermissionRequirement(EPermission.None)throws the expectedArgumentException.src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByTypeQueryHandlerTests.cs (1)
11-195: LGTM! Comprehensive test coverage.The test suite thoroughly validates the handler behavior across multiple scenarios: parameterized valid types, empty results, exception handling, mixed types, cancellation token forwarding, and large result sets. All assertions correctly match the handler's behavior, including the error message "An error occurred while retrieving providers" for exceptions.
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByVerificationStatusQueryHandlerTests.cs (1)
87-108: LGTM! Error assertion now matches handler behavior.The assertion has been correctly fixed to match the handler's actual error message "An error occurred while retrieving providers" as indicated in the past review comments.
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (3)
82-108: LGTM! Health check properly handles 404 as success.The basic operations test now correctly treats a 404 response (lines 94-95) as a passing check, distinguishing infrastructure readiness from missing data. This resolves the false-negative availability issue flagged in past reviews.
110-119: LGTM! Properly returns nullable result.The method correctly returns
Result<ModuleProviderDto?>and treats a missing provider as a successful null result rather than a failure, enabling callers to distinguish "not found" from infrastructure errors.
169-185: LGTM! Errors are now properly propagated.Both
ProviderExistsAsync(lines 169-176) andUserIsProviderAsync(lines 178-185) now correctly propagate handler failures via theMatchpattern, ensuring callers see real errors instead of silent false negatives.
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs
Show resolved
Hide resolved
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (1)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
1-40: Critical: Resolve DTO duplication before merge.As flagged in the previous review and acknowledged by the TEMP comment on line 7, this DTO duplicates
src/Shared/Contracts/Modules/Providers/DTOs/ModuleProviderBasicDto.cswith incompatible enum types. This creates fragile cross-module communication and breaks type safety.Since this PR introduces the Providers module, now is the ideal time to establish the correct architecture. Remove this file and consolidate on the shared contract DTO to ensure type-safe inter-module communication.
🧹 Nitpick comments (9)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (2)
103-128: LGTM!Test effectively validates handling of large result sets.
Consider verifying whether the explicit
(Provider)cast on line 109 is necessary. IfProviderBuilder.Create().WithId()already returns aProvider, the cast can be removed for cleaner code.
167-222: LGTM!Both tests validate important scenarios—state abbreviations and full state names.
The
HandleAsync_WithStateAbbreviation_ShouldWorktest (lines 167-193) duplicates coverage already provided by the theory testHandleAsync_WithDifferentStates_ShouldWork(which includes "SP"). You could optionally remove this test to reduce duplication, as the theory test already validates abbreviation handling.src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (1)
109-118: Consider reducing the visibility of NoOpClaimsTransformation.The
NoOpClaimsTransformationclass is declared aspublic, but it appears to be used only within the test authentication setup in this file. If this class is not intended for external use, consider making itinternalto reduce the API surface and prevent unintended usage.Apply this diff if the class is only needed internally:
-/// <summary> -/// No-op implementation of IClaimsTransformation for cases where minimal transformation is needed -/// </summary> -public class NoOpClaimsTransformation : IClaimsTransformation +/// <summary> +/// No-op implementation of IClaimsTransformation for cases where minimal transformation is needed +/// </summary> +internal class NoOpClaimsTransformation : IClaimsTransformation { public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { return Task.FromResult(principal); } }src/Modules/Providers/Infrastructure/Extensions.cs (1)
60-63: Consider environment-specific sensitive data logging configuration.Line 63 disables sensitive data logging globally with
.EnableSensitiveDataLogging(false). While appropriate for production, this might hinder debugging in development and test environments. Consider making this environment-aware.Apply this diff to enable sensitive data logging in test environments:
+ var isTestEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Testing" || + Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") == "Testing"; + options.UseNpgsql(connectionString, npgsqlOptions => { npgsqlOptions.MigrationsAssembly(typeof(ProvidersDbContext).Assembly.FullName); npgsqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", "providers"); // PERFORMANCE: Timeout mais longo para permitir criação do banco de dados npgsqlOptions.CommandTimeout(60); }) .UseSnakeCaseNamingConvention() // Configurações consistentes para evitar problemas com compiled queries .EnableServiceProviderCaching() - .EnableSensitiveDataLogging(false); + .EnableSensitiveDataLogging(isTestEnvironment); });tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs (1)
49-57: Simplify conditional assertion logic.The conditional logic that checks for 500 errors and either fails or passes is unnecessarily complex. Use standard assertions for expected status codes instead.
- // Para comparação - vamos ver se funciona agora - if (response.StatusCode == HttpStatusCode.InternalServerError) - { - Assert.Fail($"Providers endpoint still returns 500. Content: {content}"); - } - else - { - Assert.True(true, $"Providers endpoint working! Status: {response.StatusCode}"); - } + // Verify that the endpoint returns a successful status code + Assert.True(response.IsSuccessStatusCode, + $"Providers endpoint should return success status, but got {response.StatusCode}. Content: {content}");tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (2)
129-132: Overly permissive status code assertions weaken test validation.Lines 129-132 accept four different status codes (NotFound, OK, Unauthorized, Forbidden), making the assertion too broad to catch regressions. While it's reasonable to accept 404 for non-existent resources, accepting authentication/authorization errors (401/403) suggests the test isn't properly authenticated.
Since the test configures admin authentication (line 120), it should expect either 200 or 404, not 401/403.
// Assert - // Provider pode não existir (404) ou retornar dados (200) - // O importante é que não seja erro 500 - Assert.True(response.StatusCode == System.Net.HttpStatusCode.NotFound || - response.StatusCode == System.Net.HttpStatusCode.OK || - response.StatusCode == System.Net.HttpStatusCode.Unauthorized || - response.StatusCode == System.Net.HttpStatusCode.Forbidden); + // Provider may not exist (404) or return data (200) + Assert.True(response.StatusCode == System.Net.HttpStatusCode.NotFound || + response.StatusCode == System.Net.HttpStatusCode.OK, + $"Expected 200 or 404, but got {response.StatusCode}");
187-216: Consider more specific assertions for endpoint health checks.The test only verifies that endpoints don't return 500 errors (line 208), but doesn't validate response structure or authentication. This might miss issues where endpoints return unexpected 4xx errors due to misconfiguration.
Consider adding assertions for expected status codes (e.g., 200 for authenticated admin requests) or at minimum logging the actual status to aid debugging.
The current implementation with logging (lines 211-214) is acceptable for a smoke test, but could be strengthened:
// O importante é que não seja erro 500 (erro de servidor) Assert.NotEqual(System.Net.HttpStatusCode.InternalServerError, response.StatusCode); + + // For admin requests, we should get success or expected client errors, not auth failures + Assert.True(response.IsSuccessStatusCode || + response.StatusCode == System.Net.HttpStatusCode.NotFound, + $"Endpoint {endpoint} returned unexpected status {response.StatusCode}"); // Log do status para debugging se necessário if (!response.IsSuccessStatusCode)tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs (1)
45-55: Minor: Simplify boolean flag initialization.The
tableExistsvariable is initialized totrue(line 45) but is always reassigned in the try-catch block. While the current logic works, initializing tofalseand only setting totrueon success would be more intuitive.// Act: Verifica se as tabelas existem tentando uma query simples - var tableExists = true; + var tableExists = false; try { var count = await dbContext.Providers.CountAsync(); testOutput.WriteLine($"✅ Providers table exists, current count: {count}"); + tableExists = true; } catch (Exception ex) { - tableExists = false; testOutput.WriteLine($"❌ Error accessing Providers table: {ex.Message}"); }tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs (1)
62-92: Fragile reflection-based service enumeration.Lines 73-74 use reflection to access a
Servicesproperty on theIServiceProvider, assuming it will returnIEnumerable<ServiceDescriptor>. This approach is brittle and depends on internal implementation details that may not exist in all DI container implementations.Consider one of these alternatives:
Option 1: Remove this test if the specific enumeration of query handlers isn't critical for diagnostics.
Option 2: Test specific handlers individually (similar to lines 30-39) rather than trying to enumerate all registrations:
[Fact] -public void Should_List_All_Registered_QueryHandlers() +public void Should_Have_Key_QueryHandlers_Registered() { - // Arrange - var serviceProvider = Services; - - // Act - Get all IQueryHandler registrations - var queryHandlerType = typeof(IQueryHandler<,>); - var registeredServices = serviceProvider.GetServices<object>(); - - // Get all services that implement any IQueryHandler interface - var allServices = Services.GetType() - .GetProperty("Services")?.GetValue(Services) as IEnumerable<ServiceDescriptor>; - - if (allServices != null) + // Test specific key query handlers + var keyHandlers = new[] { - var queryHandlers = allServices - .Where(s => s.ServiceType.IsGenericType && - s.ServiceType.GetGenericTypeDefinition() == queryHandlerType) - .ToList(); - - testOutput.WriteLine($"Registered QueryHandlers count: {queryHandlers.Count}"); - - foreach (var handler in queryHandlers) - { - testOutput.WriteLine($"- {handler.ServiceType.Name}: {handler.ImplementationType?.Name}"); - } - - queryHandlers.Should().NotBeEmpty("At least some query handlers should be registered"); + typeof(IQueryHandler<GetProvidersQuery, Result<PagedResult<ProviderDto>>>), + typeof(IQueryHandler<GetProviderByIdQuery, Result<ProviderDto?>>), + typeof(IQueryHandler<GetProviderByUserIdQuery, Result<ProviderDto?>>) + }; + + foreach (var handlerType in keyHandlers) + { + var handler = Services.GetService(handlerType); + testOutput.WriteLine($"{handlerType.Name}: {handler != null}"); + handler.Should().NotBeNull($"{handlerType.Name} should be registered"); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs(3 hunks)src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs(1 hunks)src/Modules/Providers/Application/Extensions.cs(1 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs(1 hunks)src/Shared/Authorization/PermissionRequirement.cs(1 hunks)src/Shared/Authorization/RequirePermissionAttribute.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs(4 hunks)tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/ProvidersSchemaDebugTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs(1 hunks)tests/MeAjudaAi.Shared.Tests/Unit/Authorization/RequirePermissionAttributeTests.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/Shared/Authorization/RequirePermissionAttribute.cs
- src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
🧰 Additional context used
🧬 Code graph analysis (15)
src/Modules/Providers/Infrastructure/Extensions.cs (6)
src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContext.cs (1)
ProvidersDbContext(18-38)src/Shared/Database/DapperConnection.cs (1)
GetConnectionString(11-22)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (1)
ProviderRepository(18-207)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (1)
ProviderQueryService(17-72)
src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (3)
src/Shared/Constants/AuthConstants.cs (1)
Claims(26-45)src/Bootstrapper/MeAjudaAi.ApiService/Extensions/EnvironmentSpecificExtensions.cs (4)
TestAuthenticationSchemeOptions(195-206)TestAuthenticationHandler(211-234)TestAuthenticationHandler(213-216)Task(218-233)src/Bootstrapper/MeAjudaAi.ApiService/Handlers/SelfOrAdminHandler.cs (1)
Task(9-51)
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs (3)
src/Shared/Constants/ApiEndpoints.cs (1)
System(35-40)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-154)src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (1)
Task(114-117)
tests/MeAjudaAi.Shared.Tests/Unit/Authorization/RequirePermissionAttributeTests.cs (3)
src/Shared/Authorization/RequirePermissionAttribute.cs (1)
RequirePermissionAttribute(27-34)src/Shared/Authorization/PermissionRequirement.cs (2)
PermissionRequirement(9-33)PermissionRequirement(26-32)src/Shared/Authorization/Permission.cs (1)
Permission(9-50)
tests/MeAjudaAi.Integration.Tests/ProvidersSchemaDebugTest.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-74)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-154)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (3)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-154)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-98)Task(103-114)Task(119-132)Task(137-150)Task(155-159)Task(164-184)Task(189-197)Task(202-206)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
ConfigurableTestAuthenticationHandler(13-77)ConfigureAdmin(60-63)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-74)tests/MeAjudaAi.E2E.Tests/Base/E2ETestBase.cs (1)
DbContextOptions(268-274)tests/MeAjudaAi.Shared.Tests/Base/DatabaseTestBase.cs (1)
DbContextOptions(52-59)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (1)
ConfigureLogging(41-74)
src/Shared/Authorization/PermissionRequirement.cs (1)
src/Shared/Authorization/PermissionExtensions.cs (1)
EPermission(42-56)
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs (3)
src/Modules/Providers/Application/Handlers/Commands/RemoveQualificationCommandHandler.cs (1)
RemoveQualificationCommandHandler(17-53)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-98)Task(103-114)Task(119-132)Task(137-150)Task(155-159)Task(164-184)Task(189-197)Task(202-206)src/Modules/Providers/Tests/Unit/Domain/ValueObjects/QualificationTests.cs (1)
Theory(56-66)
tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs (3)
src/Modules/Providers/Application/Extensions.cs (1)
Extensions(16-46)src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-74)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-154)
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (2)
src/Modules/Providers/Application/Handlers/Queries/GetProvidersByStateQueryHandler.cs (1)
GetProvidersByStateQueryHandler(11-37)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-98)Task(103-114)Task(119-132)Task(137-150)Task(155-159)Task(164-184)Task(189-197)Task(202-206)
src/Modules/Providers/Application/DTOs/ModuleProviderBasicDto.cs (1)
src/Modules/Providers/Application/Services/ProvidersModuleApi.cs (1)
ModuleProviderBasicDto(272-283)
tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-74)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-154)src/Shared/Database/DapperConnection.cs (1)
GetConnectionString(11-22)
tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(12-74)tests/MeAjudaAi.Integration.Tests/Infrastructure/SimpleDatabaseFixture.cs (1)
SimpleDatabaseFixture(9-44)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ValueTask(27-145)ValueTask(147-153)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (2)
ConfigureServices(76-85)ConfigureLogging(41-74)
src/Modules/Providers/Application/Extensions.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (2)
Extensions(12-74)IServiceCollection(20-73)src/Modules/Providers/Tests/Infrastructure/TestInfrastructureExtensions.cs (1)
IServiceCollection(23-73)src/Modules/Providers/Application/Handlers/Queries/GetProvidersQueryHandler.cs (1)
GetProvidersQueryHandler(23-78)src/Modules/Providers/Application/Handlers/Commands/CreateProviderCommandHandler.cs (1)
CreateProviderCommandHandler(21-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
🔇 Additional comments (26)
src/Shared/Authorization/PermissionRequirement.cs (1)
25-31: LGTM! Defensive validation strengthens authorization.The guard clause correctly prevents
EPermission.Nonefrom being used in authorization requirements. The implementation validates before assignment, provides a clear error message, and is properly documented.tests/MeAjudaAi.Shared.Tests/Unit/Authorization/RequirePermissionAttributeTests.cs (3)
14-31: LGTM! Thorough defensive testing.The tests effectively verify that both
RequirePermissionAttributeandPermissionRequirementrejectEPermission.Nonewith the expected exception, message, and parameter name.
33-67: LGTM! Good coverage of valid scenarios.The theory tests verify that valid permissions are accepted without exceptions, covering multiple permission types across different domains (Admin, Users, Providers).
69-96: LGTM! Validates permission-to-string mappings.The tests confirm that permission enums are correctly mapped to their string representations and that policy names are properly formatted. This ensures the authorization framework will function as expected.
src/Modules/Providers/Domain/Enums/EProviderType.cs (1)
13-13: Clarify the semantic distinction between Individual and Freelancer.Both
IndividualandFreelancerappear to represent single-person service providers. Ensure there is a clear business distinction between these types to avoid confusion when selecting the appropriate type. For example, does "Individual" represent a registered professional while "Freelancer" represents an autonomous worker, or is there another meaningful difference?Consider adding more descriptive XML documentation to clarify the intended use case for each type:
/// <summary> - /// Tipo não definido + /// Prestador individual registrado /// </summary> Individual = 1,/// <summary> - /// Autônomo + /// Prestador autônomo / freelancer (especificar distinção se houver) /// </summary> Freelancer = 4Also applies to: 24-24
src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByStateQueryHandlerTests.cs (7)
11-22: LGTM!Test setup follows best practices with proper mocking of dependencies and handler initialization.
24-53: LGTM!Test correctly validates the happy path scenario with proper assertions and mock verification.
55-78: LGTM!Test correctly validates the empty result scenario.
80-101: LGTM! Previous issue resolved.The error message assertion now correctly matches the handler's actual failure message. The test properly validates exception handling behavior.
130-165: LGTM!Theory test provides excellent coverage across multiple Brazilian state abbreviations.
224-246: LGTM!Test correctly verifies that the cancellation token is properly propagated to the repository layer.
248-268: LGTM! Previous issue resolved.Excellent addition! This test properly validates the handler's input validation for null, empty, and whitespace state parameters. The test correctly verifies:
- Failure result is returned
- Appropriate error message is included
- Repository is never invoked for invalid inputs
This addresses the missing test coverage flagged in the previous review.
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs (5)
74-102: LGTM!The test correctly verifies the handler's behavior when the provider is not found, with proper assertion of the failure message and verification that
UpdateAsyncis not called.
104-134: LGTM - Past issue addressed!The failure assertion now correctly matches the handler's error message. The past review comment about message mismatch has been addressed.
136-160: LGTM - Past issue addressed!The failure assertion now correctly matches the handler's error message from the catch block. The past review comment about message mismatch has been addressed.
162-194: LGTM!The test correctly validates that invalid qualification names result in a failure with the appropriate error message from the handler's catch block.
196-264: Excellent - Past issue fully addressed!The test now includes comprehensive assertions that verify:
- The result DTO contains exactly one qualification (the one that should remain)
- The removed qualification is absent from the result
- The kept qualification is present in the result
- The provider entity passed to
UpdateAsynchas the same correct stateThis fully addresses the past review comment about missing removal assertions.
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
79-89: LGTM! Well-configured test logging.The detailed logging configuration with Debug level and appropriate filters will significantly aid in diagnosing test failures. This is exactly what's needed for effective debugging in integration tests.
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (1)
67-73: LGTM! Good cleanup practice in integration tests.The cleanup logic that attempts to delete the created provider after the test is good practice for maintaining test isolation. Ignoring deletion failures is appropriate here since permission issues in tests shouldn't fail the test of the create functionality.
src/Modules/Providers/Application/Extensions.cs (1)
18-45: LGTM! Well-structured dependency registration.The manual registration of query and command handlers provides explicit control over the DI container and makes dependencies clear. The use of
Scopedlifetime for handlers is appropriate given they depend on repositories and DbContext. The code is well-organized with clear comments separating different handler types.tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs (1)
22-33: LGTM! Clear validation of connection string fallback strategy.This test effectively validates that the multi-source connection string fallback (DefaultConnection → Providers → meajudaai-db) works correctly in test scenarios. The test is focused and provides good diagnostic output.
src/Modules/Providers/Infrastructure/Extensions.cs (1)
36-50: No changes required—test infrastructure properly handles placeholder connection string.The
ApiTestBaseremoves the defaultProvidersDbContextservice descriptors and re-registers them withoptions.UseNpgsql(_databaseFixture.ConnectionString), ensuring that the placeholder is replaced with a valid test connection string before any database operations. Database initialization occurs after schema creation and context reconfiguration, confirming the placeholder is never used for actual database operations in tests. All test files usingProvidersDbContextinherit from or access the DbContext through theApiTestBaseinfrastructure, which guarantees proper configuration.tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs (1)
29-58: Verify test re-enablement by running the test without Skip attribute.The manual table creation fallback is implemented in
ApiTestBase.cs(lines 100-143), including explicit schema creation and SQL fallback tables. Code inspection confirms the fix addresses the providers schema issue. However, manual verification is required to ensure the test passes consistently before permanently removing theSkipattribute and associated diagnostic trait.Run the test with the Skip attribute removed to confirm:
- Schema creation succeeds
- Tables are created (either via EnsureCreatedAsync or manual fallback)
- The providers endpoint responds without errors
tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs (3)
19-28: LGTM!The test correctly verifies
IQueryDispatcherregistration using a straightforward service resolution approach.
30-39: LGTM!The test correctly verifies the specific query handler registration with proper generic type parameters.
41-60: LGTM!The test effectively validates critical service registrations in a loop, providing good diagnostic output for each service type.
src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs
Show resolved
Hide resolved
tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs
Outdated
Show resolved
Hide resolved
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs
Outdated
Show resolved
Hide resolved
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (4)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
103-114: Same critical performance issue as GetByCityAsync.This method loads the entire provider table into memory before filtering by state, causing the same scalability and performance problems described for
GetByCityAsync.Apply the same server-side filtering solution as suggested for
GetByCityAsync, using a shadow property or computed column forState:public async Task<IReadOnlyList<Provider>> GetByStateAsync(string state, CancellationToken cancellationToken = default) { - // Usar client evaluation para contornar problemas de tradução EF Core com Value Objects - var providers = await GetProvidersQuery() + return await GetProvidersQuery() .Where(p => !p.IsDeleted) - .ToListAsync(cancellationToken); - - return providers - .Where(p => p.BusinessProfile.PrimaryAddress.State.Contains(state, StringComparison.OrdinalIgnoreCase)) + .Where(p => EF.Property<string>(p, "_state").Contains(state)) .OrderBy(p => p.Id.Value) - .ToList(); + .ToListAsync(cancellationToken); }
137-150: Same unnecessary client evaluation as GetByVerificationStatusAsync.This method uses the same inefficient pattern of loading all providers before filtering by the
Typeenum.Apply the same server-side filtering approach:
public async Task<IReadOnlyList<Provider>> GetByTypeAsync( EProviderType type, CancellationToken cancellationToken = default) { - // Usar client evaluation para contornar problemas de tradução EF Core com enums - var providers = await GetProvidersQuery() - .Where(p => !p.IsDeleted) - .ToListAsync(cancellationToken); - - return providers + return await GetProvidersQuery() + .Where(p => !p.IsDeleted) .Where(p => p.Type == type) .OrderBy(p => p.Id.Value) - .ToList(); + .ToListAsync(cancellationToken); }tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
206-245: Manual schema creation is incomplete and risks test failures.As identified in previous reviews, this hardcoded SQL is significantly outdated compared to the EF Core model. It's missing owned entity tables/columns for
DocumentandQualification, and has type mismatches for enums.If this fallback is triggered, integration tests will likely fail with schema-related errors. Consider one of these approaches:
- Remove this fallback entirely and let the test fail fast if
GenerateCreateScript()doesn't work- Add a prominent warning log and fail the test explicitly rather than silently continuing with incomplete schema
- Keep this as absolute minimum schema just for basic smoke tests, but document that full integration tests won't work
</comment_end>
tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs (1)
48-62: Test database not properly wired to application.As noted in previous reviews, creating the
SimpleDatabaseFixtureand attempting to configure the connection string viaservices.Configure<Dictionary<string, string>>doesn't actually override theDbContextregistrations. The application will still use the connection string from configuration, which may not exist or point to an invalid database in the Testing environment.Follow the pattern from
ApiTestBase.InitializeAsync(): remove existingDbContextOptions<UsersDbContext>andDbContextOptions<ProvidersDbContext>registrations, then add newDbContextregistrations withoptions.UseNpgsql(_databaseFixture.ConnectionString).</comment_end>
🧹 Nitpick comments (6)
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (2)
22-27: Remove redundant connection check for better performance.The
CanConnectAsynccheck is unnecessary because the subsequentCountAsyncwill fail if the database is unreachable. This adds an extra round-trip to the database on every health check execution.Apply this diff to remove the redundant check:
- // Verifica se consegue conectar ao banco - var canConnect = await dbContext.Database.CanConnectAsync(cancellationToken); - if (!canConnect) - { - return HealthCheckResult.Unhealthy("Cannot connect to providers database"); - } - // Verifica se consegue acessar a tabela providers var providersCount = await dbContext.Providers.CountAsync(cancellationToken);
29-34: Consider usingAnyAsync()instead ofCountAsync()for better performance.Health checks should be fast and lightweight. Using
CountAsync()performs a full table scan that may become slow as the providers table grows. If the count isn't required for monitoring purposes, useAnyAsync()to verify table accessibility with minimal overhead.Apply this diff if the count is not needed:
- // Verifica se consegue acessar a tabela providers - var providersCount = await dbContext.Providers.CountAsync(cancellationToken); - - logger.LogDebug("Providers health check passed - {ProvidersCount} providers found", providersCount); - - return HealthCheckResult.Healthy($"Providers database is accessible with {providersCount} providers"); + // Verifica se consegue acessar a tabela providers + await dbContext.Providers.AnyAsync(cancellationToken); + + logger.LogDebug("Providers health check passed - providers table is accessible"); + + return HealthCheckResult.Healthy("Providers database is accessible");Alternatively, if you need the count for monitoring, consider caching the result or using a more efficient query like
SELECT COUNT(*) FROM providers LIMIT 1000to cap the scan size.src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (1)
108-118: Consider making the class internal.The
NoOpClaimsTransformationimplementation is correct, but since it's only used within the testing environment setup in this assembly, consider marking it asinternalrather thanpublicfor better encapsulation.Apply this diff to restrict visibility:
/// <summary> /// No-op implementation of IClaimsTransformation for cases where minimal transformation is needed /// </summary> -public class NoOpClaimsTransformation : IClaimsTransformation +internal class NoOpClaimsTransformation : IClaimsTransformation { public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { return Task.FromResult(principal); } }tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (1)
24-39: Auto-configure admin behavior may mask test setup issues.When
_allowUnauthenticatedistrueand no configuration is set, the handler silently auto-configures an admin user (line 35). This implicit behavior could hide test setup mistakes where the test author forgot to explicitly configure authentication.Consider logging this auto-configuration at a warning level or documenting this behavior prominently so test authors are aware of the fallback.
</comment_end>
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
42-71: LGTM - DbContext substitution is thorough.The code correctly removes both
DbContextOptions<T>and the actualDbContextregistrations before adding test versions, ensuring no production database connections leak into tests.Consider extracting the removal pattern into a helper method to reduce duplication between the two contexts.
</comment_end>
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (1)
116-133: Consider creating a provider first for meaningful GetById test.The test uses a random GUID (line 121) which will almost certainly return 404, making this more of a "doesn't crash" test than a real data validation test.
Consider creating a provider first (like in
CreateProvider_WithValidData_ShouldReturnCreated), then using its ID to verify the GetById endpoint returns the correct data.</comment_end>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
src/Aspire/MeAjudaAi.AppHost/Program.cs(2 hunks)src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs(3 hunks)src/Modules/Providers/Domain/Enums/EProviderType.cs(1 hunks)src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs(6 hunks)tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/ProvidersSchemaDebugTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs(1 hunks)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- src/Modules/Providers/Domain/Enums/EProviderType.cs
- src/Modules/Providers/Tests/Unit/Application/Commands/RemoveQualificationCommandHandlerTests.cs
- src/Aspire/MeAjudaAi.AppHost/Program.cs
- tests/MeAjudaAi.Integration.Tests/ProvidersSchemaDebugTest.cs
- tests/MeAjudaAi.Integration.Tests/DependencyInjectionDiagnosticTest.cs
- tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs
- src/Modules/Providers/Infrastructure/Extensions.cs
🧰 Additional context used
🧬 Code graph analysis (9)
tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs (2)
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (6)
ConfigurableTestAuthenticationHandler(13-89)ClearConfiguration(76-81)SetAllowUnauthenticated(83-86)Task(24-39)ConfigureRegularUser(71-74)ConfigureAdmin(66-69)tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (9)
Fact(31-51)Fact(53-67)Fact(69-85)Fact(87-103)Fact(105-121)Fact(123-139)Fact(141-157)Fact(159-175)Fact(177-193)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (4)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Shared.Tests/Base/DatabaseTestBase.cs (1)
DbContextOptions(52-59)tests/MeAjudaAi.E2E.Tests/Base/E2ETestBase.cs (1)
DbContextOptions(268-274)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (1)
ConfigureLogging(41-74)
src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (1)
src/Bootstrapper/MeAjudaAi.ApiService/Extensions/EnvironmentSpecificExtensions.cs (4)
TestAuthenticationSchemeOptions(195-206)TestAuthenticationHandler(211-234)TestAuthenticationHandler(213-216)Task(218-233)
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (1)
tests/MeAjudaAi.Shared.Tests/Auth/TestAuthenticationHandlers.cs (1)
AuthenticateResult(70-78)
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
Task(206-245)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (3)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (3)
Task(22-22)Task(30-30)Task(37-37)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (3)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-246)Task(206-245)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-98)Task(103-114)Task(119-132)Task(137-150)Task(155-159)Task(164-184)Task(189-197)Task(202-206)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
ConfigurableTestAuthenticationHandler(13-89)ConfigureAdmin(66-69)
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs (2)
src/Shared/Constants/ApiEndpoints.cs (1)
System(35-40)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-246)
tests/MeAjudaAi.Integration.Tests/ApplicationStartupDiagnosticTest.cs (3)
tests/MeAjudaAi.Integration.Tests/Infrastructure/SimpleDatabaseFixture.cs (1)
SimpleDatabaseFixture(9-44)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (3)
ValueTask(27-196)ValueTask(198-204)Task(206-245)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (2)
ConfigureServices(76-85)ConfigureLogging(41-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: build-and-test
- GitHub Check: Security Scan
🔇 Additional comments (15)
src/Bootstrapper/MeAjudaAi.ApiService/Extensions/ServiceCollectionExtensions.cs (2)
1-2: LGTM! Using directives are appropriate.The new using directives support the authentication and claims transformation functionality added for testing environments.
Also applies to: 6-7
55-61: ****The review comment's concern is unfounded. The
NoOpClaimsTransformationregistration serves a specific purpose. The codebase shows that test fixtures explicitly remove the productionPermissionClaimsTransformation(which causes test hangs), but ASP.NET Core's authentication middleware may still requireIClaimsTransformationto be available in the DI container. Registering the no-op implementation satisfies this requirement while avoiding the hanging behavior of the production implementation. This is a deliberate and reasonable design choice for the test environment, not redundant code.Likely an incorrect or invalid review comment.
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
76-86: LGTM - cleanup logic properly resets all state.The
ClearConfigurationmethod correctly resets all static state including the new_allowUnauthenticatedflag, andSetAllowUnauthenticatedprovides a clean API for controlling authentication behavior in tests.Ensure all tests using this handler call
ClearConfiguration()during cleanup to prevent state leakage between tests.</comment_end>
20-22: Static state pollution risk is valid; add centralized cleanup mechanism.The concerns in the review are justified. While the codebase already acknowledges this risk through
CollectionDefinition(Sequential, Database collections withDisableParallelization = true), the cleanup is not enforced:
- Base test classes (
ApiTestBase,SharedTestBase) implementIAsyncLifetimebut do not callClearConfiguration()inDisposeAsync()- Most test files rely on manual
ClearConfiguration()calls; inconsistent adoption (e.g.,ProvidersIntegrationTests.csdoes not consistently clean up)- Volatile keyword prevents visibility issues but does not prevent race conditions between reads/writes to multiple static fields
- The auto-configure behavior at line 35 silently configures an admin user when
_allowUnauthenticated=trueand no config exists, which can hide test setup errorsRecommendation: Add
ClearConfiguration()call to base test classDisposeAsync()methods to enforce cleanup automatically, or require tests to use the Sequential collection for all tests that use the authentication handler.tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
29-31: LGTM - environment variables properly configured for testing.Setting both
ASPNETCORE_ENVIRONMENTandDOTNET_ENVIRONMENTensures that environment checks likeIsTestingEnvironment()work correctly throughout the application stack.</comment_end>
106-182: Multi-level schema creation fallback is pragmatic but carries schema drift risk.The three-level fallback strategy (EnsureCreatedAsync → GenerateCreateScript → manual SQL) provides good resilience for CI environments. The second level (script generation) is particularly good because it stays in sync with the EF model.
However, if the third level (manual table creation via
CreateProvidersTableManually) is triggered, there's significant risk of schema drift, as noted in past reviews. The hardcoded SQL won't include owned entities like Document and Qualification.Consider adding an assertion or warning log if the manual creation path is taken, so test failures can be traced back to incomplete schema.
</comment_end>
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (2)
23-84: LGTM - test includes proper cleanup and error reporting.The test follows good practices:
- Configures admin authentication
- Includes cleanup attempt to delete created resources
- Captures and reports detailed error information on failure
The cleanup ignores DELETE failures (line 72), which is reasonable for tests but could lead to test data accumulation if the endpoint has issues.
</comment_end>
187-216: LGTM - effective smoke test for multiple endpoints.Testing multiple endpoints in a loop and asserting they don't return 500 is a good approach for ensuring basic stability without requiring specific test data.
</comment_end>
tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs (3)
14-25: LGTM - authentication test now has clear expectations.Explicitly disabling unauthenticated access with
SetAllowUnauthenticated(false)and asserting a strict 401 Unauthorized response makes the test's intent clear and eliminates ambiguity from the previous multi-value assertion.</comment_end>
27-39: LGTM - test correctly expects 403 Forbidden for regular users.Renaming the test to match its actual behavior (returning Forbidden rather than OK) and updating the assertion to expect 403 correctly reflects that regular users lack permission to access the users list endpoint.
</comment_end>
41-53: LGTM - new admin test verifies proper authorization.Adding a test that verifies admin users can successfully access the endpoint (200 OK) provides good coverage of the authorization matrix: unauthenticated (401), regular user (403), admin (200).
</comment_end>
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs (3)
14-28: LGTM - strict assertion for health endpoint.The test now expects only
HttpStatusCode.OK, which is correct for an unauthenticated health check endpoint. The environment variable setup added toApiTestBase.InitializeAsync()should ensure the health endpoint is properly registered.</comment_end>
30-45: LGTM - strict assertion correctly expects 401 Unauthorized.The test now asserts a strict 401 Unauthorized response, which correctly validates that the authorization middleware is working and returning the appropriate status code instead of crashing with a 500 error.
</comment_end>
47-62: LGTM - strict assertion for Providers endpoint.Like the Users endpoint test, this now correctly expects only 401 Unauthorized, validating proper authorization behavior without allowing server errors.
</comment_end>
tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs (1)
10-27: LGTM - Users endpoint regression test is straightforward.The test properly configures admin authentication, makes a request, and asserts the expected 200 OK response with detailed error reporting.
</comment_end>
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs (4)
16-18: Remove redundant call toSetAllowUnauthenticated(false).The call on line 18 is redundant since
ClearConfiguration()already sets_allowUnauthenticated = falseby default (visible in the handler code).Apply this diff to remove the redundancy:
// Clear any authentication configuration and disable unauthenticated access ConfigurableTestAuthenticationHandler.ClearConfiguration(); -ConfigurableTestAuthenticationHandler.SetAllowUnauthenticated(false);
28-39: Consider addingClearConfiguration()for consistency.For consistency with the first test and to ensure test isolation, consider clearing the authentication configuration at the start of this test as well.
Apply this diff:
public async Task GetUsers_WithRegularUserAuthentication_ShouldReturnForbidden() { // Arrange - usuário regular sem permissão UsersList + ConfigurableTestAuthenticationHandler.ClearConfiguration(); ConfigurableTestAuthenticationHandler.ConfigureRegularUser();
41-53: Consider addingClearConfiguration()for consistency.Similar to the previous test, adding
ClearConfiguration()at the start ensures test isolation and consistency across all tests in this class.Apply this diff:
public async Task GetUsers_WithAdminAuthentication_ShouldReturnOk() { // Arrange - usuário admin com todas as permissões + ConfigurableTestAuthenticationHandler.ClearConfiguration(); ConfigurableTestAuthenticationHandler.ConfigureAdmin();
11-53: Consider implementing proper test cleanup for better isolation.Since
ConfigurableTestAuthenticationHandleruses static state (_userConfigs,_currentConfigKey,_allowUnauthenticated), tests may interfere with each other if they run in parallel or if a test fails before completing. Consider one of these approaches:
- Add a test fixture with cleanup in
Dispose()or a teardown method- Ensure every test calls
ClearConfiguration()in afinallyblock or at the start- Use xUnit's
IClassFixture<T>orICollectionFixture<T>to manage test lifecycleThis will improve reliability when tests are run in different orders or concurrently.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/Modules/Providers/Infrastructure/Extensions.cs(1 hunks)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs(6 hunks)tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs(1 hunks)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/Modules/Providers/Infrastructure/Persistence/Configurations/ProviderConfiguration.cs
- src/Modules/Providers/Infrastructure/Extensions.cs
🧰 Additional context used
🧬 Code graph analysis (6)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (1)
ConfigureLogging(41-74)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (1)
Task(16-41)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-299)Task(208-298)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (1)
Task(16-41)
tests/MeAjudaAi.Integration.Tests/ConnectionStringValidationTest.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-299)Task(208-298)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (4)
Fact(14-24)Fact(26-36)Fact(38-47)Fact(49-63)
tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs (1)
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (6)
ConfigurableTestAuthenticationHandler(13-89)ClearConfiguration(76-81)SetAllowUnauthenticated(83-86)Task(24-39)ConfigureRegularUser(71-74)ConfigureAdmin(66-69)
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (13)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-98)Task(103-114)Task(119-132)Task(137-150)Task(155-159)Task(164-184)Task(189-197)
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (1)
tests/MeAjudaAi.Shared.Tests/Auth/TestAuthenticationHandlers.cs (1)
AuthenticateResult(70-78)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
- GitHub Check: code-analysis
🔇 Additional comments (11)
tests/MeAjudaAi.Integration.Tests/Auth/AuthenticationTests.cs (1)
22-24: LGTM!The updated assertion correctly validates that the endpoint returns 401 Unauthorized when no valid authentication is provided.
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (3)
12-14: LGTM - Clean primary constructor syntax.The class declaration uses modern C# primary constructor syntax appropriately with proper dependency injection.
22-27: LGTM - Explicit connectivity check provides good diagnostics.The explicit connection check before querying data provides clear error messaging when connectivity issues occur.
36-40: LGTM - Proper exception handling for health checks.The exception handling correctly logs errors and returns an unhealthy status with exception details, which is the appropriate pattern for health checks.
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (3)
1-13: LGTM!The imports and class declaration are appropriate for integration testing the Providers database module.
14-36: LGTM!Both tests follow the Arrange-Act-Assert pattern correctly and properly verify database connectivity and table existence.
49-63: LGTM!The test correctly validates that the query service can execute queries and return properly structured results. The use of
GetRequiredServiceis appropriate here since the previous test verifies registration.tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (4)
22-22: LGTM! Appropriate use of volatile for test configuration.The
volatilekeyword ensures visibility of the flag across threads, and the default value offalseprovides a safe default that requires explicit authentication configuration.
80-81: Excellent test isolation - properly resets authentication requirements.Resetting
_allowUnauthenticatedtofalseinClearConfiguration()ensures that tests must explicitly opt-in to unauthenticated access, preventing unexpected behavior from state leakage between tests.
83-86: Clear and consistent API for controlling authentication behavior.The method name is self-documenting and follows the established pattern of static configuration methods in this test utility class.
26-36: Authentication logic correctly implements unauthenticated access control.The code at lines 26-36 properly handles both authenticated and unauthenticated flows. However, verification reveals a test infrastructure gap:
ApiTestBase.DisposeAsync()does not callConfigurableTestAuthenticationHandler.ClearConfiguration(), meaning tests inheriting fromApiTestBase(e.g.,RegressãoTest,ProvidersIntegrationTests) may leak auth state between test runs. Tests that explicitly callClearConfiguration()in constructors or test methods (e.g.,PermissionAuthorizationIntegrationTests,AuthenticationTests) mitigate this.Consider adding
ConfigurableTestAuthenticationHandler.ClearConfiguration()toApiTestBase.DisposeAsync()to ensure consistent cleanup across all integration tests.
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (3)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
156-161: Standardize ordering expression for consistency.Line 158 uses
.OrderBy(p => p.Id)while all other query methods in this file use.OrderBy(p => p.Id.Value)(lines 53, 92, 104, 118, 132). This inconsistency could lead to confusion and potential translation issues depending on how EF Core interprets the ProviderId value object.Apply this diff to align with the pattern used elsewhere:
var providers = await GetProvidersQuery() .Where(p => !p.IsDeleted) - .OrderBy(p => p.Id) + .OrderBy(p => p.Id.Value) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(cancellationToken);
31-35: Consider extracting SaveChanges for unit of work flexibility.Both
AddAsyncandUpdateAsyncimmediately callSaveChangesAsync, which couples these methods to immediate persistence and prevents batching multiple operations within a single transaction. While this is a valid repository pattern, it limits flexibility for scenarios where multiple aggregate changes should be committed atomically.Consider one of these alternatives if transactional batching is needed:
- Separate SaveChanges: Remove
SaveChangesAsyncfrom these methods and rely on callers (command handlers) to manage transaction boundaries- Unit of Work pattern: Introduce an explicit
IUnitOfWorkthat managesSaveChangesAsync- Keep current design: If each operation is intended to be an independent transaction, the current approach is appropriate
The current design is acceptable for repositories that guarantee each operation is immediately persisted.
Also applies to: 139-143
tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs (1)
180-195: Consider using statements for cleaner code.The DI verification test is solid and checks essential services. However, the fully qualified type names (lines 187-194) are verbose. Consider adding using statements for improved readability.
Add these using statements at the top of the file:
using FluentAssertions; using MeAjudaAi.Integration.Tests.Base; +using MeAjudaAi.Modules.Providers.Application.Services; +using MeAjudaAi.Modules.Providers.Domain.Repositories; +using MeAjudaAi.Modules.Providers.Infrastructure.Persistence;Then simplify the service resolution:
- var dbContext = scope.ServiceProvider.GetService<MeAjudaAi.Modules.Providers.Infrastructure.Persistence.ProvidersDbContext>(); + var dbContext = scope.ServiceProvider.GetService<ProvidersDbContext>(); dbContext.Should().NotBeNull("ProvidersDbContext should be registered"); - var repository = scope.ServiceProvider.GetService<MeAjudaAi.Modules.Providers.Domain.Repositories.IProviderRepository>(); + var repository = scope.ServiceProvider.GetService<IProviderRepository>(); repository.Should().NotBeNull("IProviderRepository should be registered"); - var queryService = scope.ServiceProvider.GetService<MeAjudaAi.Modules.Providers.Application.Services.IProviderQueryService>(); + var queryService = scope.ServiceProvider.GetService<IProviderQueryService>(); queryService.Should().NotBeNull("IProviderQueryService should be registered");
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs(1 hunks)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs(5 hunks)tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs(6 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs
- src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs
🧰 Additional context used
🧬 Code graph analysis (7)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (5)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Shared.Tests/Base/DatabaseTestBase.cs (1)
DbContextOptions(52-59)src/Bootstrapper/MeAjudaAi.ApiService/Program.cs (1)
ConfigureLogging(41-74)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (1)
Task(16-41)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (12)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-94)Task(99-106)Task(111-120)Task(125-134)Task(139-143)Task(148-168)
src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (2)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-94)Task(99-106)Task(111-120)Task(125-134)Task(139-143)Task(148-168)Task(173-181)Task(186-190)src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)
tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs (9)
src/Shared/Constants/ApiEndpoints.cs (1)
System(35-40)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-299)tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (9)
Fact(31-52)Fact(54-68)Fact(70-86)Fact(88-104)Fact(106-122)Fact(124-138)Fact(140-154)Fact(156-172)Fact(174-189)tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs (1)
Fact(15-29)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (6)
Fact(22-104)Fact(106-137)Fact(139-156)Fact(158-182)Fact(184-208)Fact(210-239)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (1)
Task(16-41)src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (14)
Task(31-35)Task(40-44)Task(49-55)Task(60-64)Task(69-73)Task(78-82)Task(87-94)Task(99-106)Task(111-120)Task(125-134)Task(139-143)Task(148-168)Task(173-181)Task(186-190)src/Modules/Providers/Infrastructure/Queries/ProviderQueryService.cs (1)
Task(23-71)src/Modules/Providers/Infrastructure/Persistence/ProvidersDbContextFactory.cs (1)
ProvidersDbContext(13-42)
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (2)
tests/MeAjudaAi.Shared.Tests/Extensions/TestCancellationExtensions.cs (1)
CancellationToken(13-13)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
ConfigurableTestAuthenticationHandler(13-89)SetAllowUnauthenticated(83-86)
tests/MeAjudaAi.Integration.Tests/AuthorizationDiagnosticTest.cs (3)
src/Shared/Constants/ApiEndpoints.cs (1)
System(35-40)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-299)Task(208-298)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (3)
ConfigurableTestAuthenticationHandler(13-89)ClearConfiguration(76-81)SetAllowUnauthenticated(83-86)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (2)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
ApiTestBase(19-299)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (4)
src/Modules/Providers/Domain/Entities/Provider.cs (4)
Provider(19-327)Provider(80-80)Provider(85-105)Provider(118-143)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (1)
Task(208-298)src/Modules/Providers/Domain/Repositories/IProviderRepository.cs (2)
Task(22-22)Task(30-30)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
- GitHub Check: code-analysis
🔇 Additional comments (9)
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (3)
49-49: LGTM: Unauthorized status added to expectations.Adding
Unauthorizedas an expected status code is appropriate for permission-based authorization tests where users may lack required permissions.
181-182: LGTM: Test updated to use real API endpoint.The comment and endpoint update improve test clarity by explicitly referencing real API endpoints rather than test-only paths.
162-163: No action required—the endpoint properly supports optional pagination parameters.The endpoint
GetUsersAsynchas all pagination parameters as optional with defaults:pageNumber = 1andpageSize = 10. ASP.NET Core's model binding will use these defaults when query parameters are omitted. The endpoint explicitly marks these parameters asRequired = falsein its OpenAPI documentation. Since the test focuses on authorization (not pagination validation), removing the query parameters poses no risk.Likely an incorrect or invalid review comment.
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs (2)
18-26: LGTM! Clean repository structure with proper eager loading.The primary constructor syntax is concise, and the
GetProvidersQueryhelper correctly includes related entities (Documents, Qualifications) to avoid N+1 queries.
173-181: Physical deletion is intentional and correctly isolated from the application command flow.The verification confirms the design is sound:
DeleteProviderCommandHandlercorrectly uses soft delete via the domain method:provider.Delete(dateTimeProvider, command.DeletedBy)followed byUpdateAsync.- The repository's
DeleteAsyncmethod (performing physical deletion) is not invoked by the application layer—it exists for admin/compliance scenarios and is already documented onIProviderRepositorywith a comment explaining the distinction.- The interface already clarifies both deletion paths in its XML remarks: physical deletion via repository vs. logical deletion via the domain method.
The two-path design is intentional and functioning correctly. No changes are necessary.
tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs (4)
21-31: LGTM!This smoke test appropriately verifies the endpoint exists without requiring authentication. The assertions correctly check for route availability rather than functional correctness.
82-96: Good parameter validation test, but authentication is disabled.The test correctly verifies pagination parameters are accepted by the endpoint. However, note that authentication is disabled (line 86), so this test runs unauthenticated. If this is temporary, consider tracking it with a task to re-enable authentication across all tests.
98-112: LGTM!Appropriately validates that filter parameters are accepted without causing errors. Consistent with the testing pattern established in other methods.
138-178: LGTM!The test appropriately verifies the POST endpoint route exists by checking it doesn't return 404 or 405. The detailed payload structure helps ensure the endpoint can accept the request body format, even if authorization prevents actual creation.
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
Show resolved
Hide resolved
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (1)
227-258: Critical: Module endpoints not mapped in test application.The
Configuremethod only maps test endpoints (lines 236-257), but the tests call real API endpoints like/api/v1/usersand/api/v1/providers. Without mapping these module endpoints, all tests will fail with 404 Not Found.The Users and Providers modules register services (lines 211-212) but don't expose their routes. Add endpoint mapping after
UseAuthorization():app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); + + // Map module endpoints + app.UseEndpoints(endpoints => + { + // Map Users module endpoints + endpoints.MapUsersEndpoints(); + + // Map Providers module endpoints + endpoints.MapProvidersEndpoints(); + }); app.UseEndpoints(endpoints =>Note: Verify the exact method names (
MapUsersEndpoints,MapProvidersEndpoints) match the module's Extensions classes. Alternative patterns might beUseUsersModule()or endpoint groups.
🧹 Nitpick comments (7)
tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs (1)
10-68: Consider extracting common test logic to reduce duplication.Both test methods share nearly identical structure (try-finally auth setup, GET request, logging, assertion). A helper method could reduce duplication while maintaining test clarity:
private async Task<(HttpStatusCode StatusCode, string Content)> GetAsAdminAsync(string endpoint) { ConfigurableTestAuthenticationHandler.ClearConfiguration(); ConfigurableTestAuthenticationHandler.ConfigureAdmin(); try { var response = await Client.GetAsync(endpoint, TestContext.Current.CancellationToken); var content = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); Console.WriteLine($"Response Status: {response.StatusCode}"); Console.WriteLine($"Response Content: {content}"); return (response.StatusCode, content); } finally { ConfigurableTestAuthenticationHandler.ClearConfiguration(); } }Then simplify each test:
[Fact] public async Task UsersEndpoint_ShouldWork_WithoutErrors() { var (status, content) = await GetAsAdminAsync("/api/v1/users?PageNumber=1&PageSize=5"); Assert.True(status == HttpStatusCode.OK, $"Users endpoint should return OK, but got {status}. Content: {content}"); }tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (1)
38-49: Consider simplifying the test method.The previous review comment has been addressed—the method is no longer async and uses singular naming. However, two optional improvements remain:
- Since the test performs only synchronous assertions, it could be simplified to a
voidmethod instead of returningTask.- The fully qualified namespace on line 43 could be replaced with a using directive for cleaner code.
Apply this diff for a cleaner implementation:
+using MeAjudaAi.Modules.Providers.Application.Services; + namespace MeAjudaAi.Integration.Tests.Providers; /// <summary>[Fact] - public Task ProviderQueryService_ShouldBeRegistered() + public void ProviderQueryService_ShouldBeRegistered() { // Arrange using var scope = Services.CreateScope(); - var queryService = scope.ServiceProvider.GetService<MeAjudaAi.Modules.Providers.Application.Services.IProviderQueryService>(); + var queryService = scope.ServiceProvider.GetService<IProviderQueryService>(); // Act & Assert queryService.Should().NotBeNull(); - - return Task.CompletedTask; }tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (5)
1-1: Remove unused import.The
using System.Linq;directive is not used in this file. No LINQ methods are invoked in any of the test methods.Apply this diff:
-using System.Linq; using System.Net.Http.Json;
64-96: Eliminate duplicate response-handling and cleanup logic.The code duplicates response parsing and cleanup logic across both branches (lines 71-81 and 86-95). Extract this into a helper method to improve maintainability.
Consider refactoring to:
+ private static string? ExtractProviderId(JsonElement response) + { + var element = response.TryGetProperty("data", out var dataElement) ? dataElement : response; + return element.TryGetProperty("id", out var idProperty) ? idProperty.GetString() : null; + } + // Assert var content = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { var responseJson = JsonSerializer.Deserialize<JsonElement>(content); - - // Verifica se é uma response estruturada (com data) - if (responseJson.TryGetProperty("data", out var dataElement)) - { - Assert.True(dataElement.TryGetProperty("id", out _), - $"Response data does not contain 'id' property. Full response: {content}"); - Assert.True(dataElement.TryGetProperty("name", out var nameProperty)); - Assert.Equal("Test Provider Integration", nameProperty.GetString()); - - // Cleanup - tentar deletar o provider criado - if (dataElement.TryGetProperty("id", out var idProperty)) - { - var providerId = idProperty.GetString(); - await Client.DeleteAsync($"/api/v1/providers/{providerId}"); - } - } - else - { - // Fallback para response direta - Assert.True(responseJson.TryGetProperty("id", out _), - $"Response does not contain 'id' property. Full response: {content}"); - Assert.True(responseJson.TryGetProperty("name", out var nameProperty)); - Assert.Equal("Test Provider Integration", nameProperty.GetString()); - - if (responseJson.TryGetProperty("id", out var idProperty)) - { - var providerId = idProperty.GetString(); - await Client.DeleteAsync($"/api/v1/providers/{providerId}"); - } - } + var element = responseJson.TryGetProperty("data", out var dataElement) ? dataElement : responseJson; + + Assert.True(element.TryGetProperty("id", out _), + $"Response does not contain 'id' property. Full response: {content}"); + Assert.True(element.TryGetProperty("name", out var nameProperty)); + Assert.Equal("Test Provider Integration", nameProperty.GetString()); + + var providerId = ExtractProviderId(responseJson); + if (providerId != null) + { + await Client.DeleteAsync($"/api/v1/providers/{providerId}"); + } }
118-129: Standardize API response format.The test accepts three different response formats (lines 123-126), indicating the API response structure is inconsistent. This makes tests brittle and the API contract unclear.
Consider standardizing on a single response format across all endpoints, such as:
{ "data": { "items": [...], "totalCount": 0 } }Then simplify the assertion:
var response = JsonSerializer.Deserialize<JsonElement>(content); Assert.True(response.TryGetProperty("data", out var data)); Assert.True(data.TryGetProperty("items", out _));
158-182: Verify that the type filter actually works.The test checks that the endpoint returns a list structure but doesn't verify that the returned providers actually match the requested type (type 0 / Individual). A provider with any type could be returned and the test would still pass.
Enhance the assertion:
if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var providers = JsonSerializer.Deserialize<JsonElement>(content); // Verificar que retorna uma lista Assert.True(providers.ValueKind == JsonValueKind.Array || (providers.ValueKind == JsonValueKind.Object && providers.TryGetProperty("items", out _))); + + // Verify filtering: if any items are returned, they should have type 0 + if (providers.ValueKind == JsonValueKind.Array && providers.GetArrayLength() > 0) + { + var firstItem = providers[0]; + Assert.True(firstItem.TryGetProperty("type", out var typeProperty)); + Assert.Equal(0, typeProperty.GetInt32()); + } }
184-208: Verify that the verification status filter actually works.Like the previous test, this one checks the response structure but doesn't verify that returned providers actually have the requested verification status (0 / Pending).
Apply a similar enhancement as suggested for the type filter test:
if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var providers = JsonSerializer.Deserialize<JsonElement>(content); // Verificar que retorna uma lista Assert.True(providers.ValueKind == JsonValueKind.Array || (providers.ValueKind == JsonValueKind.Object && providers.TryGetProperty("items", out _))); + + // Verify filtering: if any items are returned, they should have verificationStatus 0 + if (providers.ValueKind == JsonValueKind.Array && providers.GetArrayLength() > 0) + { + var firstItem = providers[0]; + Assert.True(firstItem.TryGetProperty("verificationStatus", out var statusProperty)); + Assert.Equal(0, statusProperty.GetInt32()); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs(7 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs(1 hunks)tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/MeAjudaAi.Integration.Tests/Providers/ImplementedFeaturesTests.cs
- src/Modules/Providers/Infrastructure/Persistence/Repositories/ProviderRepository.cs
🧰 Additional context used
🧬 Code graph analysis (3)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (3)
src/Modules/Providers/Infrastructure/Extensions.cs (1)
Extensions(14-84)tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-299)Task(208-298)src/Modules/Providers/Infrastructure/HealthChecks/ProvidersHealthCheck.cs (1)
Task(16-41)
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (2)
tests/MeAjudaAi.Integration.Tests/Base/ApiTestBase.cs (2)
ApiTestBase(19-299)Task(208-298)tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
ConfigurableTestAuthenticationHandler(13-89)ConfigureAdmin(66-69)
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (1)
tests/MeAjudaAi.Shared.Tests/Auth/ConfigurableTestAuthenticationHandler.cs (2)
ConfigurableTestAuthenticationHandler(13-89)SetAllowUnauthenticated(83-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
🔇 Additional comments (10)
tests/MeAjudaAi.Integration.Tests/RegressãoTest.cs (2)
10-35: LGTM! Previous auth cleanup concern addressed.The try-finally block properly ensures
ClearConfiguration()is called even when assertions fail, preventing static auth state from leaking into subsequent tests. This addresses the previous review feedback.
37-68: LGTM! Test re-enabled and auth cleanup properly implemented.The test has been re-enabled (no longer skipped) and now includes the same try-finally cleanup pattern as the Users test, addressing the previous auth state leakage concern.
The
[Trait("Status", "NeedsInvestigation")]suggests uncertainty about test stability. Since the comment indicates CI now shows 200 OK responses, consider running this test a few times in CI to confirm stability, then remove the "NeedsInvestigation" trait if it passes consistently.tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs (2)
17-17: LGTM! Providers module import follows established pattern.The static using directive correctly imports the Providers module extensions, mirroring the Users module pattern on line 16.
180-180: Good defensive configuration for unauthenticated test.Explicitly calling
SetAllowUnauthenticated(false)ensures the test properly validates unauthorized access behavior rather than relying on default state.tests/MeAjudaAi.Integration.Tests/Providers/ProvidersDatabaseTest.cs (4)
1-13: LGTM: Test class structure is correct.The imports, namespace declaration, and class inheritance are properly configured for integration testing.
14-24: LGTM: Database connectivity test is properly implemented.The test correctly verifies that the ProvidersDbContext can connect to the database.
26-36: LGTM: Table existence test is correct.The test effectively verifies that the Providers table is accessible and can be queried.
51-66: LGTM: Query functionality test is correctly implemented.The test properly verifies that the query service can retrieve providers. The fully qualified namespace on line 56 could be simplified with a using directive (as suggested in the previous comment), but the test logic is sound.
tests/MeAjudaAi.Integration.Tests/Providers/ProvidersIntegrationTests.cs (2)
210-239: LGTM: Smoke test is valuable for catching server errors.This test effectively verifies that all provider endpoints handle requests without throwing unhandled exceptions (500 errors). The use of
testOutputfor logging non-success responses aids debugging.
28-56: Remove the review comment—no foreign key constraint exists.The ProviderConfiguration does not define a foreign key constraint from
providers.user_idto theuserstable. TheUserIdproperty is mapped to the database column but has only a unique index, not a referential integrity constraint. A randomGuid.NewGuid()will not violate any database constraint.Likely an incorrect or invalid review comment.
tests/MeAjudaAi.Integration.Tests/Authorization/PermissionAuthorizationIntegrationTests.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (7)
src/Modules/Providers/API/API.Client/README.md (1)
41-51: Authentication guidance could be more specific.While mentioning Keycloak is helpful context, the authentication section assumes users already know how to obtain a token. Consider expanding with:
- Direct link to the Keycloak authentication endpoint path
- Example curl command or reference to where auth tokens can be obtained
- Whether the token requires specific scopes or claims for the Providers API
src/Modules/Users/API/API.Client/README.md (1)
35-41: Clarify the sequential setup order—both sections claim "PRIMEIRO" (FIRST).Lines 35 and 41 both emphasize being the first step with the ⚡ icon and "PRIMEIRO" label, creating ambiguity about the intended order. The flow should be: (1) copy config file, (2) execute shared setup, (3) start app. Consider renumbering the sections as Passo 1, Passo 2, Passo 3 to make the sequence unambiguous for developers.
Apply this diff to clarify the step sequence:
-#### ⚡ **PRIMEIRO: Crie seu arquivo de configuração local** +#### ⚡ **Passo 1: Crie seu arquivo de configuração local** ```bash # No diretório API.Client cp collection.bru.example collection.bru-#### ⚡ Execute PRIMEIRO a configuração compartilhada
+#### ⚡ Passo 2: Execute a configuração compartilhada
- Navegue para:
src/Shared/API.Collections/Setup/- Execute:
SetupGetKeycloakToken.brupara autenticar- Resultado: Token de acesso será definido automaticamente para TODOS os módulos
</blockquote></details> <details> <summary>src/Modules/Users/Infrastructure/Services/Mock/MockKeycloakService.cs (1)</summary><blockquote> `1-58`: **Excellent implementation - all past concerns addressed!** This implementation successfully resolves all previously flagged issues: - ✅ Thread-safety: `ConcurrentDictionary` with `TryAdd`/`TryRemove` prevents race conditions - ✅ Test isolation: `Reset()` method enables clean state between tests - ✅ Deterministic data: `MockAuthenticationHelper` provides fixed, predictable values - ✅ Roles captured: `CreateUserAsync` now stores roles in `_userRoles` - ✅ Constants usage: `MockAuthenticationHelper` uses `AuthConstants.Claims` The mock is well-documented, thread-safe, and follows best practices for test doubles. **Minor observation (optional):** The stored roles in `_userRoles` (lines 17, 34, 55) are never retrieved by `AuthenticateAsync` or `ValidateTokenAsync` - those methods return fixed roles from `MockAuthenticationHelper`. The storage demonstrates the parameter is "handled" but serves no functional purpose in the current mock behavior. This is acceptable for a simple mock, though future enhancements could return the stored roles to more accurately simulate role-based behavior. </blockquote></details> <details> <summary>src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)</summary><blockquote> `104-105`: **Remove unnecessary blank lines.** These consecutive empty lines appear to be leftover from a previous refactoring (possibly duplicate test removal). </blockquote></details> <details> <summary>src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)</summary><blockquote> `22-30`: **Consider more specific parameter names in ArgumentNullException.** Lines 25 and 28 throw `ArgumentNullException` with `nameof(request)` as the parameter name, but the actual null properties are `request.UserId` and `request.BusinessProfile`. While the error messages are clear, using more specific parameter identification would improve debugging. Consider this diff: ```diff return new CreateProviderCommand( - Guid.Parse(request.UserId ?? throw new ArgumentNullException(nameof(request), "UserId is required")), + Guid.Parse(request.UserId ?? throw new ArgumentNullException(nameof(request.UserId), "UserId is required")), request.Name, request.Type, - request.BusinessProfile ?? throw new ArgumentNullException(nameof(request), "BusinessProfile is required") + request.BusinessProfile ?? throw new ArgumentNullException(nameof(request.BusinessProfile), "BusinessProfile is required") );Note: The remarks correctly indicate these are programming errors caught at the API boundary, with user input validation handled earlier by FluentValidation.
src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs (2)
15-23: Consider simplifying PageSize validation for clarity.Line 20 uses
.GreaterThan(ValidationConstants.Pagination.MinPageSize - 1)which evaluates to.GreaterThan(0). While functionally correct, this is semantically checking that PageSize is at least MinPageSize. For clarity and directness, consider using.GreaterThanOrEqualTo(ValidationConstants.Pagination.MinPageSize)instead.Apply this diff:
RuleFor(x => x.PageSize) - .GreaterThan(ValidationConstants.Pagination.MinPageSize - 1) - .WithMessage("Tamanho da página deve ser maior que 0") + .GreaterThanOrEqualTo(ValidationConstants.Pagination.MinPageSize) + .WithMessage($"Tamanho da página deve ser pelo menos {ValidationConstants.Pagination.MinPageSize}") .LessThanOrEqualTo(ValidationConstants.Pagination.MaxPageSize) - .WithMessage("Tamanho da página não pode ser maior que 100"); + .WithMessage($"Tamanho da página não pode ser maior que {ValidationConstants.Pagination.MaxPageSize}");
34-46: Hardcoded enum values in error messages create maintenance burden.The error messages on lines 38 and 45 hardcode enum values and descriptions. If enum definitions change (new values added, reordered, or removed), these messages will become outdated and require manual updates.
Consider these approaches:
- Use FluentValidation's
.IsInEnum()method if available in your version (cleaner and automatically generates messages)- Dynamically generate the message by iterating over enum values
- Extract enum descriptions to constants or resources for centralized maintenance
Option 1: Use IsInEnum() if available
When(x => x.Type.HasValue, () => { RuleFor(x => x.Type!.Value) - .Must(type => Enum.IsDefined(typeof(EProviderType), type)) - .WithMessage("Tipo de prestador inválido. Valores válidos: 0 (None), 1 (Individual), 2 (Company), 3 (Cooperative), 4 (Freelancer)"); + .IsInEnum() + .WithMessage("Tipo de prestador inválido"); }); When(x => x.VerificationStatus.HasValue, () => { RuleFor(x => x.VerificationStatus!.Value) - .Must(status => Enum.IsDefined(typeof(EVerificationStatus), status)) - .WithMessage("Status de verificação inválido. Valores válidos: 0 (None), 1 (Pending), 2 (InProgress), 3 (Verified), 4 (Rejected), 5 (Suspended)"); + .IsInEnum() + .WithMessage("Status de verificação inválido"); });Option 2: Dynamically generate message
When(x => x.Type.HasValue, () => { + var validTypes = string.Join(", ", Enum.GetValues(typeof(EProviderType)) + .Cast<EProviderType>() + .Select(e => $"{(int)e} ({e})")); RuleFor(x => x.Type!.Value) .Must(type => Enum.IsDefined(typeof(EProviderType), type)) - .WithMessage("Tipo de prestador inválido. Valores válidos: 0 (None), 1 (Individual), 2 (Company), 3 (Cooperative), 4 (Freelancer)"); + .WithMessage($"Tipo de prestador inválido. Valores válidos: {validTypes}"); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
.gitignore(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/AddDocument.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviderById.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviderByUserId.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviders.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByState.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByType.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByVerificationStatus.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateProviderProfile.bru(1 hunks)src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateVerificationStatus.bru(1 hunks)src/Modules/Providers/API/API.Client/README.md(1 hunks)src/Modules/Providers/API/API.Client/collection.bru.example(1 hunks)src/Modules/Providers/API/Endpoints/ProvidersModuleEndpoints.cs(1 hunks)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/Application/DTOs/Requests/GetProvidersRequest.cs(1 hunks)src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Validators/GetProvidersRequestValidatorTests.cs(1 hunks)src/Modules/Users/API/API.Client/README.md(2 hunks)src/Modules/Users/Infrastructure/Services/Mock/MockAuthenticationHelper.cs(1 hunks)src/Modules/Users/Infrastructure/Services/Mock/MockKeycloakService.cs(1 hunks)src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockAuthenticationHelperTests.cs(1 hunks)src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockKeycloakServiceTests.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
- src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByType.bru
- src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviderByUserId.bru
- src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviders.bru
- src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByState.bru
- src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockAuthenticationHelperTests.cs
- src/Modules/Providers/API/API.Client/ProviderAdmin/GetProviderById.bru
- src/Modules/Providers/Application/DTOs/Requests/GetProvidersRequest.cs
- src/Modules/Users/Infrastructure/Services/Mock/MockAuthenticationHelper.cs
- src/Modules/Providers/API/Endpoints/ProvidersModuleEndpoints.cs
🧰 Additional context used
🧬 Code graph analysis (6)
src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs (1)
src/Shared/Constants/ValidationConstants.cs (1)
ValidationConstants(9-65)
src/Modules/Providers/Tests/Unit/Application/Validators/GetProvidersRequestValidatorTests.cs (1)
src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs (2)
GetProvidersRequestValidator(11-48)GetProvidersRequestValidator(13-47)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs (3)
ModuleApi(18-321)DocumentDto(307-310)DocumentDto(317-320)
src/Modules/Users/Infrastructure/Services/Mock/MockKeycloakService.cs (1)
src/Modules/Users/Infrastructure/Services/Mock/MockAuthenticationHelper.cs (4)
MockAuthenticationHelper(12-55)CreateMockKeycloakId(44-54)AuthenticationResult(19-28)TokenValidationResult(30-42)
src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockKeycloakServiceTests.cs (2)
src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockAuthenticationHelperTests.cs (5)
Trait(10-78)Fact(15-32)Fact(34-48)Fact(50-62)Fact(64-77)src/Modules/Users/Infrastructure/Services/Mock/MockKeycloakService.cs (6)
MockKeycloakService(14-58)Reset(22-25)Task(27-38)Task(40-44)Task(46-50)Task(52-57)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
src/Shared/Constants/ApiEndpoints.cs (1)
Providers(35-51)
🪛 LanguageTool
src/Modules/Providers/API/API.Client/README.md
[typographical] ~30-~30: Símbolo sem par: “]” aparentemente está ausente
Context: ...# 🚀 Como Usar 1. Instale o Bruno: [https://usebruno.com/](https://usebruno....
(UNPAIRED_BRACKETS)
[uncategorized] ~36-~36: Pontuação duplicada
Context: ...igure as variáveis** em collection.bru: - baseUrl: URL da API (padrão: `http://localhost:5...
(DOUBLE_PUNCTUATION_XML)
[inconsistency] ~37-~37: O URL contém o caratére inválido segundo RFC 1738. Os caratéres especiais podem ser codificados com % seguido de dois números hexadecimais. Context: ...u: - baseUrl: URL da API (padrão: http://localhost:5000) - accessToken: Token JWT obtido ap...
(URL_VALIDATION)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
🔇 Additional comments (19)
.gitignore (1)
129-131: Approve: Prevent credential leakage from Bruno collections.Adding
**/collection.bruto the ignore list is a sound security practice. Bruno collection files typically store environment-specific credentials and configuration that should never be committed to version control. The pattern correctly targets only collection metadata files (which contain credentials) while allowing individual API contract .bru files to be tracked.src/Modules/Providers/API/API.Client/README.md (4)
1-26: Well-structured documentation for the API client collection.The folder structure and endpoint organization is clear and comprehensive. The documentation effectively communicates the available testing resources for the Providers module.
28-40: Setup instructions are clear; verify default baseUrl matches project configuration.The setup steps are practical and user-friendly. However, ensure the documented default
baseUrlofhttp://localhost:5000aligns with your actual project's API port configuration, or provide guidance on how to determine the correct port.
53-68: Example endpoints cover key use cases well.The provided examples are practical and aligned with the documented folder structure. Ensure these paths are validated against the actual implementation to prevent user confusion.
1-82: Static analysis false positives: Dismiss markdown formatting warnings.LanguageTool flagged potential issues on lines 30, 36, and 37. These are false positives—the markdown link syntax, colon punctuation, and localhost URL are all valid. No action needed.
src/Modules/Users/API/API.Client/README.md (1)
9-10: The.gitignorecorrectly excludescollection.bru— no action needed.Verification confirms that
.gitignorecontains**/collection.bru, properly excluding local configuration files at any directory level. The documentation and version control configuration are consistent.src/Modules/Users/Tests/Unit/Infrastructure/Services/Mock/MockKeycloakServiceTests.cs (1)
1-109: Comprehensive test coverage with proper isolation!The test suite effectively validates all mock service operations:
- ✅ Constructor calls
Reset()(line 19) - addresses the past shared-state concern- ✅ All core operations tested: create, authenticate, validate, deactivate
- ✅ Concurrency test (lines 85-108) with 50 parallel users validates thread-safety
- ✅ Clean AAA pattern with FluentAssertions throughout
- ✅ Proper test categorization with
[Trait]attributesThe concurrency test is particularly valuable for catching race conditions in the
ConcurrentDictionaryoperations. Well done!src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (5)
37-61: LGTM!Test setup properly mocks all dependencies and follows standard testing patterns.
83-102: LGTM!The test correctly validates the availability check by returning null for
HealthCheckService, which triggers the fallback to basic operations testing. This is a pragmatic approach that avoids the complexity of mockingHealthCheckServicewhile still verifying the core availability logic.
106-123: LGTM!Test correctly validates that the module reports unavailability when basic operations fail.
125-203: LGTM!All tests follow the AAA pattern correctly and provide good coverage of both success and null-result scenarios.
205-247: LGTM!Helper method creates a comprehensive test DTO with all required nested objects properly populated.
src/Modules/Providers/API/API.Client/collection.bru.example (1)
1-27: LGTM!Configuration file follows good security practices with clear warnings about credentials and suggests using environment variables for sensitive data. The bilingual comments are helpful for international teams.
src/Modules/Providers/API/API.Client/ProviderAdmin/AddDocument.bru (1)
1-75: LGTM!API contract is well-documented with clear authorization requirements, parameter descriptions, document type enumerations, and expected responses. The parameter naming is now consistent throughout.
src/Modules/Providers/API/API.Client/ProviderAdmin/GetProvidersByVerificationStatus.bru (1)
1-75: LGTM!API contract documentation is comprehensive and accurate. The verification status enum values are now correctly documented (0-5) matching the domain enum definition.
src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateVerificationStatus.bru (1)
1-42: LGTM!API contract structure, authorization requirements, and parameter documentation (including the corrected
providerIdpath parameter) are well-defined.src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateProviderProfile.bru (1)
1-98: LGTM!API contract is comprehensive and well-documented. The path parameter naming is consistent, and the response documentation now includes all fields from the request body (zipCode, website, operatingHours).
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
32-171: LGTM!All mapper extension methods follow a consistent pattern and correctly translate between DTOs, commands, and queries. The mappings align well with the CQRS architecture and domain model.
src/Modules/Providers/Tests/Unit/Application/Validators/GetProvidersRequestValidatorTests.cs (1)
1-298: Excellent test coverage!The test suite comprehensively covers all validation rules:
- ✓ Valid requests with and without optional fields
- ✓ Boundary conditions for pagination (PageNumber, PageSize)
- ✓ Name length validation (too short, too long, valid)
- ✓ Empty/whitespace/null name handling
- ✓ All valid enum values for Type and VerificationStatus
- ✓ Invalid enum values outside defined ranges
- ✓ Proper use of property path assertions for nested nullable value types
The tests properly verify the conditional validation behavior where Name, Type, and VerificationStatus validations only apply when values are provided.
src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateVerificationStatus.bru
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
22-30: Consider documenting or handlingFormatExceptionfromGuid.Parse.
Guid.Parseat line 25 can throwFormatExceptionifUserIdcontains an invalid GUID string. The comment states validation should happen via FluentValidation beforehand, but doesn't acknowledge this possible exception. Consider either:
- Documenting that
FormatExceptionmay be thrown for invalid GUIDs- Using
Guid.TryParsewith explicit error handling if this is a concernsrc/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (2)
164-201: Consider using specific predicates for consistency.While
It.IsAny<GetProviderByIdQuery>()works, usingIt.Is<GetProviderByIdQuery>(q => q.ProviderId == providerId)(as in theGetProviderByIdAsynctests) would make the mock setups more precise and consistent across the test suite.Example for the existing provider test:
_getProviderByIdHandlerMock.Setup(x => x.HandleAsync( - It.IsAny<GetProviderByIdQuery>(), + It.Is<GetProviderByIdQuery>(q => q.ProviderId == providerId), It.IsAny<CancellationToken>())) .ReturnsAsync(Result<ProviderDto?>.Success(providerDto));Apply similarly to the non-existent provider test.
1-246: Consider expanding test coverage for remaining public methods.The current tests validate core functionality (
ModuleName,ApiVersion,IsAvailableAsync,GetProviderByIdAsync,ProviderExistsAsync), but several public methods fromProvidersModuleApiremain untested, including:
GetProviderByDocumentAsyncGetProviderByUserIdAsyncUserIsProviderAsyncDocumentExistsAsyncGetProvidersByCityAsync/GetProvidersByStateAsyncGetProvidersByTypeAsync/GetProvidersByVerificationStatusAsyncGetProvidersBasicInfoAsync/GetProvidersBatchAsyncAdding tests for these methods would improve coverage and catch potential issues in the mapping logic, especially for methods that parse enum strings.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateVerificationStatus.bru(1 hunks)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Modules/Providers/Application/Validators/GetProvidersRequestValidator.cs
🧰 Additional context used
🧬 Code graph analysis (2)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs (1)
ModuleApi(18-321)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
src/Shared/Constants/ApiEndpoints.cs (1)
Providers(35-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
- GitHub Check: code-analysis
🔇 Additional comments (7)
src/Modules/Providers/API/API.Client/ProviderAdmin/UpdateVerificationStatus.bru (1)
28-73: Previous issues have been successfully addressed.Both concerns from previous reviews have been fixed:
- The parameter name is now consistently documented as
providerIdthroughout (line 38)- The enum values now correctly match
EVerificationStatuswith the proper 0-5 mapping (lines 44-49)The documentation is comprehensive and accurate.
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (6)
1-35: Well-structured test class setup.The mock declarations cover all dependencies required by
ProvidersModuleApi, and the imports are appropriate for comprehensive unit testing.
37-61: Constructor correctly initializes all test dependencies.All mocks are properly instantiated and injected into the SUT, ensuring each test starts with a clean state.
63-81: Property tests validate the module metadata correctly.
83-121: IsAvailableAsync tests correctly validate both healthy and failing scenarios.The tests properly work around
HealthCheckServicemocking difficulties by returningnulland focusing on the basic operations check. The two tests are distinct (contrary to past review comments): one verifies success returnstrue, the other verifies failure returnsfalse.
123-162: GetProviderByIdAsync tests comprehensively cover success and not-found scenarios.The mock setups are specific (using predicate matching), and the assertions validate both the result status and the returned data.
203-245: Helper method provides comprehensive test data.
CreateTestProviderDtoconstructs a fully populatedProviderDtowith all nested objects, reducing duplication across tests and ensuring consistent test data.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (5)
83-121: Health check path remains untested.The workaround of returning
nullforHealthCheckServicebypasses the constructor issues noted in previous reviews, but it leaves the health check integration path (lines 26-45 in the implementation) completely untested. Only the basic operations fallback is exercised.Consider adding a test that mocks
HealthCheckServicewith proper constructor dependencies to verify the health check logic:
- Healthy health report → returns true
- Unhealthy health report → returns false
293-312: Add negative test case.This test only covers the scenario where the user is a provider. Add a test for when
GetProviderByUserIdAsyncreturnsnullto verify thatUserIsProviderAsynccorrectly returnsfalse.
335-356: Test invalid enum conversion.The test only validates the happy path with a valid enum string. The implementation uses
ToEnum<EProviderType>()which can return aFailurefor invalid values. Add a test case with an invalid type string (e.g.,"InvalidType") to verify the error handling path.Apply this approach:
+ [Fact] + public async Task GetProvidersByTypeAsync_WithInvalidTypeString_ShouldReturnFailure() + { + // Arrange + var invalidTypeString = "InvalidType"; + + // Act + var result = await _sut.GetProvidersByTypeAsync(invalidTypeString); + + // Assert + result.IsSuccess.Should().BeFalse(); + result.Error.StatusCode.Should().Be(400); + }
358-379: Test invalid enum conversion.Similar to the provider type test, add a test case with an invalid verification status string to verify error handling when
ToEnum<EVerificationStatus>()fails.
247-380: Consider testing additional public API methods.The test suite doesn't cover several public methods from
ProvidersModuleApi:
GetProvidersBasicInfoAsyncGetProvidersBatchAsyncGetProvidersByCityAsyncGetProvidersByStateAsyncWhile the current coverage is reasonable, adding tests for these methods would improve confidence in the module API surface, especially for batch operations and filtering by location.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs
🧰 Additional context used
🧬 Code graph analysis (1)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (2)
src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs (3)
ModuleApi(18-321)DocumentDto(307-310)DocumentDto(317-320)src/Shared/Extensions/EnumExtensions.cs (1)
Result(17-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: code-analysis
- GitHub Check: build-and-test
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (3)
83-121: Health check logic is bypassed in availability tests.The tests work around the
HealthCheckServicemocking challenges by returningnull, which causesIsAvailableAsyncto skip health check validation and rely solely on basic operations. This means the health check filtering logic (checks with tags "providers" or "database") at lines 42-46 of ProvidersModuleApi.cs is untested.The basic operations test setup is correct: line 95 returns
Success(null)(valid scenario), and line 114 returnsFailurewith an internal error (non-404 status), which correctly fails the availability check.Consider creating integration tests or using a test-specific health check implementation to validate the health monitoring path. For now, document this limitation in a comment above the tests:
+ // Note: These tests bypass HealthCheckService by returning null to avoid complex mocking. + // The health check filtering logic (tags: "providers", "database") is not covered here. + // Consider adding integration tests for full health check validation. [Fact] public async Task IsAvailableAsync_WithHealthySystem_ShouldReturnTrue()
123-124: Remove extra blank line.Two consecutive blank lines here. The file convention uses a single blank line between test methods.
- - + [Fact] public async Task GetProviderByIdAsync_WithExistingProvider_ShouldReturnProvider()
249-508: Excellent test coverage for the module API surface.This comprehensive test suite validates all public methods of
ProvidersModuleApiwith both positive and negative scenarios. The tests correctly handle:
- Enum parsing validation (lines 379-391, 416-428) with expected 400 status codes
- Batch operations using
SequenceEqualfor ID matching- Existence checks returning boolean results
- Geographic filtering by city and state
Optional: Consider adding edge case tests for:
- Empty result collections from filtering queries (e.g.,
GetProvidersByCityAsyncreturning empty list)- Negative scenarios for document/user lookups (non-existent document/user)
- Error propagation when handlers return unexpected failures
These would further strengthen the test suite but are not critical for the current implementation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByUserIdEndpoint.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs(1 hunks)src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs(1 hunks)src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Modules/Providers/Application/Handlers/Commands/UpdateProviderProfileCommandHandler.cs
🧰 Additional context used
🧬 Code graph analysis (3)
src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByUserIdEndpoint.cs (4)
src/Shared/Constants/ApiEndpoints.cs (1)
Providers(35-51)src/Shared/Endpoints/BaseEndpoint.cs (1)
BaseEndpoint(10-130)src/Shared/Contracts/Response.cs (1)
Response(12-20)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
GetProviderByUserIdQuery(92-95)
src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (5)
src/Shared/Constants/ApiEndpoints.cs (1)
Providers(35-51)src/Modules/Providers/Application/Extensions.cs (1)
Extensions(17-52)src/Modules/Providers/API/Mappers/RequestMapperExtensions.cs (1)
DeleteProviderCommand(142-145)src/Modules/Providers/Domain/ValueObjects/ProviderId.cs (3)
ProviderId(9-33)ProviderId(13-18)ProviderId(20-20)src/Modules/Providers/Domain/Entities/Provider.cs (1)
Delete(348-362)
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (2)
src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs (3)
ModuleApi(18-321)DocumentDto(307-310)DocumentDto(317-320)src/Shared/Extensions/EnumExtensions.cs (1)
Result(17-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Code Quality Checks
- GitHub Check: Security Scan
- GitHub Check: build-and-test
🔇 Additional comments (7)
src/Modules/Providers/Application/Handlers/Commands/DeleteProviderCommandHandler.cs (2)
17-21: LGTM: Clean handler structure with appropriate dependencies.The primary constructor pattern is well-used here, and the dependencies (repository, date/time provider, logger) are exactly what's needed for a soft-delete operation with proper auditing and observability.
26-52: LGTM: Implementation is solid and the previous security issue has been addressed.The handler correctly implements soft-delete semantics and the error handling now appropriately returns a generic message (line 50) while keeping detailed diagnostics in the logs. The flow is clean: validate existence, perform soft delete with audit trail, persist changes, and handle errors gracefully.
src/Modules/Providers/Tests/Unit/Application/Services/ProvidersModuleApiTests.cs (1)
205-247: Well-structured test data helper.The
CreateTestProviderDtomethod provides comprehensive test data with properly initialized nested objects. The parameterization byidsupports multiple test scenarios effectively.src/Modules/Providers/API/Endpoints/ProviderAdmin/GetProviderByUserIdEndpoint.cs (4)
1-12: LGTM! Clean imports and namespace organization.All necessary dependencies are imported and properly organized.
14-23: LGTM! Well-documented class declaration.The XML documentation clearly describes the endpoint's purpose and the CQRS architecture pattern. Class properly inherits from BaseEndpoint and implements IEndpoint.
78-91: Good null handling, but verify authorization policy.The explicit null check on lines 87-88 is appropriate defensive programming. It ensures that when a user doesn't have an associated provider, the endpoint returns a clear 404 response rather than a 200 OK with null data.
However, this handler assumes the "SelfOrAdmin" authorization policy (line 60) properly validates that the
userIdroute parameter matches the authenticated user. Please ensure this is verified as noted in the previous comment.
36-62: The original review comment is incorrect.The
SelfOrAdminHandlerincludes a custom authorization handler that reads and validates theuserIdroute parameter against the authenticated user's ID from the "sub" claim. The handler only succeeds if the authenticated user's ID matches the route parameter or the user has admin/super-admin roles. The authorization policy is properly implemented to prevent unauthorized access.Likely an incorrect or invalid review comment.
…modules
Documents module (5 endpoints):
- UploadDocument.bru - POST /api/v1/documents (multipart upload)
- GetDocument.bru - GET /api/v1/documents/{id}
- GetProviderDocuments.bru - GET /api/v1/documents/provider/{providerId}
- VerifyDocument.bru - POST /api/v1/documents/{id}/verify (admin)
- RejectDocument.bru - POST /api/v1/documents/{id}/reject (admin)
SearchProviders module (3 endpoints):
- SearchProviders.bru - POST /api/v1/search (anonymous, geospatial search)
- IndexProvider.bru - POST /api/v1/search/providers/{id}/index (admin)
- RemoveProvider.bru - DELETE /api/v1/search/providers/{id} (admin)
Features:
- Complete REST API documentation in .bru format
- Authorization policies documented (SelfOrAdmin, AdminOnly, AllowAnonymous)
- Request/response examples with realistic data
- Integration with shared Keycloak authentication
- Error codes and troubleshooting sections
- Ranking logic documented (tier → rating → distance)
Progress: 2/3 modules created (Documents ✅, SearchProviders ✅)
Remaining: ServiceCatalogs, Locations (next commit)
Related to Sprint 2 task #5: Create Bruno API collections
…s modules
ServiceCatalogs module (3 endpoints):
- CreateCategory.bru - POST /api/v1/catalogs/categories (admin)
- ListCategories.bru - GET /api/v1/catalogs/categories (public)
- CreateService.bru - POST /api/v1/catalogs/services (admin)
Locations module (2 endpoints):
- GetAddressFromCep.bru - GET /api/v1/locations/cep/{cep} (anonymous)
- ValidateCity.bru - POST /api/v1/locations/validate-city (anonymous)
Features:
- READMEs with endpoint documentation
- CEP lookup with 3-provider fallback chain (ViaCEP → BrasilAPI → OpenCEP)
- IBGE API integration for city validation
- Authorization policies documented
- Compact format for maintainability
Progress: 4/4 modules completed ✅
- Documents ✅ (5 endpoints)
- SearchProviders ✅ (3 endpoints)
- ServiceCatalogs ✅ (3 endpoints)
- Locations ✅ (2 endpoints)
Total: 13 new .bru files + 4 READMEs
Sprint 2 Task #5 completed: Create Bruno API collections for 5 modules
…dpoints Adiciona WithDescription detalhado a todos os 18 endpoints: **Service Endpoints (10):** - Create, Update, Delete: Validações e efeitos - Activate/Deactivate: Impactos na disponibilidade - GetAll, GetById, GetByCategory: Filtros e casos de uso - ChangeCategory: Reorganização de catálogo - Validate: Validação em lote para integrações **ServiceCategory Endpoints (7):** - Create, Update, Delete: Validações e restrições - Activate/Deactivate: Efeitos em cascata nos serviços - GetAll, GetById: Filtros e ordenação Todas as descrições incluem: - Validações esperadas - Efeitos da operação - Casos de uso práticos - Permissões necessárias Itens #5 e #6 concluídos
Summary by CodeRabbit