Skip to content

refactor/cqrs mediatr migration#1

Merged
alysonsz merged 13 commits intomainfrom
refactor/cqrs-mediatr-migration
Apr 9, 2026
Merged

refactor/cqrs mediatr migration#1
alysonsz merged 13 commits intomainfrom
refactor/cqrs-mediatr-migration

Conversation

@alysonsz
Copy link
Copy Markdown
Owner

@alysonsz alysonsz commented Apr 9, 2026

This PR completes the migration from a traditional Service Layer architecture to a modern CQRS (Command Query Responsibility Segregation) pattern using MediatR, implementing the Result Pattern for consistent error handling across the EventFlow API.

Motivation

The previous architecture relied on service interfaces (IEventService, IOrganizerService, etc.) that were becoming bloated and difficult to maintain. By migrating to CQRS with MediatR, we achieve:

  • Better Separation of Concerns: Commands (writes) and Queries (reads) are explicitly separated
  • Improved Testability: Handlers are isolated and easier to unit test
  • Consistent Error Handling: Result Pattern provides type-safe error handling
  • Cross-Cutting Concerns: MediatR behaviors for validation, logging, and caching
  • Performance: Redis caching integration for frequently accessed queries

Infrastructure Improvements

Caching

Added Redis caching to query handlers:

  • GetAllOrganizersQueryHandler: 5-minute cache
  • GetAllSpeakersQueryHandler: 5-minute cache
  • GetParticipantsByEventIdQueryHandler: 3-minute cache

With structured logging for cache hit/miss monitoring.

Rate Limiting

Implemented global rate limiting:

  • 100 requests per minute per user/IP
  • Fixed window algorithm
  • Returns HTTP 429 when limit exceeded

Health Checks

Added comprehensive health monitoring:

  • Database connectivity check
  • Redis cache connectivity check
  • JSON endpoint at /health
  • UI dashboard at /healthchecks-ui

alysonsz added 10 commits April 8, 2026 17:33
Remove all service interfaces and implementations:
- IEventService, EventService
- IOrganizerService, OrganizerService
- ISpeakerService, SpeakerService
- IParticipantService, ParticipantService
- IAuthService (interface only)

BREAKING CHANGE: Services are replaced by MediatR handlers
Remove test files for deleted service layer:
- EventServiceTests
- OrganizerServiceTests
- ParticipantServiceTests
- SpeakerServiceTests
Add CQRS pattern implementation with commands and queries:
- Events: Create, Update, Delete, GetById, GetAll
- Organizers: Create, Update, Delete, GetById, GetAll
- Speakers: Create, Update, Delete, GetById, GetAll
- Participants: Create, Update, Delete, GetById, GetByEventId

Each command/query has a corresponding handler implementing
IRequestHandler with Result Pattern for consistent responses.
Update all controllers to use MediatR instead of service layer:
- EventController: Use IMediator for commands and queries
- OrganizerController: Use ISender for CQRS operations
- SpeakerController: Use ISender for CQRS operations
- ParticipantController: Use ISender for CQRS operations

Remove direct service dependencies in favor of mediator pattern.
Update controller tests to mock MediatR ISender/IMediator:
- EventControllerTests: Mock IMediator with Result Pattern
- OrganizerControllerTests: Mock ISender with Result types
- SpeakerControllerTests: Mock ISender with Result types
- ParticipantControllerTests: Mock ISender with Result types

Remove obsolete service mocks and update assertions.
Add production-ready infrastructure features:
- Rate Limiting: 100 requests/minute per user/IP (Fixed Window)
- Health Checks: /health endpoint for DB and Redis
- Health Checks UI: Dashboard at /healthchecks-ui

Update AppConfiguration with AddRateLimitingConfig() and
AddHealthCheckConfig() extension methods.
Update AutoMapper to resolve GHSA-rvv3-g6hj-g44x security vulnerability:
- Vulnerability: Denial of Service via uncontrolled recursion
- Fixed in version 16.1.1
- Update Microsoft.Extensions.Logging.Abstractions to 10.0.0
- Update in both Application and Test projects
Clean up legacy files no longer needed:
- Remove old DTOs (EventDTO, OrganizerDTO, SpeakerDTO, ParticipantDTO, UserDTO, etc.)
- Remove legacy command classes (EventCommand, OrganizerCommand, etc.)
- Remove old Abstractions (ICommand, IQuery, etc.)
- Remove Behaviors (LoggingBehavior, ValidationBehavior)
- Remove Services (AuthService)
- Clean up test files (IntegrationTestBase, ValueObjects tests)
- Clean up redundant files after CQRS migration
Complete domain layer implementation:
- Add Domain Primitives (Result<T>, Error, Entity, ValueObject)
- Add ValueObjects (Email, EventTitle, EventLocation, PersonName)
- Add Domain Events (EventCreatedDomainEvent, EventDeletedDomainEvent, EventUpdatedDomainEvent)
- Add Infrastructure services (CacheService, JwtTokenService, PasswordHasher, UnitOfWork)
- Add ExceptionHandlingMiddleware and ResultExtensions
- Remove legacy DTOs and Commands from EventFlow.Core
- Move Repository interfaces to root namespace
- Update all Models with proper domain logic
- Add required modifier to non-nullable properties in SpeakerCommand, OrganizerCommand, and EventCommand
- Add await Task.CompletedTask to placeholder async methods in controllers to resolve async method lacks await warnings
Copilot AI review requested due to automatic review settings April 9, 2026 17:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the API’s architectural migration from a service-layer approach to CQRS using MediatR, introduces a Result pattern for consistent error handling, and adds cross-cutting infrastructure (rate limiting + health checks) plus new domain primitives (entities/value objects/domain events).

Changes:

  • Replaced service-layer CRUD flows with MediatR commands/queries + handlers (and added pipeline behaviors for validation/logging).
  • Introduced domain primitives (Result/Error, Entity, ValueObjects, Domain Events) and updated EF Core mappings for owned value objects.
  • Added global exception middleware, rate limiting, and health checks endpoints/UI, plus Redis caching abstractions.

Reviewed changes

Copilot reviewed 154 out of 154 changed files in this pull request and generated 32 comments.

Show a summary per file
File Description
EventFlow.Presentation/Program.cs Wires middleware + endpoints (exception handling, rate limiting, health checks).
EventFlow.Presentation/Middleware/ExceptionHandlingMiddleware.cs Adds global exception-to-HTTP mapping.
EventFlow.Presentation/GlobalUsing.cs Updates global usings for MediatR/Application layer.
EventFlow.Presentation/Extensions/ResultExtensions.cs Converts Result/Error into IActionResult responses.
EventFlow.Presentation/EventFlow.Presentation.csproj Adds rate limit + health check packages.
EventFlow.Presentation/Controllers/StatisticsController.cs Switches DTO namespace; keeps repository-based stats.
EventFlow.Presentation/Controllers/SpeakerController.cs Migrates speaker endpoints to MediatR commands/queries.
EventFlow.Presentation/Controllers/RecommendationController.cs Adds recommendation endpoints (service-based).
EventFlow.Presentation/Controllers/ParticipantController.cs Migrates participant endpoints to MediatR commands/queries.
EventFlow.Presentation/Controllers/OrganizerController.cs Migrates organizer endpoints to MediatR commands/queries.
EventFlow.Presentation/Controllers/HomeController.cs Adds root “/” health-ish endpoint.
EventFlow.Presentation/Controllers/EventController.cs Migrates event endpoints to MediatR + adjusts REST routes.
EventFlow.Presentation/Controllers/AuthController.cs Moves to ControllerBase + updated DTO namespace.
EventFlow.Presentation/Config/AppConfiguration.cs Adds DI wiring for CQRS, rate limiting, health checks, and infra services.
EventFlow.Presentation/appsettings.json Updates connection string/JWT key (now containing real credentials).
EventFlow.Infrastructure/Services/PasswordHasher.cs Introduces password hashing abstraction implementation.
EventFlow.Infrastructure/Services/JwtTokenService.cs Introduces JWT generation/validation service.
EventFlow.Infrastructure/Repository/SpeakerRepository.cs Updates filtering/sorting for value objects.
EventFlow.Infrastructure/Repository/ParticipantRepository.cs Updates filtering/sorting + adds shared-events query helper.
EventFlow.Infrastructure/Repository/OrganizerRepository.cs Updates filtering/sorting for value objects.
EventFlow.Infrastructure/Repository/EventRepository.cs Updates filtering/sorting for value objects.
EventFlow.Infrastructure/Profiles/MappingProfile.cs Moves DTO mapping to Application DTO namespace.
EventFlow.Infrastructure/Persistence/UnitOfWork.cs Adds UnitOfWork wrapper around DbContext.SaveChangesAsync.
EventFlow.Infrastructure/GlobalUsing.cs Updates repository namespace usage.
EventFlow.Infrastructure/Events/MediatRDomainEventDispatcher.cs Dispatches domain events via MediatR publish.
EventFlow.Infrastructure/Data/Mapping/UserMap.cs Maps Email as owned type + adds LastLoginAt.
EventFlow.Infrastructure/Data/Mapping/SpeakerMap.cs Maps Name/Email as owned types.
EventFlow.Infrastructure/Data/Mapping/ParticipantMap.cs Maps Name/Email as owned types.
EventFlow.Infrastructure/Data/Mapping/OrganizerMap.cs Maps Name/Email as owned types + timestamps.
EventFlow.Infrastructure/Data/Mapping/EventMap.cs Maps Title/Location as owned types.
EventFlow.Infrastructure/Data/EventFlowContext.cs Adds domain event dispatching in SaveChangesAsync override.
EventFlow.Core/ValueObjects/PersonName.cs Adds PersonName value object.
EventFlow.Core/ValueObjects/EventTitle.cs Adds EventTitle value object.
EventFlow.Core/ValueObjects/EventLocation.cs Adds EventLocation value object.
EventFlow.Core/ValueObjects/Email.cs Adds Email value object.
EventFlow.Core/Services/Interfaces/ISpeakerService.cs Deletes legacy service interface.
EventFlow.Core/Services/Interfaces/IParticipantService.cs Deletes legacy service interface.
EventFlow.Core/Services/Interfaces/IOrganizerService.cs Deletes legacy service interface.
EventFlow.Core/Services/Interfaces/IEventService.cs Deletes legacy service interface.
EventFlow.Core/Repository/IUserRepository.cs Moves repository interfaces to new namespace.
EventFlow.Core/Repository/ISpeakerRepository.cs Moves repository interfaces to new namespace.
EventFlow.Core/Repository/IParticipantRepository.cs Moves repository interfaces to new namespace.
EventFlow.Core/Repository/IOrganizerRepository.cs Moves repository interfaces to new namespace.
EventFlow.Core/Repository/IEventRepository.cs Moves repository interfaces to new namespace.
EventFlow.Core/Primitives/ValueObject.cs Adds base ValueObject equality implementation.
EventFlow.Core/Primitives/Result.cs Adds Result + Result primitives.
EventFlow.Core/Primitives/IHasDomainEvents.cs Adds domain event tracking interface.
EventFlow.Core/Primitives/IDomainEventDispatcher.cs Adds dispatcher abstraction.
EventFlow.Core/Primitives/IDomainEvent.cs Adds domain event contract.
EventFlow.Core/Primitives/IBusinessRule.cs Adds business rule abstraction.
EventFlow.Core/Primitives/Error.cs Adds Error + ErrorType primitives.
EventFlow.Core/Primitives/Entity.cs Adds Entity base + domain event/rule helpers.
EventFlow.Core/Primitives/DomainEvent.cs Adds base DomainEvent.
EventFlow.Core/Primitives/BusinessRuleValidationException.cs Adds exception for broken business rules.
EventFlow.Core/Models/User.cs Refactors User into Entity + value object email + rules.
EventFlow.Core/Models/SpeakerEvent.cs Refactors SpeakerEvent construction/immutability.
EventFlow.Core/Models/Speaker.cs Refactors Speaker into Entity + value objects + behavior.
EventFlow.Core/Models/Participant.cs Refactors Participant into Entity + value objects + behavior.
EventFlow.Core/Models/Organizer.cs Refactors Organizer into Entity + value objects + behavior.
EventFlow.Core/Models/Event.cs Refactors Event into Entity + value objects + domain events/rules.
EventFlow.Core/Models/DTOs/DashboardStatsDTO.cs Deletes legacy Core DTO.
EventFlow.Core/GlobalUsing.cs Updates global usings to new primitives/events/value objects.
EventFlow.Core/Events/EventUpdatedDomainEvent.cs Adds EventUpdated domain event.
EventFlow.Core/Events/EventDeletedDomainEvent.cs Adds EventDeleted domain event.
EventFlow.Core/Events/EventCreatedDomainEvent.cs Adds EventCreated domain event.
EventFlow.Core/Commands/SpeakerCommand.cs Deletes legacy Core command model.
EventFlow.Core/Commands/ParticipantCommand.cs Deletes legacy Core command model.
EventFlow.Core/Commands/OrganizerCommand.cs Deletes legacy Core command model.
EventFlow.Application/Services/SpeakerService.cs Removes legacy service implementation.
EventFlow.Application/Services/RecommendationService.cs Adds recommendation logic service.
EventFlow.Application/Services/ParticipantService.cs Removes legacy service implementation.
EventFlow.Application/Services/OrganizerService.cs Removes legacy service implementation.
EventFlow.Application/Services/IRecommendationService.cs Adds recommendation service interface.
EventFlow.Application/Services/ICacheService.cs Adds cache abstraction.
EventFlow.Application/Services/IAuthService.cs Moves auth service interface into Application.
EventFlow.Application/Services/EventService.cs Removes legacy service implementation.
EventFlow.Application/Services/CacheService.cs Implements cache abstraction over IDistributedCache.
EventFlow.Application/Services/AuthService.cs Refactors auth to use IPasswordHasher + IJwtTokenService.
EventFlow.Application/GlobalUsing.cs Updates global usings for CQRS + new namespaces.
EventFlow.Application/Features/Speakers/Queries/GetSpeakerById/GetSpeakerByIdQueryHandler.cs Adds speaker-by-id query handler + caching.
EventFlow.Application/Features/Speakers/Queries/GetSpeakerById/GetSpeakerByIdQuery.cs Adds speaker-by-id query type.
EventFlow.Application/Features/Speakers/Queries/GetAllSpeakers/GetAllSpeakersQueryHandler.cs Adds paged speakers query handler + caching/logging.
EventFlow.Application/Features/Speakers/Queries/GetAllSpeakers/GetAllSpeakersQuery.cs Adds speakers list query type.
EventFlow.Application/Features/Speakers/Commands/UpdateSpeaker/UpdateSpeakerCommandHandler.cs Adds update speaker command handler.
EventFlow.Application/Features/Speakers/Commands/UpdateSpeaker/UpdateSpeakerCommand.cs Adds update speaker command type.
EventFlow.Application/Features/Speakers/Commands/DeleteSpeaker/DeleteSpeakerCommandHandler.cs Adds delete speaker command handler.
EventFlow.Application/Features/Speakers/Commands/DeleteSpeaker/DeleteSpeakerCommand.cs Adds delete speaker command type.
EventFlow.Application/Features/Speakers/Commands/CreateSpeaker/CreateSpeakerCommandHandler.cs Adds create speaker command handler.
EventFlow.Application/Features/Speakers/Commands/CreateSpeaker/CreateSpeakerCommand.cs Adds create speaker command type.
EventFlow.Application/Features/Participants/Queries/GetParticipantsByEventId/GetParticipantsByEventIdQueryHandler.cs Adds participants-by-event query handler + caching/logging.
EventFlow.Application/Features/Participants/Queries/GetParticipantsByEventId/GetParticipantsByEventIdQuery.cs Adds participants-by-event query type.
EventFlow.Application/Features/Participants/Queries/GetParticipantById/GetParticipantByIdQueryHandler.cs Adds participant-by-id query handler + caching.
EventFlow.Application/Features/Participants/Queries/GetParticipantById/GetParticipantByIdQuery.cs Adds participant-by-id query type.
EventFlow.Application/Features/Participants/Commands/UpdateParticipant/UpdateParticipantCommandHandler.cs Adds update participant command handler.
EventFlow.Application/Features/Participants/Commands/UpdateParticipant/UpdateParticipantCommand.cs Adds update participant command type.
EventFlow.Application/Features/Participants/Commands/DeleteParticipant/DeleteParticipantCommandHandler.cs Adds delete participant command handler.
EventFlow.Application/Features/Participants/Commands/DeleteParticipant/DeleteParticipantCommand.cs Adds delete participant command type.
EventFlow.Application/Features/Participants/Commands/CreateParticipant/CreateParticipantCommandHandler.cs Adds create participant command handler.
EventFlow.Application/Features/Participants/Commands/CreateParticipant/CreateParticipantCommand.cs Adds create participant command type.
EventFlow.Application/Features/Organizers/Queries/GetOrganizerById/GetOrganizerByIdQueryHandler.cs Adds organizer-by-id query handler + caching.
EventFlow.Application/Features/Organizers/Queries/GetOrganizerById/GetOrganizerByIdQuery.cs Adds organizer-by-id query type.
EventFlow.Application/Features/Organizers/Queries/GetAllOrganizers/GetAllOrganizersQueryHandler.cs Adds paged organizers query handler + caching/logging.
EventFlow.Application/Features/Organizers/Queries/GetAllOrganizers/GetAllOrganizersQuery.cs Adds organizers list query type.
EventFlow.Application/Features/Organizers/Commands/UpdateOrganizer/UpdateOrganizerCommandHandler.cs Adds update organizer command handler.
EventFlow.Application/Features/Organizers/Commands/UpdateOrganizer/UpdateOrganizerCommand.cs Adds update organizer command type.
EventFlow.Application/Features/Organizers/Commands/DeleteOrganizer/DeleteOrganizerCommandHandler.cs Adds delete organizer command handler.
EventFlow.Application/Features/Organizers/Commands/DeleteOrganizer/DeleteOrganizerCommand.cs Adds delete organizer command type.
EventFlow.Application/Features/Organizers/Commands/CreateOrganizer/CreateOrganizerCommandHandler.cs Adds create organizer command handler.
EventFlow.Application/Features/Organizers/Commands/CreateOrganizer/CreateOrganizerCommand.cs Adds create organizer command type.
EventFlow.Application/Features/Events/Queries/GetEventById/GetEventByIdQueryHandler.cs Adds event-by-id query handler + caching.
EventFlow.Application/Features/Events/Queries/GetEventById/GetEventByIdQuery.cs Adds event-by-id query type.
EventFlow.Application/Features/Events/Queries/GetAllEvents/GetAllEventsQueryHandler.cs Adds paged events query handler.
EventFlow.Application/Features/Events/Queries/GetAllEvents/GetAllEventsQuery.cs Adds events list query type.
EventFlow.Application/Features/Events/Commands/UpdateEvent/UpdateEventCommandHandler.cs Adds update event command handler.
EventFlow.Application/Features/Events/Commands/UpdateEvent/UpdateEventCommand.cs Adds update event command type.
EventFlow.Application/Features/Events/Commands/DeleteEvent/DeleteEventCommandHandler.cs Adds delete event command handler + domain event.
EventFlow.Application/Features/Events/Commands/DeleteEvent/DeleteEventCommand.cs Adds delete event command type.
EventFlow.Application/Features/Events/Commands/CreateEvent/CreateEventCommandHandler.cs Adds create event command handler + domain event.
EventFlow.Application/Features/Events/Commands/CreateEvent/CreateEventCommand.cs Adds create event command type.
EventFlow.Application/EventFlow.Application.csproj Updates packages (AutoMapper, adds MediatR).
EventFlow.Application/DTOs/UserPasswordUpdateDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/UserDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/SpeakerDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/ParticipantDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/OrganizerDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/EventSummaryDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/EventDTO.cs Moves DTO namespace to Application.
EventFlow.Application/DTOs/DashboardStatsDTO.cs Adds Application-level dashboard DTO.
EventFlow.Application/Commands/SpeakerCommand.cs Adds Application command model.
EventFlow.Application/Commands/RegisterUserCommand.cs Moves command namespace to Application.
EventFlow.Application/Commands/ParticipantCommand.cs Adds Application command model.
EventFlow.Application/Commands/OrganizerCommand.cs Adds Application command model.
EventFlow.Application/Commands/LoginUserCommand.cs Moves command namespace to Application.
EventFlow.Application/Commands/EventCommand.cs Moves command namespace + adds required fields.
EventFlow.Application/Behaviors/ValidationBehavior.cs Adds FluentValidation MediatR pipeline behavior.
EventFlow.Application/Behaviors/LoggingBehavior.cs Adds request logging/timing pipeline behavior.
EventFlow.Application/Abstractions/IUnitOfWork.cs Adds unit of work abstraction.
EventFlow.Application/Abstractions/IQuery.cs Adds query marker interface.
EventFlow.Application/Abstractions/IPasswordHasher.cs Adds password hasher abstraction.
EventFlow.Application/Abstractions/IJwtTokenService.cs Adds JWT token abstraction.
EventFlow.Application/Abstractions/ICommand.cs Adds command marker interfaces.
EventFlow-API.Tests/ValueObjects/EventTitleTests.cs Adds tests for EventTitle value object.
EventFlow-API.Tests/ValueObjects/EmailTests.cs Adds tests for Email value object.
EventFlow-API.Tests/Services/SpeakerServiceTests.cs Removes legacy service tests.
EventFlow-API.Tests/Services/ParticipantServiceTests.cs Removes legacy service tests.
EventFlow-API.Tests/Services/OrganizerServiceTests.cs Removes legacy service tests.
EventFlow-API.Tests/Services/EventServiceTests.cs Removes legacy service tests.
EventFlow-API.Tests/GlobalUsing.cs Updates test global usings to new namespaces.
EventFlow-API.Tests/EventFlow.Tests.csproj Updates AutoMapper package version.
EventFlow-API.Tests/Data/IntegrationTestBase.cs Updates seeding to new entity factory pattern.
EventFlow-API.Tests/Controllers/SpeakerControllerTests.cs Updates controller tests to MediatR-based controllers.
EventFlow-API.Tests/Controllers/ParticipantControllerTests.cs Updates controller tests to MediatR-based controllers.
EventFlow-API.Tests/Controllers/OrganizerControllerTests.cs Updates controller tests to MediatR-based controllers.
EventFlow-API.Tests/Controllers/EventControllerTests.cs Updates controller tests to MediatR-based controllers + REST routes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 24 to 30
"ConnectionStrings": {
"DevConnectionString": "Server=INSIRA AQUI O IP; Database = NOME DO SEU BANCO DE DADOS; User Id = SEU USUARIO; Password = SUA SENHA;"
"DevConnectionString": "Server=DESKTOP-M76AS7V\\ALYSONSZ; Database=EventFlow; User Id=EventUser; Password=12345; TrustServerCertificate=True;"
},

"Jwt": {
"Key": "chave-super-secreta-para-token-jwt",
"Key": "NzM4QkFGNjItQ0M5Qi00RDlGLUEzQTYtQzBFRDdCRkU1ODdELURDMjYtNDhBNC05N0JBLTAxMDI4RkQ0OTM4Qw==",
"Issuer": "EventFlowAPI",
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appsettings.json now contains a real SQL Server connection string (including username/password) and a JWT signing key. These are secrets/environment-specific values and should not be committed; move them to user-secrets/KeyVault/CI environment variables and keep only placeholders in the repo.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +45
public static Result<T> Success(T value) => new(value, true, Error.None);
public new static Result<T> Failure(Error error) => new(default, false, error);

public static implicit operator Result<T>(T? value) => value is not null ? Success(value) : Failure(Error.None);
public static implicit operator Result<T>(Error error) => Failure(error);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result<T> defines implicit operator Result<T>(T? value) that returns Failure(Error.None) when value is null. Result explicitly forbids failure results with Error.None, so this conversion will throw at runtime. Either remove this implicit conversion or return a real error (or treat null as success only when that is explicitly desired).

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +50
var result = new PagedResult<SpeakerDTO>(
dtos,
pagedResult.TotalCount,
request.QueryParameters.PageNumber,
request.QueryParameters.PageSize);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PagedResult<T> constructor signature is (items, pageNumber, pageSize, totalCount), but this handler passes (items, totalCount, pageNumber, pageSize), which will swap pagination metadata (page number becomes total count, etc.). Build the PagedResult using the correct parameter order.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +53
var result = new PagedResult<ParticipantDTO>(
dtos,
pagedResult.TotalCount,
request.QueryParameters.PageNumber,
request.QueryParameters.PageSize);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PagedResult<T> constructor is (items, pageNumber, pageSize, totalCount), but this handler passes (items, totalCount, pageNumber, pageSize), producing incorrect pagination fields and headers. Use the correct argument order when constructing the DTO result.

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +50
var result = new PagedResult<OrganizerDTO>(
dtos,
pagedResult.TotalCount,
request.QueryParameters.PageNumber,
request.QueryParameters.PageSize);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PagedResult<T> is constructed with (items, pageNumber, pageSize, totalCount), but here it is built with (items, totalCount, pageNumber, pageSize), which corrupts pagination metadata. Construct the PagedResult with the correct parameter order.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +20
builder.OwnsOne(x => x.Name, name =>
{
name.Property(n => n.FirstName)
.HasColumnName("Name")
.HasColumnType("VARCHAR")
.HasMaxLength(200);
});
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PersonName includes LastName, but this mapping only persists FirstName into the Name column. That will discard LastName when entities are rehydrated. Persist LastName (or a single FullName value) consistently with the value object design.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +33
@event.UpdateDetails(
request.Title,
request.Description,
request.Date,
request.Location);

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UpdateEventCommand includes OrganizerId, but the handler/event aggregate update logic never applies it (only title/description/date/location are updated). If changing organizer is supported, update the aggregate accordingly; otherwise remove OrganizerId from the command/DTO to avoid misleading API contracts.

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +120
public class EventDateMustBeInFutureRule : IBusinessRule
{
private readonly DateTime _date;

public EventDateMustBeInFutureRule(DateTime date)
{
_date = date;
}

public bool IsBroken() => _date < DateTime.Now.AddHours(-1);
public string Message => "Event date must be in the future";
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EventDateMustBeInFutureRule considers a date valid if it is within the last hour (_date < DateTime.Now.AddHours(-1)). That allows scheduling events in the past (up to 1 hour) and also uses local time instead of UTC while the rest of the model uses UtcNow. If the intent is strictly "future", compare against DateTime.UtcNow (optionally with an explicit allowed clock-skew constant).

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +7
{
Task<IEnumerable<EventDTO>> GetRecommendedEventsAsync(int participantId);
Task<IEnumerable<object>> GetRecommendedConnectionsAsync(int participantId);
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetRecommendedConnectionsAsync returns IEnumerable<object>, but the implementation maps to IEnumerable<ParticipantDTO>. Returning object reduces type safety and produces poor OpenAPI/Swagger schemas for this endpoint. Prefer returning a concrete DTO type (e.g., IEnumerable<ParticipantDTO> or a dedicated connection recommendation DTO).

Copilot uses AI. Check for mistakes.
Comment on lines 42 to +44
app.MapControllers();
app.MapHealthChecks("/health");
app.MapHealthChecksUI();
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MapHealthChecks("/health") uses the default response writer, but HealthChecks.UI typically expects the UI JSON format. Without configuring HealthCheckOptions.ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse, the UI endpoint may not be able to parse the health response correctly. Consider mapping /health with the UI response writer (and any tag filtering you want).

Copilot uses AI. Check for mistakes.
alysonsz added 3 commits April 9, 2026 14:43
- Add JWT key validation with null-check and minimum length requirement
- Fix Entity operator== to use ReferenceEquals for null comparison
- Seal HomeController and add route prefix + ProducesResponseType
- Replace Any() with Count comparisons for clarity and performance
- Convert constant arrays to static readonly fields
- Rename UserPasswordUpdateDTO to UserPasswordUpdateDto (naming convention)
- Remove unused private setters from Event model
- Remove TODO comments from placeholder controller methods
- Fix PagedResult parameter order in 3 handlers (was corrupting pagination)
- Fix Result implicit operator to use proper NullValue error
- Fix OrganizerMap to persist LastName (was only saving FirstName)
- Remove unused OrganizerId from UpdateEventCommand
- Fix EventDateMustBeInFutureRule to use UtcNow and strictly reject past dates
- Change IRecommendationService to return concrete ParticipantDTO type
- Configure HealthChecks with UI response writer
- Remove operator == and != overloads from Entity<T>
- Replace Count() with Any() in RecommendationService for performance
- Change ToActionResult return type from IActionResult to ObjectResult
- Rename userClaims to user in AuthService to match interface
- Extract GetSigningKey() method in JwtTokenService to reduce direct config access
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

@alysonsz alysonsz merged commit dc4cc5d into main Apr 9, 2026
3 checks passed
@alysonsz alysonsz deleted the refactor/cqrs-mediatr-migration branch April 9, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants