Conversation
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
There was a problem hiding this comment.
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.
| "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", |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
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).
| var result = new PagedResult<SpeakerDTO>( | ||
| dtos, | ||
| pagedResult.TotalCount, | ||
| request.QueryParameters.PageNumber, | ||
| request.QueryParameters.PageSize); |
There was a problem hiding this comment.
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.
| var result = new PagedResult<ParticipantDTO>( | ||
| dtos, | ||
| pagedResult.TotalCount, | ||
| request.QueryParameters.PageNumber, | ||
| request.QueryParameters.PageSize); |
There was a problem hiding this comment.
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.
| var result = new PagedResult<OrganizerDTO>( | ||
| dtos, | ||
| pagedResult.TotalCount, | ||
| request.QueryParameters.PageNumber, | ||
| request.QueryParameters.PageSize); |
There was a problem hiding this comment.
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.
| builder.OwnsOne(x => x.Name, name => | ||
| { | ||
| name.Property(n => n.FirstName) | ||
| .HasColumnName("Name") | ||
| .HasColumnType("VARCHAR") | ||
| .HasMaxLength(200); | ||
| }); |
There was a problem hiding this comment.
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.
| @event.UpdateDetails( | ||
| request.Title, | ||
| request.Description, | ||
| request.Date, | ||
| request.Location); | ||
|
|
There was a problem hiding this comment.
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.
| 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"; |
There was a problem hiding this comment.
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).
| { | ||
| Task<IEnumerable<EventDTO>> GetRecommendedEventsAsync(int participantId); | ||
| Task<IEnumerable<object>> GetRecommendedConnectionsAsync(int participantId); | ||
| } |
There was a problem hiding this comment.
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).
| app.MapControllers(); | ||
| app.MapHealthChecks("/health"); | ||
| app.MapHealthChecksUI(); |
There was a problem hiding this comment.
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).
- 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
|
|




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:Infrastructure Improvements
Caching
Added Redis caching to query handlers:
GetAllOrganizersQueryHandler: 5-minute cacheGetAllSpeakersQueryHandler: 5-minute cacheGetParticipantsByEventIdQueryHandler: 3-minute cacheWith structured logging for cache hit/miss monitoring.
Rate Limiting
Implemented global rate limiting:
Health Checks
Added comprehensive health monitoring:
/health/healthchecks-ui