From bd78fe6533fcb259d5254d2f39767bcf5b988d30 Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Sun, 30 Aug 2026 04:12:21 -0400 Subject: [PATCH] Merge Features.Auth and Features.UserManagement into Features.Users --- web/backend/API/API.Core/API.Core.csproj | 3 +- web/backend/API/API.Core/Dockerfile | 6 +- web/backend/API/API.Core/Program.cs | 15 +-- web/backend/API/API.Specs/Dockerfile | 6 +- web/backend/Biergarten.API.slnx | 25 +++- .../Database.Seed/Database.Seed.csproj | 2 +- .../SendRegistrationEmailHandler.cs | 2 +- .../SendResendConfirmationEmailHandler.cs | 2 +- .../Commands/UpdateUserHandlerTests.cs | 22 ---- .../Features.UserManagement.Tests.csproj | 25 ---- .../Commands/UpdateUser/UpdateUserCommand.cs | 10 -- .../Commands/UpdateUser/UpdateUserHandler.cs | 13 -- ...erManagementServiceCollectionExtensions.cs | 20 --- .../Features.UserManagement.csproj | 20 --- .../Repository/IUserAccountRepository.cs | 33 ----- .../Repository/UserAccountRepository.cs | 118 ------------------ .../Commands/ConfirmUserHandlerTests.cs | 0 .../Commands/DeleteAccountHandlerTests.cs | 0 .../Commands/RefreshTokenHandlerTests.cs | 0 .../Commands/RegisterUserHandlerTests.cs | 0 .../ResendConfirmationEmailHandlerTests.cs | 0 .../Commands/UpdateEmailHandlerTests.cs | 0 .../Commands/UpdatePasswordHandlerTests.cs | 0 .../Commands/UpdateProfileHandlerTests.cs | 0 .../Commands/UpdateUsernameHandlerTests.cs | 0 .../Features.Users.Tests.csproj} | 2 +- .../Queries/GetAllUsersHandlerTests.cs | 8 +- .../Queries/GetUserByIdHandlerTests.cs | 8 +- .../Queries/LoginHandlerTests.cs | 0 .../Services/TokenServiceRefreshTests.cs | 0 .../Services/TokenServiceValidationTests.cs | 0 .../TestSupport/UserManagerMockFactory.cs | 0 .../ConfirmUser/ConfirmUserCommand.cs | 0 .../ConfirmUser/ConfirmUserHandler.cs | 0 .../DeleteAccount/DeleteAccountCommand.cs | 0 .../DeleteAccount/DeleteAccountHandler.cs | 0 .../Commands/Login/LoginCommand.cs | 0 .../Commands/Login/LoginHandler.cs | 0 .../Commands/Login/LoginValidator.cs | 0 .../RefreshToken/RefreshTokenCommand.cs | 0 .../RefreshToken/RefreshTokenHandler.cs | 0 .../RefreshToken/RefreshTokenValidator.cs | 0 .../RegisterUser/RegisterUserCommand.cs | 0 .../RegisterUser/RegisterUserHandler.cs | 0 .../RegisterUser/RegisterUserValidator.cs | 0 .../ResendConfirmationEmailCommand.cs | 0 .../ResendConfirmationEmailHandler.cs | 0 .../UpdateEmail/UpdateEmailCommand.cs | 0 .../UpdateEmail/UpdateEmailHandler.cs | 2 +- .../UpdateEmail/UpdateEmailValidator.cs | 0 .../UpdatePassword/UpdatePasswordCommand.cs | 0 .../UpdatePassword/UpdatePasswordHandler.cs | 0 .../UpdatePassword/UpdatePasswordValidator.cs | 0 .../UpdateProfile/UpdateProfileCommand.cs | 0 .../UpdateProfile/UpdateProfileHandler.cs | 0 .../UpdateProfile/UpdateProfileValidator.cs | 0 .../UpdateUsername/UpdateUsernameCommand.cs | 0 .../UpdateUsername/UpdateUsernameHandler.cs | 0 .../UpdateUsername/UpdateUsernameValidator.cs | 0 .../Controllers/AuthController.cs | 0 .../Controllers/UserController.cs | 6 +- ...FeaturesAuthServiceCollectionExtensions.cs | 9 +- .../Dtos/AuthPayloads.cs | 0 .../Features.Users.csproj} | 5 +- .../Identity/ApplicationUser.cs | 2 +- .../Identity/Argon2PasswordHasher.cs | 0 .../Identity/DapperUserStore.cs | 5 +- .../Identity/UserAccountExtensions.cs | 2 +- .../Queries/GetAllUsers/GetAllUsersHandler.cs | 6 +- .../Queries/GetAllUsers/GetAllUsersQuery.cs | 2 +- .../Queries/GetUserById/GetUserByIdHandler.cs | 6 +- .../Queries/GetUserById/GetUserByIdQuery.cs | 2 +- .../Repository/IUserListRepository.cs | 21 ++++ .../Repository/UserListRepository.cs | 50 ++++++++ .../Services/ITokenService.cs | 0 .../Services/TokenService.cs | 0 .../Emails/SendRegistrationEmailCommand.cs | 2 +- .../SendResendConfirmationEmailCommand.cs | 2 +- 78 files changed, 137 insertions(+), 325 deletions(-) delete mode 100644 web/backend/Features/Features.UserManagement.Tests/Commands/UpdateUserHandlerTests.cs delete mode 100644 web/backend/Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj delete mode 100644 web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserCommand.cs delete mode 100644 web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs delete mode 100644 web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs delete mode 100644 web/backend/Features/Features.UserManagement/Features.UserManagement.csproj delete mode 100644 web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs delete mode 100644 web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/ConfirmUserHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/DeleteAccountHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/RefreshTokenHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/RegisterUserHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/ResendConfirmationEmailHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/UpdateEmailHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/UpdatePasswordHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/UpdateProfileHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Commands/UpdateUsernameHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests/Features.Auth.Tests.csproj => Features.Users.Tests/Features.Users.Tests.csproj} (92%) rename web/backend/Features/{Features.UserManagement.Tests => Features.Users.Tests}/Queries/GetAllUsersHandlerTests.cs (75%) rename web/backend/Features/{Features.UserManagement.Tests => Features.Users.Tests}/Queries/GetUserByIdHandlerTests.cs (84%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Queries/LoginHandlerTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Services/TokenServiceRefreshTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/Services/TokenServiceValidationTests.cs (100%) rename web/backend/Features/{Features.Auth.Tests => Features.Users.Tests}/TestSupport/UserManagerMockFactory.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/ConfirmUser/ConfirmUserCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/ConfirmUser/ConfirmUserHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/DeleteAccount/DeleteAccountCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/DeleteAccount/DeleteAccountHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/Login/LoginCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/Login/LoginHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/Login/LoginValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RefreshToken/RefreshTokenCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RefreshToken/RefreshTokenHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RefreshToken/RefreshTokenValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RegisterUser/RegisterUserCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RegisterUser/RegisterUserHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/RegisterUser/RegisterUserValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateEmail/UpdateEmailCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateEmail/UpdateEmailHandler.cs (96%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateEmail/UpdateEmailValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdatePassword/UpdatePasswordCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdatePassword/UpdatePasswordHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdatePassword/UpdatePasswordValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateProfile/UpdateProfileCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateProfile/UpdateProfileHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateProfile/UpdateProfileValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateUsername/UpdateUsernameCommand.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateUsername/UpdateUsernameHandler.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Commands/UpdateUsername/UpdateUsernameValidator.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Controllers/AuthController.cs (100%) rename web/backend/Features/{Features.UserManagement => Features.Users}/Controllers/UserController.cs (89%) rename web/backend/Features/{Features.Auth => Features.Users}/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs (81%) rename web/backend/Features/{Features.Auth => Features.Users}/Dtos/AuthPayloads.cs (100%) rename web/backend/Features/{Features.Auth/Features.Auth.csproj => Features.Users/Features.Users.csproj} (93%) rename web/backend/Features/{Features.Auth => Features.Users}/Identity/ApplicationUser.cs (88%) rename web/backend/Features/{Features.Auth => Features.Users}/Identity/Argon2PasswordHasher.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Identity/DapperUserStore.cs (98%) rename web/backend/Features/{Features.Auth => Features.Users}/Identity/UserAccountExtensions.cs (87%) rename web/backend/Features/{Features.UserManagement => Features.Users}/Queries/GetAllUsers/GetAllUsersHandler.cs (66%) rename web/backend/Features/{Features.UserManagement => Features.Users}/Queries/GetAllUsers/GetAllUsersQuery.cs (86%) rename web/backend/Features/{Features.UserManagement => Features.Users}/Queries/GetUserById/GetUserByIdHandler.cs (78%) rename web/backend/Features/{Features.UserManagement => Features.Users}/Queries/GetUserById/GetUserByIdQuery.cs (67%) create mode 100644 web/backend/Features/Features.Users/Repository/IUserListRepository.cs create mode 100644 web/backend/Features/Features.Users/Repository/UserListRepository.cs rename web/backend/Features/{Features.Auth => Features.Users}/Services/ITokenService.cs (100%) rename web/backend/Features/{Features.Auth => Features.Users}/Services/TokenService.cs (100%) diff --git a/web/backend/API/API.Core/API.Core.csproj b/web/backend/API/API.Core/API.Core.csproj index 36e47d4c..09478802 100644 --- a/web/backend/API/API.Core/API.Core.csproj +++ b/web/backend/API/API.Core/API.Core.csproj @@ -22,8 +22,7 @@ - - + diff --git a/web/backend/API/API.Core/Dockerfile b/web/backend/API/API.Core/Dockerfile index 21132363..4ba26f84 100644 --- a/web/backend/API/API.Core/Dockerfile +++ b/web/backend/API/API.Core/Dockerfile @@ -22,8 +22,6 @@ COPY ["Database/Database.Migrations/Database.Migrations.csproj", "Database/Datab COPY ["Database/Database.Seed/Database.Seed.csproj", "Database/Database.Seed/"] COPY ["Domain/Domain.Entities/Domain.Entities.csproj", "Domain/Domain.Entities/"] COPY ["Domain/Domain.Exceptions/Domain.Exceptions.csproj", "Domain/Domain.Exceptions/"] -COPY ["Features/Features.Auth/Features.Auth.csproj", "Features/Features.Auth/"] -COPY ["Features/Features.Auth.Tests/Features.Auth.Tests.csproj", "Features/Features.Auth.Tests/"] COPY ["Features/Features.Breweries/Features.Breweries.csproj", "Features/Features.Breweries/"] COPY ["Features/Features.Breweries.Tests/Features.Breweries.Tests.csproj", "Features/Features.Breweries.Tests/"] COPY ["Features/Features.Emails/Features.Emails.csproj", "Features/Features.Emails/"] @@ -32,8 +30,8 @@ COPY ["Features/Features.Locations/Features.Locations.csproj", "Features/Feature COPY ["Features/Features.Locations.Tests/Features.Locations.Tests.csproj", "Features/Features.Locations.Tests/"] COPY ["Features/Features.PhotoUpload/Features.PhotoUpload.csproj", "Features/Features.PhotoUpload/"] COPY ["Features/Features.PhotoUpload.Tests/Features.PhotoUpload.Tests.csproj", "Features/Features.PhotoUpload.Tests/"] -COPY ["Features/Features.UserManagement/Features.UserManagement.csproj", "Features/Features.UserManagement/"] -COPY ["Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj", "Features/Features.UserManagement.Tests/"] +COPY ["Features/Features.Users/Features.Users.csproj", "Features/Features.Users/"] +COPY ["Features/Features.Users.Tests/Features.Users.Tests.csproj", "Features/Features.Users.Tests/"] COPY ["Infrastructure/Infrastructure.Configuration/Infrastructure.Configuration.csproj", "Infrastructure/Infrastructure.Configuration/"] COPY ["Infrastructure/Infrastructure.Email/Infrastructure.Email.csproj", "Infrastructure/Infrastructure.Email/"] COPY ["Infrastructure/Infrastructure.Email.Templates/Infrastructure.Email.Templates.csproj", "Infrastructure/Infrastructure.Email.Templates/"] diff --git a/web/backend/API/API.Core/Program.cs b/web/backend/API/API.Core/Program.cs index 80912563..9c10bd5b 100644 --- a/web/backend/API/API.Core/Program.cs +++ b/web/backend/API/API.Core/Program.cs @@ -9,8 +9,8 @@ using Features.Emails.DependencyInjection; using Features.Emails.Services; using Features.ImageUploads.Commands.UploadPhoto; using Features.ImageUploads.DependencyInjection; -using Features.UserManagement.Controllers; -using Features.UserManagement.DependencyInjection; +using Features.Users.Controllers; +using Features.Users.DependencyInjection; using FluentValidation; using FluentValidation.AspNetCore; using Infrastructure.FileUpload; @@ -25,12 +25,8 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add current controllers to the exception filter builder - .Services.AddControllers(options => - { - options.Filters.Add(); - }) + .Services.AddControllers(options => { options.Filters.Add(); }) .AddApplicationPart(typeof(BreweryController).Assembly) - .AddApplicationPart(typeof(UserController).Assembly) .AddApplicationPart(typeof(AuthController).Assembly); builder.Services.AddEndpointsApiExplorer(); @@ -69,7 +65,6 @@ builder.Services.AddOpenApi(); builder.Services.AddValidatorsFromAssemblyContaining(); builder.Services.AddValidatorsFromAssembly(typeof(BreweryController).Assembly); -builder.Services.AddValidatorsFromAssembly(typeof(UserController).Assembly); builder.Services.AddValidatorsFromAssembly(typeof(AuthController).Assembly); builder.Services.AddValidatorsFromAssembly(typeof(UploadPhotoCommand).Assembly); builder.Services.AddFluentValidationAutoValidation(); @@ -80,7 +75,6 @@ builder.Services.AddMediatR(cfg => { cfg.RegisterServicesFromAssemblyContaining(); cfg.RegisterServicesFromAssembly(typeof(BreweryController).Assembly); - cfg.RegisterServicesFromAssembly(typeof(UserController).Assembly); cfg.RegisterServicesFromAssembly(typeof(AuthController).Assembly); cfg.RegisterServicesFromAssembly(typeof(UploadPhotoCommand).Assembly); cfg.RegisterServicesFromAssembly(typeof(IEmailDispatcher).Assembly); @@ -98,7 +92,6 @@ if (!builder.Environment.IsProduction()) builder.Services.AddDatabaseConnection(); builder.Services.AddFeaturesBreweries(); -builder.Services.AddFeaturesUserManagement(); builder.Services.AddFeaturesAuth(); builder.Services.AddFeaturesEmails(); builder.Services.AddFeaturesPhotoUpload(); @@ -152,4 +145,4 @@ lifetime.ApplicationStopping.Register(() => app.Logger.LogInformation("Application is shutting down gracefully..."); }); -app.Run(); +app.Run(); \ No newline at end of file diff --git a/web/backend/API/API.Specs/Dockerfile b/web/backend/API/API.Specs/Dockerfile index 4ac4114d..124425d4 100644 --- a/web/backend/API/API.Specs/Dockerfile +++ b/web/backend/API/API.Specs/Dockerfile @@ -12,8 +12,6 @@ COPY ["Database/Database.Migrations/Database.Migrations.csproj", "Database/Datab COPY ["Database/Database.Seed/Database.Seed.csproj", "Database/Database.Seed/"] COPY ["Domain/Domain.Entities/Domain.Entities.csproj", "Domain/Domain.Entities/"] COPY ["Domain/Domain.Exceptions/Domain.Exceptions.csproj", "Domain/Domain.Exceptions/"] -COPY ["Features/Features.Auth/Features.Auth.csproj", "Features/Features.Auth/"] -COPY ["Features/Features.Auth.Tests/Features.Auth.Tests.csproj", "Features/Features.Auth.Tests/"] COPY ["Features/Features.Breweries/Features.Breweries.csproj", "Features/Features.Breweries/"] COPY ["Features/Features.Breweries.Tests/Features.Breweries.Tests.csproj", "Features/Features.Breweries.Tests/"] COPY ["Features/Features.Emails/Features.Emails.csproj", "Features/Features.Emails/"] @@ -22,8 +20,8 @@ COPY ["Features/Features.Locations/Features.Locations.csproj", "Features/Feature COPY ["Features/Features.Locations.Tests/Features.Locations.Tests.csproj", "Features/Features.Locations.Tests/"] COPY ["Features/Features.PhotoUpload/Features.PhotoUpload.csproj", "Features/Features.PhotoUpload/"] COPY ["Features/Features.PhotoUpload.Tests/Features.PhotoUpload.Tests.csproj", "Features/Features.PhotoUpload.Tests/"] -COPY ["Features/Features.UserManagement/Features.UserManagement.csproj", "Features/Features.UserManagement/"] -COPY ["Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj", "Features/Features.UserManagement.Tests/"] +COPY ["Features/Features.Users/Features.Users.csproj", "Features/Features.Users/"] +COPY ["Features/Features.Users.Tests/Features.Users.Tests.csproj", "Features/Features.Users.Tests/"] COPY ["Infrastructure/Infrastructure.Configuration/Infrastructure.Configuration.csproj", "Infrastructure/Infrastructure.Configuration/"] COPY ["Infrastructure/Infrastructure.Email/Infrastructure.Email.csproj", "Infrastructure/Infrastructure.Email/"] COPY ["Infrastructure/Infrastructure.Email.Templates/Infrastructure.Email.Templates.csproj", "Infrastructure/Infrastructure.Email.Templates/"] diff --git a/web/backend/Biergarten.API.slnx b/web/backend/Biergarten.API.slnx index e62246bc..a7cce055 100644 --- a/web/backend/Biergarten.API.slnx +++ b/web/backend/Biergarten.API.slnx @@ -12,6 +12,10 @@ + + + + @@ -20,22 +24,31 @@ - + + + + + + - - - - + + + + + + + + - + \ No newline at end of file diff --git a/web/backend/Database/Database.Seed/Database.Seed.csproj b/web/backend/Database/Database.Seed/Database.Seed.csproj index a40bea94..0ce082e9 100644 --- a/web/backend/Database/Database.Seed/Database.Seed.csproj +++ b/web/backend/Database/Database.Seed/Database.Seed.csproj @@ -18,7 +18,7 @@ - + diff --git a/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs b/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs index 31981b69..6bd22d78 100644 --- a/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs +++ b/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs @@ -5,7 +5,7 @@ using Shared.Application.Emails; namespace Features.Emails.Commands.SendRegistrationEmail; /// -/// Handles , the cross-slice command sent by Features.Auth +/// Handles , the cross-slice command sent by Features.Users /// after a new user registers. /// public class SendRegistrationEmailHandler(IEmailDispatcher emailDispatcher) diff --git a/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs b/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs index d04419b9..c37551e0 100644 --- a/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs +++ b/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs @@ -5,7 +5,7 @@ using Shared.Application.Emails; namespace Features.Emails.Commands.SendResendConfirmationEmail; /// -/// Handles , the cross-slice command sent by Features.Auth +/// Handles , the cross-slice command sent by Features.Users /// when a user requests a fresh confirmation link. /// public class SendResendConfirmationEmailHandler(IEmailDispatcher emailDispatcher) diff --git a/web/backend/Features/Features.UserManagement.Tests/Commands/UpdateUserHandlerTests.cs b/web/backend/Features/Features.UserManagement.Tests/Commands/UpdateUserHandlerTests.cs deleted file mode 100644 index 53f3a800..00000000 --- a/web/backend/Features/Features.UserManagement.Tests/Commands/UpdateUserHandlerTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Domain.Entities; -using Features.UserManagement.Commands.UpdateUser; -using Features.UserManagement.Repository; -using Moq; - -namespace Features.UserManagement.Tests.Commands; - -public class UpdateUserHandlerTests -{ - [Fact] - public async Task Handle_DelegatesToRepository() - { - Mock repoMock = new(); - UpdateUserHandler handler = new(repoMock.Object); - UserAccount user = new() { UserAccountId = Guid.NewGuid() }; - repoMock.Setup(r => r.UpdateAsync(user)).Returns(Task.CompletedTask); - - await handler.Handle(new UpdateUserCommand(user), CancellationToken.None); - - repoMock.Verify(r => r.UpdateAsync(user), Times.Once); - } -} diff --git a/web/backend/Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj b/web/backend/Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj deleted file mode 100644 index 1777547c..00000000 --- a/web/backend/Features/Features.UserManagement.Tests/Features.UserManagement.Tests.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - net10.0 - enable - enable - false - Features.UserManagement.Tests - - - - - - - - - - - - - - - - - - diff --git a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserCommand.cs b/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserCommand.cs deleted file mode 100644 index 73d9c503..00000000 --- a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Domain.Entities; -using MediatR; - -namespace Features.UserManagement.Commands.UpdateUser; - -/// -/// Updates an existing user account. Not currently exposed via any HTTP route, carried forward -/// from IUserService.UpdateAsync as-is. -/// -public record UpdateUserCommand(UserAccount UserAccount) : IRequest; diff --git a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs b/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs deleted file mode 100644 index 4967b127..00000000 --- a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Features.UserManagement.Repository; -using MediatR; - -namespace Features.UserManagement.Commands.UpdateUser; - -public class UpdateUserHandler(IUserAccountRepository repository) - : IRequestHandler -{ - public Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) - { - return repository.UpdateAsync(request.UserAccount); - } -} diff --git a/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs b/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs deleted file mode 100644 index caff349d..00000000 --- a/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Features.UserManagement.Repository; -using Microsoft.Extensions.DependencyInjection; - -namespace Features.UserManagement.DependencyInjection; - -/// -/// Registers the services used by the Features.UserManagement slice. -/// -public static class FeaturesUserManagementServiceCollectionExtensions -{ - /// - /// Registers and its Dapper-based implementation. - /// - /// The same instance, for chaining. - public static IServiceCollection AddFeaturesUserManagement(this IServiceCollection services) - { - services.AddScoped(); - return services; - } -} diff --git a/web/backend/Features/Features.UserManagement/Features.UserManagement.csproj b/web/backend/Features/Features.UserManagement/Features.UserManagement.csproj deleted file mode 100644 index 77bfb16b..00000000 --- a/web/backend/Features/Features.UserManagement/Features.UserManagement.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - net10.0 - enable - enable - Features.UserManagement - - - - - - - - - - - - - - diff --git a/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs b/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs deleted file mode 100644 index 25ebf13d..00000000 --- a/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Domain.Entities; -using Domain.Exceptions; - -namespace Features.UserManagement.Repository; - -/// -/// Repository for CRUD operations on user account records. -/// -public interface IUserAccountRepository -{ - /// Returns null if no user account exists with the given ID. - Task GetByIdAsync(Guid id); - - /// Returns user accounts ordered by creation date descending. - /// null for no limit. - /// null for no offset. - Task> GetAllAsync(int? limit, int? offset); - - /// Updates the mutable fields of an existing user account. - /// Must have a valid UserAccountId. - /// Thrown when no user account exists with the given ID. - Task UpdateAsync(UserAccount userAccount); - - /// Deletes the user account with the given ID. - /// Thrown when no user account exists with the given ID. - Task DeleteAsync(Guid id); - - /// Returns null if no user account exists with the given username. - Task GetByUsernameAsync(string username); - - /// Returns null if no user account exists with the given email address. - Task GetByEmailAsync(string email); -} diff --git a/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs b/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs deleted file mode 100644 index 13d56011..00000000 --- a/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Data.Common; -using Dapper; -using Database.Connection; -using Domain.Entities; -using Domain.Exceptions; - -namespace Features.UserManagement.Repository; - -/// -/// Dapper-based implementation of . -/// -public class UserAccountRepository(ISqlConnectionFactory connectionFactory) - : DapperRepository(connectionFactory), - IUserAccountRepository -{ - /// - public async Task GetByIdAsync(Guid id) - { - await using DbConnection connection = await CreateConnection(); - return await connection.QueryFirstOrDefaultAsync( - """ - SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion - FROM dbo.UserAccount - WHERE UserAccountID = @UserAccountId - """, - new { UserAccountId = id } - ); - } - - /// - /// - /// Always applies pagination via OFFSET/FETCH, ordered by creation date descending. - /// A null / is treated as "no limit"/"no offset". - /// - public async Task> GetAllAsync(int? limit, int? offset) - { - await using DbConnection connection = await CreateConnection(); - return await connection.QueryAsync( - """ - SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion - FROM dbo.UserAccount - ORDER BY CreatedAt DESC - OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY - """, - new { Offset = offset ?? 0, Limit = limit ?? int.MaxValue } - ); - } - - /// - public async Task UpdateAsync(UserAccount userAccount) - { - await using DbConnection connection = await CreateConnection(); - int rows = await connection.ExecuteAsync( - """ - UPDATE dbo.UserAccount - SET Username = @Username, FirstName = @FirstName, LastName = @LastName, - DateOfBirth = @DateOfBirth, Email = @Email - WHERE UserAccountId = @UserAccountId - """, - new - { - userAccount.UserAccountId, - userAccount.Username, - userAccount.FirstName, - userAccount.LastName, - userAccount.DateOfBirth, - userAccount.Email, - } - ); - - if (rows == 0) - throw new NotFoundException("User account not found."); - } - - /// - public async Task DeleteAsync(Guid id) - { - await using DbConnection connection = await CreateConnection(); - int rows = await connection.ExecuteAsync( - """ - DELETE FROM dbo.UserAccount - WHERE UserAccountId = @UserAccountId - """, - new { UserAccountId = id } - ); - - if (rows == 0) - throw new NotFoundException("User account not found."); - } - - /// - public async Task GetByUsernameAsync(string username) - { - await using DbConnection connection = await CreateConnection(); - return await connection.QueryFirstOrDefaultAsync( - """ - SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion - FROM dbo.UserAccount - WHERE Username = @Username - """, - new { Username = username } - ); - } - - /// - public async Task GetByEmailAsync(string email) - { - await using DbConnection connection = await CreateConnection(); - return await connection.QueryFirstOrDefaultAsync( - """ - SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion - FROM dbo.UserAccount - WHERE Email = @Email - """, - new { Email = email } - ); - } -} diff --git a/web/backend/Features/Features.Auth.Tests/Commands/ConfirmUserHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/ConfirmUserHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/ConfirmUserHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/ConfirmUserHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/DeleteAccountHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/DeleteAccountHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/DeleteAccountHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/DeleteAccountHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/RefreshTokenHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/RefreshTokenHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/RefreshTokenHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/RefreshTokenHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/RegisterUserHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/RegisterUserHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/RegisterUserHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/RegisterUserHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/ResendConfirmationEmailHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/ResendConfirmationEmailHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/ResendConfirmationEmailHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/ResendConfirmationEmailHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/UpdateEmailHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/UpdateEmailHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/UpdateEmailHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/UpdateEmailHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/UpdatePasswordHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/UpdatePasswordHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/UpdatePasswordHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/UpdatePasswordHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/UpdateProfileHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/UpdateProfileHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/UpdateProfileHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/UpdateProfileHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Commands/UpdateUsernameHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Commands/UpdateUsernameHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Commands/UpdateUsernameHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Commands/UpdateUsernameHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Features.Auth.Tests.csproj b/web/backend/Features/Features.Users.Tests/Features.Users.Tests.csproj similarity index 92% rename from web/backend/Features/Features.Auth.Tests/Features.Auth.Tests.csproj rename to web/backend/Features/Features.Users.Tests/Features.Users.Tests.csproj index aa3c8bff..53d61628 100644 --- a/web/backend/Features/Features.Auth.Tests/Features.Auth.Tests.csproj +++ b/web/backend/Features/Features.Users.Tests/Features.Users.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/web/backend/Features/Features.UserManagement.Tests/Queries/GetAllUsersHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Queries/GetAllUsersHandlerTests.cs similarity index 75% rename from web/backend/Features/Features.UserManagement.Tests/Queries/GetAllUsersHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Queries/GetAllUsersHandlerTests.cs index 83b42d1c..4f2aeb06 100644 --- a/web/backend/Features/Features.UserManagement.Tests/Queries/GetAllUsersHandlerTests.cs +++ b/web/backend/Features/Features.Users.Tests/Queries/GetAllUsersHandlerTests.cs @@ -1,17 +1,17 @@ using Domain.Entities; -using Features.UserManagement.Queries.GetAllUsers; -using Features.UserManagement.Repository; +using Features.Auth.Queries.GetAllUsers; +using Features.Auth.Repository; using FluentAssertions; using Moq; -namespace Features.UserManagement.Tests.Queries; +namespace Features.Auth.Tests.Queries; public class GetAllUsersHandlerTests { [Fact] public async Task Handle_PassesLimitAndOffset_ToRepository() { - Mock repoMock = new(); + Mock repoMock = new(); GetAllUsersHandler handler = new(repoMock.Object); repoMock.Setup(r => r.GetAllAsync(10, 5)).ReturnsAsync(Array.Empty()); diff --git a/web/backend/Features/Features.UserManagement.Tests/Queries/GetUserByIdHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Queries/GetUserByIdHandlerTests.cs similarity index 84% rename from web/backend/Features/Features.UserManagement.Tests/Queries/GetUserByIdHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Queries/GetUserByIdHandlerTests.cs index e79b05b4..d3d7fbdf 100644 --- a/web/backend/Features/Features.UserManagement.Tests/Queries/GetUserByIdHandlerTests.cs +++ b/web/backend/Features/Features.Users.Tests/Queries/GetUserByIdHandlerTests.cs @@ -1,16 +1,16 @@ using Domain.Entities; using Domain.Exceptions; -using Features.UserManagement.Queries.GetUserById; -using Features.UserManagement.Repository; +using Features.Auth.Queries.GetUserById; +using Features.Auth.Repository; using FluentAssertions; using Moq; -namespace Features.UserManagement.Tests.Queries; +namespace Features.Auth.Tests.Queries; public class GetUserByIdHandlerTests { private readonly GetUserByIdHandler _handler; - private readonly Mock _repoMock = new(); + private readonly Mock _repoMock = new(); public GetUserByIdHandlerTests() { diff --git a/web/backend/Features/Features.Auth.Tests/Queries/LoginHandlerTests.cs b/web/backend/Features/Features.Users.Tests/Queries/LoginHandlerTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Queries/LoginHandlerTests.cs rename to web/backend/Features/Features.Users.Tests/Queries/LoginHandlerTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Services/TokenServiceRefreshTests.cs b/web/backend/Features/Features.Users.Tests/Services/TokenServiceRefreshTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Services/TokenServiceRefreshTests.cs rename to web/backend/Features/Features.Users.Tests/Services/TokenServiceRefreshTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/Services/TokenServiceValidationTests.cs b/web/backend/Features/Features.Users.Tests/Services/TokenServiceValidationTests.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/Services/TokenServiceValidationTests.cs rename to web/backend/Features/Features.Users.Tests/Services/TokenServiceValidationTests.cs diff --git a/web/backend/Features/Features.Auth.Tests/TestSupport/UserManagerMockFactory.cs b/web/backend/Features/Features.Users.Tests/TestSupport/UserManagerMockFactory.cs similarity index 100% rename from web/backend/Features/Features.Auth.Tests/TestSupport/UserManagerMockFactory.cs rename to web/backend/Features/Features.Users.Tests/TestSupport/UserManagerMockFactory.cs diff --git a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs b/web/backend/Features/Features.Users/Commands/ConfirmUser/ConfirmUserCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs rename to web/backend/Features/Features.Users/Commands/ConfirmUser/ConfirmUserCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs b/web/backend/Features/Features.Users/Commands/ConfirmUser/ConfirmUserHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs rename to web/backend/Features/Features.Users/Commands/ConfirmUser/ConfirmUserHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/DeleteAccount/DeleteAccountCommand.cs b/web/backend/Features/Features.Users/Commands/DeleteAccount/DeleteAccountCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/DeleteAccount/DeleteAccountCommand.cs rename to web/backend/Features/Features.Users/Commands/DeleteAccount/DeleteAccountCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/DeleteAccount/DeleteAccountHandler.cs b/web/backend/Features/Features.Users/Commands/DeleteAccount/DeleteAccountHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/DeleteAccount/DeleteAccountHandler.cs rename to web/backend/Features/Features.Users/Commands/DeleteAccount/DeleteAccountHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/Login/LoginCommand.cs b/web/backend/Features/Features.Users/Commands/Login/LoginCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/Login/LoginCommand.cs rename to web/backend/Features/Features.Users/Commands/Login/LoginCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/Login/LoginHandler.cs b/web/backend/Features/Features.Users/Commands/Login/LoginHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/Login/LoginHandler.cs rename to web/backend/Features/Features.Users/Commands/Login/LoginHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/Login/LoginValidator.cs b/web/backend/Features/Features.Users/Commands/Login/LoginValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/Login/LoginValidator.cs rename to web/backend/Features/Features.Users/Commands/Login/LoginValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenCommand.cs b/web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenCommand.cs rename to web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs b/web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs rename to web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs b/web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs rename to web/backend/Features/Features.Users/Commands/RefreshToken/RefreshTokenValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserCommand.cs b/web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserCommand.cs rename to web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs b/web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs rename to web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs b/web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs rename to web/backend/Features/Features.Users/Commands/RegisterUser/RegisterUserValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs b/web/backend/Features/Features.Users/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs rename to web/backend/Features/Features.Users/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs b/web/backend/Features/Features.Users/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs rename to web/backend/Features/Features.Users/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailCommand.cs b/web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailCommand.cs rename to web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailHandler.cs b/web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailHandler.cs similarity index 96% rename from web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailHandler.cs rename to web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailHandler.cs index 8ef0613d..5cc03d34 100644 --- a/web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailHandler.cs +++ b/web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailHandler.cs @@ -10,7 +10,7 @@ namespace Features.Auth.Commands.UpdateEmail; /// Handles via . /// also resets EmailConfirmed to /// , so the user must re-confirm the new address (see -/// Features.Auth.Commands.ResendConfirmationEmail). +/// Features.Users.Commands.ResendConfirmationEmail). /// public class UpdateEmailHandler(UserManager userManager) : IRequestHandler diff --git a/web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailValidator.cs b/web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateEmail/UpdateEmailValidator.cs rename to web/backend/Features/Features.Users/Commands/UpdateEmail/UpdateEmailValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordCommand.cs b/web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordCommand.cs rename to web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordHandler.cs b/web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordHandler.cs rename to web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordValidator.cs b/web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdatePassword/UpdatePasswordValidator.cs rename to web/backend/Features/Features.Users/Commands/UpdatePassword/UpdatePasswordValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileCommand.cs b/web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileCommand.cs rename to web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileHandler.cs b/web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileHandler.cs rename to web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileValidator.cs b/web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateProfile/UpdateProfileValidator.cs rename to web/backend/Features/Features.Users/Commands/UpdateProfile/UpdateProfileValidator.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameCommand.cs b/web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameCommand.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameCommand.cs rename to web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameCommand.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameHandler.cs b/web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameHandler.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameHandler.cs rename to web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameHandler.cs diff --git a/web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameValidator.cs b/web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameValidator.cs similarity index 100% rename from web/backend/Features/Features.Auth/Commands/UpdateUsername/UpdateUsernameValidator.cs rename to web/backend/Features/Features.Users/Commands/UpdateUsername/UpdateUsernameValidator.cs diff --git a/web/backend/Features/Features.Auth/Controllers/AuthController.cs b/web/backend/Features/Features.Users/Controllers/AuthController.cs similarity index 100% rename from web/backend/Features/Features.Auth/Controllers/AuthController.cs rename to web/backend/Features/Features.Users/Controllers/AuthController.cs diff --git a/web/backend/Features/Features.UserManagement/Controllers/UserController.cs b/web/backend/Features/Features.Users/Controllers/UserController.cs similarity index 89% rename from web/backend/Features/Features.UserManagement/Controllers/UserController.cs rename to web/backend/Features/Features.Users/Controllers/UserController.cs index 669d4f5e..86d4827c 100644 --- a/web/backend/Features/Features.UserManagement/Controllers/UserController.cs +++ b/web/backend/Features/Features.Users/Controllers/UserController.cs @@ -1,11 +1,11 @@ using Domain.Entities; using Domain.Exceptions; -using Features.UserManagement.Queries.GetAllUsers; -using Features.UserManagement.Queries.GetUserById; +using Features.Auth.Queries.GetAllUsers; +using Features.Auth.Queries.GetUserById; using MediatR; using Microsoft.AspNetCore.Mvc; -namespace Features.UserManagement.Controllers; +namespace Features.Auth.Controllers; /// /// Exposes read endpoints for user accounts. diff --git a/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs b/web/backend/Features/Features.Users/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs similarity index 81% rename from web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs rename to web/backend/Features/Features.Users/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs index 97d632a0..89dec851 100644 --- a/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs +++ b/web/backend/Features/Features.Users/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using Features.Auth.Identity; +using Features.Auth.Repository; using Features.Auth.Services; using Infrastructure.PasswordHashing; using Microsoft.AspNetCore.Identity; @@ -6,17 +7,19 @@ using Microsoft.Extensions.DependencyInjection; namespace Features.Auth.DependencyInjection; -/// Registers the services required by Features.Auth with the dependency injection container. +/// Registers the services required by Features.Users with the dependency injection container. public static class FeaturesAuthServiceCollectionExtensions { /// - /// Adds and ASP.NET Core Identity ( - /// backed by and ) as scoped services. + /// Adds , , and ASP.NET Core + /// Identity ( backed by and + /// ) as scoped services. /// public static IServiceCollection AddFeaturesAuth(this IServiceCollection services) { services.AddScoped(); services.AddScoped(); + services.AddScoped(); // AddDefaultTokenProviders() is deliberately not called: it registers // DataProtectorTokenProvider, which UserManager's constructor resolves eagerly and which diff --git a/web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs b/web/backend/Features/Features.Users/Dtos/AuthPayloads.cs similarity index 100% rename from web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs rename to web/backend/Features/Features.Users/Dtos/AuthPayloads.cs diff --git a/web/backend/Features/Features.Auth/Features.Auth.csproj b/web/backend/Features/Features.Users/Features.Users.csproj similarity index 93% rename from web/backend/Features/Features.Auth/Features.Auth.csproj rename to web/backend/Features/Features.Users/Features.Users.csproj index 53379c51..b7439890 100644 --- a/web/backend/Features/Features.Auth/Features.Auth.csproj +++ b/web/backend/Features/Features.Users/Features.Users.csproj @@ -18,11 +18,8 @@ + - - - - diff --git a/web/backend/Features/Features.Auth/Identity/ApplicationUser.cs b/web/backend/Features/Features.Users/Identity/ApplicationUser.cs similarity index 88% rename from web/backend/Features/Features.Auth/Identity/ApplicationUser.cs rename to web/backend/Features/Features.Users/Identity/ApplicationUser.cs index e0dd41d5..9b015bc6 100644 --- a/web/backend/Features/Features.Auth/Identity/ApplicationUser.cs +++ b/web/backend/Features/Features.Users/Identity/ApplicationUser.cs @@ -2,7 +2,7 @@ namespace Features.Auth.Identity; /// /// The user type driving for -/// Features.Auth. A plain POCO (not IdentityUser<TKey>) backed by +/// Features.Users. A plain POCO (not IdentityUser<TKey>) backed by /// rather than EF Core, matching the rest of the solution's Dapper-only persistence. /// public sealed class ApplicationUser diff --git a/web/backend/Features/Features.Auth/Identity/Argon2PasswordHasher.cs b/web/backend/Features/Features.Users/Identity/Argon2PasswordHasher.cs similarity index 100% rename from web/backend/Features/Features.Auth/Identity/Argon2PasswordHasher.cs rename to web/backend/Features/Features.Users/Identity/Argon2PasswordHasher.cs diff --git a/web/backend/Features/Features.Auth/Identity/DapperUserStore.cs b/web/backend/Features/Features.Users/Identity/DapperUserStore.cs similarity index 98% rename from web/backend/Features/Features.Auth/Identity/DapperUserStore.cs rename to web/backend/Features/Features.Users/Identity/DapperUserStore.cs index fb2780a9..1e8965cb 100644 --- a/web/backend/Features/Features.Auth/Identity/DapperUserStore.cs +++ b/web/backend/Features/Features.Users/Identity/DapperUserStore.cs @@ -186,8 +186,9 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory) /// /// /// A plain DELETE against dbo.UserAccount: its foreign keys from - /// dbo.UserCredential, dbo.UserVerification, and dbo.UserAvatar cascade, so no - /// manual child cleanup is needed. Other tables (posts, comments, photos, follows) reference the + /// dbo.UserCredential, dbo.UserVerification, and dbo.UserProfile cascade + /// (dbo.UserAvatar cascades transitively through dbo.UserProfile), so no manual + /// child cleanup is needed. Other tables (posts, comments, photos, follows) reference the /// account with ON DELETE NO ACTION by design; deleting an account that still has any of /// those fails with a foreign key violation, which is surfaced as a failed /// rather than an unhandled . diff --git a/web/backend/Features/Features.Auth/Identity/UserAccountExtensions.cs b/web/backend/Features/Features.Users/Identity/UserAccountExtensions.cs similarity index 87% rename from web/backend/Features/Features.Auth/Identity/UserAccountExtensions.cs rename to web/backend/Features/Features.Users/Identity/UserAccountExtensions.cs index 67c270bb..24c11c5a 100644 --- a/web/backend/Features/Features.Auth/Identity/UserAccountExtensions.cs +++ b/web/backend/Features/Features.Users/Identity/UserAccountExtensions.cs @@ -5,7 +5,7 @@ namespace Features.Auth.Identity; /// /// Converts the persistence-agnostic domain entity into the /// shape required by . -/// Kept here, in Features.Auth, rather than on itself so the domain layer has +/// Kept here, in Features.Users, rather than on itself so the domain layer has /// no dependency on ASP.NET Core Identity. /// public static class UserAccountExtensions diff --git a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs b/web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersHandler.cs similarity index 66% rename from web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs rename to web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersHandler.cs index 4e8afe82..201c35be 100644 --- a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs +++ b/web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersHandler.cs @@ -1,10 +1,10 @@ using Domain.Entities; -using Features.UserManagement.Repository; +using Features.Auth.Repository; using MediatR; -namespace Features.UserManagement.Queries.GetAllUsers; +namespace Features.Auth.Queries.GetAllUsers; -public class GetAllUsersHandler(IUserAccountRepository repository) +public class GetAllUsersHandler(IUserListRepository repository) : IRequestHandler> { public Task> Handle( diff --git a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs b/web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersQuery.cs similarity index 86% rename from web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs rename to web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersQuery.cs index 54e8d4cf..e000063e 100644 --- a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs +++ b/web/backend/Features/Features.Users/Queries/GetAllUsers/GetAllUsersQuery.cs @@ -1,7 +1,7 @@ using Domain.Entities; using MediatR; -namespace Features.UserManagement.Queries.GetAllUsers; +namespace Features.Auth.Queries.GetAllUsers; /// /// Requests a page of user accounts, ordered by creation date descending. diff --git a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs b/web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdHandler.cs similarity index 78% rename from web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs rename to web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdHandler.cs index d664310e..8d83c112 100644 --- a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs +++ b/web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdHandler.cs @@ -1,11 +1,11 @@ using Domain.Entities; using Domain.Exceptions; -using Features.UserManagement.Repository; +using Features.Auth.Repository; using MediatR; -namespace Features.UserManagement.Queries.GetUserById; +namespace Features.Auth.Queries.GetUserById; -public class GetUserByIdHandler(IUserAccountRepository repository) +public class GetUserByIdHandler(IUserListRepository repository) : IRequestHandler { /// Thrown when no user account exists with the given ID. diff --git a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs b/web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdQuery.cs similarity index 67% rename from web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs rename to web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdQuery.cs index 8337b7a9..80328852 100644 --- a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs +++ b/web/backend/Features/Features.Users/Queries/GetUserById/GetUserByIdQuery.cs @@ -1,6 +1,6 @@ using Domain.Entities; using MediatR; -namespace Features.UserManagement.Queries.GetUserById; +namespace Features.Auth.Queries.GetUserById; public record GetUserByIdQuery(Guid UserAccountId) : IRequest; diff --git a/web/backend/Features/Features.Users/Repository/IUserListRepository.cs b/web/backend/Features/Features.Users/Repository/IUserListRepository.cs new file mode 100644 index 00000000..954d37ab --- /dev/null +++ b/web/backend/Features/Features.Users/Repository/IUserListRepository.cs @@ -0,0 +1,21 @@ +using Domain.Entities; + +namespace Features.Auth.Repository; + +/// +/// Read access for user account listing. Everything else on user accounts (lookup by +/// username/email, create/update/delete) already goes through +/// ; this repository only covers +/// what IUserStore has no equivalent for: fetching by ID with full audit fields, and +/// paginated listing. +/// +public interface IUserListRepository +{ + /// Returns null if no user account exists with the given ID. + Task GetByIdAsync(Guid id); + + /// Returns user accounts ordered by creation date descending. + /// null for no limit. + /// null for no offset. + Task> GetAllAsync(int? limit, int? offset); +} diff --git a/web/backend/Features/Features.Users/Repository/UserListRepository.cs b/web/backend/Features/Features.Users/Repository/UserListRepository.cs new file mode 100644 index 00000000..8f90054a --- /dev/null +++ b/web/backend/Features/Features.Users/Repository/UserListRepository.cs @@ -0,0 +1,50 @@ +using System.Data.Common; +using Dapper; +using Database.Connection; +using Domain.Entities; + +namespace Features.Auth.Repository; + +/// +/// Dapper-based implementation of . +/// +public class UserListRepository(ISqlConnectionFactory connectionFactory) + : DapperRepository(connectionFactory), + IUserListRepository +{ + /// + public async Task GetByIdAsync(Guid id) + { + await using DbConnection connection = await CreateConnection(); + return await connection.QueryFirstOrDefaultAsync( + """ + SELECT + UserAccountID, + Username, + FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion + FROM dbo.UserAccount + WHERE UserAccountID = @UserAccountId + """, + new { UserAccountId = id } + ); + } + + /// + /// + /// Always applies pagination via OFFSET/FETCH, ordered by creation date descending. + /// A null / is treated as "no limit"/"no offset". + /// + public async Task> GetAllAsync(int? limit, int? offset) + { + await using DbConnection connection = await CreateConnection(); + return await connection.QueryAsync( + """ + SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion + FROM dbo.UserAccount + ORDER BY CreatedAt DESC + OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY + """, + new { Offset = offset ?? 0, Limit = limit ?? int.MaxValue } + ); + } +} diff --git a/web/backend/Features/Features.Auth/Services/ITokenService.cs b/web/backend/Features/Features.Users/Services/ITokenService.cs similarity index 100% rename from web/backend/Features/Features.Auth/Services/ITokenService.cs rename to web/backend/Features/Features.Users/Services/ITokenService.cs diff --git a/web/backend/Features/Features.Auth/Services/TokenService.cs b/web/backend/Features/Features.Users/Services/TokenService.cs similarity index 100% rename from web/backend/Features/Features.Auth/Services/TokenService.cs rename to web/backend/Features/Features.Users/Services/TokenService.cs diff --git a/web/backend/Shared/Shared.Application/Emails/SendRegistrationEmailCommand.cs b/web/backend/Shared/Shared.Application/Emails/SendRegistrationEmailCommand.cs index 5c573245..80e1133e 100644 --- a/web/backend/Shared/Shared.Application/Emails/SendRegistrationEmailCommand.cs +++ b/web/backend/Shared/Shared.Application/Emails/SendRegistrationEmailCommand.cs @@ -3,7 +3,7 @@ using MediatR; namespace Shared.Application.Emails; /// -/// Cross-slice command sent by Features.Auth and handled by Features.Emails to dispatch a +/// Cross-slice command sent by Features.Users and handled by Features.Emails to dispatch a /// registration confirmation email, without either slice taking a project reference on the other. /// public record SendRegistrationEmailCommand(string FirstName, string Email, string ConfirmationToken) diff --git a/web/backend/Shared/Shared.Application/Emails/SendResendConfirmationEmailCommand.cs b/web/backend/Shared/Shared.Application/Emails/SendResendConfirmationEmailCommand.cs index 0831d8c2..af2fa75b 100644 --- a/web/backend/Shared/Shared.Application/Emails/SendResendConfirmationEmailCommand.cs +++ b/web/backend/Shared/Shared.Application/Emails/SendResendConfirmationEmailCommand.cs @@ -3,7 +3,7 @@ using MediatR; namespace Shared.Application.Emails; /// -/// Cross-slice command sent by Features.Auth and handled by Features.Emails to dispatch a +/// Cross-slice command sent by Features.Users and handled by Features.Emails to dispatch a /// fresh confirmation-link email, without either slice taking a project reference on the other. /// public record SendResendConfirmationEmailCommand(