diff --git a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs b/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs
index 0a3c3aae..841392fa 100644
--- a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs
+++ b/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserCommand.cs
@@ -3,8 +3,5 @@ using MediatR;
namespace Features.Auth.Commands.ConfirmUser;
-///
-/// Validates a confirmation token and confirms the corresponding user account.
-///
-/// The confirmation token issued to the user, typically delivered via email.
+/// Validates a confirmation token and confirms the corresponding user account.
public record ConfirmUserCommand(string Token) : IRequest;
diff --git a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs b/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs
index 230d799a..cbf4f91c 100644
--- a/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs
+++ b/web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs
@@ -11,8 +11,6 @@ namespace Features.Auth.Commands.ConfirmUser;
/// Handles by validating the confirmation token and marking the
/// corresponding user account as confirmed.
///
-/// Repository used to look up and confirm user accounts.
-/// Service used to validate the confirmation token.
public class ConfirmUserHandler(IAuthRepository authRepository, ITokenService tokenService)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs b/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs
index 91c9d496..4b311b73 100644
--- a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs
+++ b/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenHandler.cs
@@ -8,7 +8,6 @@ namespace Features.Auth.Commands.RefreshToken;
/// Handles by validating the refresh token and issuing a new
/// access/refresh token pair.
///
-/// Service used to validate and exchange the refresh token.
public class RefreshTokenHandler(ITokenService tokenService)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs b/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs
index b6f2a2e7..19489ddf 100644
--- a/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs
+++ b/web/backend/Features/Features.Auth/Commands/RefreshToken/RefreshTokenValidator.cs
@@ -2,14 +2,8 @@ using FluentValidation;
namespace Features.Auth.Commands.RefreshToken;
-///
-/// Validates instances before they are processed.
-///
public class RefreshTokenValidator : AbstractValidator
{
- ///
- /// Configures a validation rule requiring to be non-empty.
- ///
public RefreshTokenValidator()
{
RuleFor(x => x.RefreshToken).NotEmpty().WithMessage("Refresh token is required");
diff --git a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs b/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs
index d056894c..2663a5ef 100644
--- a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs
+++ b/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserHandler.cs
@@ -14,10 +14,6 @@ namespace Features.Auth.Commands.RegisterUser;
/// account, issues access/refresh/confirmation tokens, and attempts to send the registration
/// confirmation email via Features.Emails.
///
-/// Repository used to check for existing users and persist the new account.
-/// Infrastructure component used to hash the user's plain-text password.
-/// Service used to generate access, refresh, and confirmation tokens.
-/// Used to send the cross-slice command that triggers the confirmation email.
public class RegisterUserHandler(
IAuthRepository authRepo,
IPasswordInfrastructure passwordInfrastructure,
diff --git a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs b/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs
index 04125df8..de31bddf 100644
--- a/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs
+++ b/web/backend/Features/Features.Auth/Commands/RegisterUser/RegisterUserValidator.cs
@@ -2,15 +2,8 @@ using FluentValidation;
namespace Features.Auth.Commands.RegisterUser;
-///
-/// Validates instances before they are processed.
-///
public class RegisterUserValidator : AbstractValidator
{
- ///
- /// Configures validation rules for username format and length, first/last name length, email format and
- /// length, minimum age based on date of birth, and password strength requirements.
- ///
public RegisterUserValidator()
{
RuleFor(x => x.Username)
diff --git a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs b/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs
index 5b276fc0..216371fe 100644
--- a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs
+++ b/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailCommand.cs
@@ -2,8 +2,5 @@ using MediatR;
namespace Features.Auth.Commands.ResendConfirmationEmail;
-///
-/// Resends the account confirmation email to a user, generating a fresh confirmation token.
-///
-/// The unique identifier of the user requesting the resend.
+/// Resends the account confirmation email to a user, generating a fresh confirmation token.
public record ResendConfirmationEmailCommand(Guid UserId) : IRequest;
diff --git a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs b/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs
index 33eb3f98..0fa817b1 100644
--- a/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs
+++ b/web/backend/Features/Features.Auth/Commands/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs
@@ -10,9 +10,6 @@ namespace Features.Auth.Commands.ResendConfirmationEmail;
/// Handles by generating a fresh confirmation token and
/// sending it via Features.Emails.
///
-/// Repository used to look up the user and check verification status.
-/// Service used to generate the confirmation token.
-/// Used to send the cross-slice command that triggers the email.
///
/// Returns silently without sending an email if the user does not exist (to prevent user enumeration)
/// or if the user's account is already verified.
diff --git a/web/backend/Features/Features.Auth/Controllers/AuthController.cs b/web/backend/Features/Features.Auth/Controllers/AuthController.cs
index 308c36d8..2e0aa868 100644
--- a/web/backend/Features/Features.Auth/Controllers/AuthController.cs
+++ b/web/backend/Features/Features.Auth/Controllers/AuthController.cs
@@ -18,21 +18,11 @@ namespace Features.Auth.Controllers;
/// The controller is decorated with [Authorize(AuthenticationSchemes = "JWT")] by default, but most
/// actions opt out via [AllowAnonymous] since they are entry points used before a caller holds a token.
///
-/// Used to dispatch auth commands and queries to their handlers.
[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "JWT")]
public class AuthController(IMediator mediator) : ControllerBase
{
- ///
- /// Registers a new user account.
- ///
- ///
- /// Allows anonymous access. On success, responds with 201 Created containing the new user's ID,
- /// username, issued refresh/access tokens, and whether a confirmation email was sent.
- ///
- /// The registration details, including username, name, email, date of birth, and password.
- /// A 201 Created result wrapping a of .
[AllowAnonymous]
[HttpPost("register")]
public async Task>> Register(
@@ -50,15 +40,6 @@ public class AuthController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Authenticates a user with a username and password.
- ///
- ///
- /// Allows anonymous access. On success, responds with 200 OK containing the user's ID,
- /// username, and a newly issued refresh/access token pair.
- ///
- /// The login credentials (username and password).
- /// An 200 OK result wrapping a of .
[AllowAnonymous]
[HttpPost("login")]
public async Task>> Login([FromBody] LoginQuery query)
@@ -73,15 +54,6 @@ public class AuthController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Confirms a user account using a confirmation token.
- ///
- ///
- /// Requires JWT authentication. On success, responds with 200 OK containing the confirmed
- /// user's ID and the confirmation timestamp.
- ///
- /// The confirmation token supplied via the confirmation email link.
- /// A 200 OK result wrapping a of .
[HttpPost("confirm")]
public async Task>> Confirm(
[FromQuery] string token
@@ -97,14 +69,6 @@ public class AuthController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Resends the account confirmation email for the specified user.
- ///
- ///
- /// Requires JWT authentication. On success, responds with 200 OK.
- ///
- /// The unique identifier of the user account to resend the confirmation email for.
- /// A 200 OK result wrapping a confirming the email was resent.
[HttpPost("confirm/resend")]
public async Task> ResendConfirmation([FromQuery] Guid userId)
{
@@ -112,15 +76,6 @@ public class AuthController(IMediator mediator) : ControllerBase
return Ok(new ResponseBody { Message = "confirmation email has been resent" });
}
- ///
- /// Exchanges a valid refresh token for a new access/refresh token pair.
- ///
- ///
- /// Allows anonymous access. On success, responds with 200 OK containing the user's ID,
- /// username, and the newly issued refresh/access token pair.
- ///
- /// The request containing the refresh token to exchange.
- /// A 200 OK result wrapping a of .
[AllowAnonymous]
[HttpPost("refresh")]
public async Task>> Refresh(
diff --git a/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs b/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs
index 7e475731..c3181b51 100644
--- a/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs
+++ b/web/backend/Features/Features.Auth/DependencyInjection/FeaturesAuthServiceCollectionExtensions.cs
@@ -5,9 +5,6 @@ using Microsoft.Extensions.DependencyInjection;
namespace Features.Auth.DependencyInjection;
-///
-/// Registers the services owned by the Auth feature slice.
-///
public static class FeaturesAuthServiceCollectionExtensions
{
public static IServiceCollection AddFeaturesAuth(this IServiceCollection services)
diff --git a/web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs b/web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs
index 64e5a855..43070541 100644
--- a/web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs
+++ b/web/backend/Features/Features.Auth/Dtos/AuthPayloads.cs
@@ -1,12 +1,6 @@
namespace Features.Auth.Dtos;
-///
-/// Payload returned to the client after a successful login or token refresh.
-///
-/// The unique identifier of the authenticated user account.
-/// The username of the authenticated user account.
-/// The newly issued refresh token used to obtain new access tokens.
-/// The newly issued JWT access token used to authorize subsequent requests.
+/// Payload returned to the client after a successful login or token refresh.
public record LoginPayload(
Guid UserAccountId,
string Username,
@@ -14,14 +8,7 @@ public record LoginPayload(
string AccessToken
);
-///
-/// Payload returned to the client after a successful registration.
-///
-/// The unique identifier of the newly created user account.
-/// The username of the newly created user account.
-/// The refresh token issued for the new account.
-/// The JWT access token issued for the new account.
-/// Whether a confirmation email was successfully sent to the new user.
+/// Payload returned to the client after a successful registration.
public record RegistrationPayload(
Guid UserAccountId,
string Username,
@@ -30,9 +17,5 @@ public record RegistrationPayload(
bool ConfirmationEmailSent
);
-///
-/// Payload returned to the client after a user account's email has been confirmed.
-///
-/// The unique identifier of the user account that was confirmed.
-/// The date and time at which the account was confirmed.
+/// Payload returned to the client after a user account's email has been confirmed.
public record ConfirmationPayload(Guid UserAccountId, DateTime ConfirmedDate);
diff --git a/web/backend/Features/Features.Auth/Queries/Login/LoginHandler.cs b/web/backend/Features/Features.Auth/Queries/Login/LoginHandler.cs
index d3ee64d4..2cd27f59 100644
--- a/web/backend/Features/Features.Auth/Queries/Login/LoginHandler.cs
+++ b/web/backend/Features/Features.Auth/Queries/Login/LoginHandler.cs
@@ -11,12 +11,6 @@ namespace Features.Auth.Queries.Login;
///
/// Handles by verifying credentials and issuing access/refresh tokens.
///
-/// Repository used to look up the user account and its active credential.
-///
-/// Infrastructure component used to verify a plain-text password against a stored
-/// hash.
-///
-/// Service used to generate access and refresh tokens for the authenticated user.
public class LoginHandler(
IAuthRepository authRepo,
IPasswordInfrastructure passwordInfrastructure,
diff --git a/web/backend/Features/Features.Auth/Queries/Login/LoginValidator.cs b/web/backend/Features/Features.Auth/Queries/Login/LoginValidator.cs
index 8458414e..c90e9fb7 100644
--- a/web/backend/Features/Features.Auth/Queries/Login/LoginValidator.cs
+++ b/web/backend/Features/Features.Auth/Queries/Login/LoginValidator.cs
@@ -2,15 +2,8 @@ using FluentValidation;
namespace Features.Auth.Queries.Login;
-///
-/// Validates instances before they are processed.
-///
public class LoginValidator : AbstractValidator
{
- ///
- /// Configures validation rules requiring both and
- /// to be non-empty.
- ///
public LoginValidator()
{
RuleFor(x => x.Username).NotEmpty().WithMessage("Username is required");
diff --git a/web/backend/Features/Features.Auth/Repository/AuthRepository.cs b/web/backend/Features/Features.Auth/Repository/AuthRepository.cs
index 46f8aca7..020c2458 100644
--- a/web/backend/Features/Features.Auth/Repository/AuthRepository.cs
+++ b/web/backend/Features/Features.Auth/Repository/AuthRepository.cs
@@ -11,7 +11,6 @@ namespace Features.Auth.Repository;
/// ADO.NET-based implementation of backed by SQL Server stored procedures,
/// handling user registration, credential lookup/rotation, and account verification.
///
-/// The factory used to create database connections.
public class AuthRepository(ISqlConnectionFactory connectionFactory)
: Repository(connectionFactory),
IAuthRepository
@@ -26,15 +25,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
/// If the result cannot be interpreted, is used, which will cause the
/// subsequent lookup to fail.
///
- /// Unique username for the user
- /// User's first name
- /// User's last name
- /// User's email address
- /// User's date of birth
- /// Hashed password
- /// The newly created UserAccount with generated ID
/// Thrown when the newly registered user cannot be retrieved after registration.
- /// Thrown when the database command fails.
public async Task RegisterUserAsync(
UserRegistrationDto userRegistrationDto
)
@@ -84,13 +75,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
?? throw new Exception("Failed to retrieve newly registered user.");
}
- ///
- /// Retrieves a user account by email address (typically used for login) using the
- /// usp_GetUserAccountByEmail stored procedure.
- ///
- /// Email address to search for
- /// UserAccount if found, null otherwise
- /// Thrown when the database command fails.
+ /// Retrieves a user account by email using the usp_GetUserAccountByEmail stored procedure.
public async Task GetUserByEmailAsync(string email)
{
await using DbConnection connection = await CreateConnection();
@@ -104,13 +89,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
return await reader.ReadAsync() ? MapToEntity(reader) : null;
}
- ///
- /// Retrieves a user account by username (typically used for login) using the
- /// usp_GetUserAccountByUsername stored procedure.
- ///
- /// Username to search for
- /// UserAccount if found, null otherwise
- /// Thrown when the database command fails.
+ /// Retrieves a user account by username using the usp_GetUserAccountByUsername stored procedure.
public async Task GetUserByUsernameAsync(string username)
{
await using DbConnection connection = await CreateConnection();
@@ -128,9 +107,6 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
/// Retrieves the active (non-revoked) credential for a user account using the
/// USP_GetActiveUserCredentialByUserAccountId stored procedure.
///
- /// ID of the user account
- /// Active UserCredential if found, null otherwise
- /// Thrown when the database command fails.
public async Task GetActiveCredentialByUserAccountIdAsync(Guid userAccountId)
{
await using DbConnection connection = await CreateConnection();
@@ -148,9 +124,6 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
/// Rotates a user's credential by invalidating all existing credentials and creating a new one,
/// using the USP_RotateUserCredential stored procedure.
///
- /// ID of the user account
- /// New hashed password
- /// Thrown when the database command fails.
public async Task RotateCredentialAsync(Guid userAccountId, string newPasswordHash)
{
await using DbConnection connection = await CreateConnection();
@@ -164,12 +137,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
await command.ExecuteNonQueryAsync();
}
- ///
- /// Retrieves a user account by ID using the usp_GetUserAccountById stored procedure.
- ///
- /// ID of the user account
- /// UserAccount if found, null otherwise
- /// Thrown when the database command fails.
+ /// Retrieves a user account by ID using the usp_GetUserAccountById stored procedure.
public async Task GetUserByIdAsync(Guid userAccountId)
{
await using DbConnection connection = await CreateConnection();
@@ -189,8 +157,6 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
/// no-op and the existing user is returned (idempotent). If a concurrent request verifies the user
/// first, the resulting duplicate-key SQL exception (error 2601/2627) is swallowed.
///
- /// ID of the user account to confirm
- /// The confirmed , or null if the user account does not exist.
///
/// Thrown when the database command fails for a reason other than
/// a duplicate verification record.
@@ -225,13 +191,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
return await GetUserByIdAsync(userAccountId);
}
- ///
- /// Checks whether a user account has been verified by querying the
- /// dbo.UserVerification table for a matching record.
- ///
- /// ID of the user account
- /// True if the user has a verification record, false otherwise
- /// Thrown when the database command fails.
+ /// Checks whether a user account has been verified by querying the dbo.UserVerification table.
public async Task IsUserVerifiedAsync(Guid userAccountId)
{
await using DbConnection connection = await CreateConnection();
@@ -246,23 +206,13 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
return result != null && result != DBNull.Value;
}
- ///
- /// Determines whether a represents a duplicate key violation
- /// (SQL Server error 2601 or 2627), used to detect a concurrent duplicate verification insert.
- ///
- /// The SQL exception to inspect.
- /// True if the exception represents a duplicate key violation, false otherwise.
+ /// Determines whether a is a duplicate key violation (SQL Server error 2601 or 2627).
private static bool IsDuplicateVerificationViolation(SqlException ex)
{
// 2601/2627 are duplicate key violations in SQL Server.
return ex.Number == 2601 || ex.Number == 2627;
}
- ///
- /// Maps a data reader row to a UserAccount entity.
- ///
- /// The data reader positioned on the row to map.
- /// The mapped instance.
protected override UserAccount MapToEntity(DbDataReader reader)
{
return new UserAccount
@@ -285,8 +235,6 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
/// Maps a data reader row to a UserCredential entity. The Timer column is mapped only if
/// present in the reader's schema, allowing this method to support result sets that omit it.
///
- /// The data reader positioned on the row to map.
- /// The mapped instance.
private static UserCredential MapToCredentialEntity(DbDataReader reader)
{
UserCredential entity = new()
@@ -319,13 +267,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
return entity;
}
- ///
- /// Helper method to add a parameter to a database command, converting null values to
- /// .
- ///
- /// The command to add the parameter to.
- /// The parameter name (including any prefix, e.g. "@Username").
- /// The parameter value, or null to bind .
+ /// Adds a parameter to a database command, converting null values to .
private static void AddParameter(DbCommand command, string name, object? value)
{
DbParameter p = command.CreateParameter();
diff --git a/web/backend/Features/Features.Auth/Repository/IAuthRepository.cs b/web/backend/Features/Features.Auth/Repository/IAuthRepository.cs
index 6a2570fc..092cfd59 100644
--- a/web/backend/Features/Features.Auth/Repository/IAuthRepository.cs
+++ b/web/backend/Features/Features.Auth/Repository/IAuthRepository.cs
@@ -7,64 +7,23 @@ namespace Features.Auth.Repository;
///
public interface IAuthRepository
{
- ///
- /// Registers a new user with account details and initial credential.
- /// Uses stored procedure: USP_RegisterUser
- ///
Task RegisterUserAsync(
UserRegistrationDto userRegistrationDto
);
- ///
- /// Retrieves a user account by email address (typically used for login).
- /// Uses stored procedure: usp_GetUserAccountByEmail
- ///
- /// Email address to search for
- /// UserAccount if found, null otherwise
Task GetUserByEmailAsync(string email);
- ///
- /// Retrieves a user account by username (typically used for login).
- /// Uses stored procedure: usp_GetUserAccountByUsername
- ///
- /// Username to search for
- /// UserAccount if found, null otherwise
Task GetUserByUsernameAsync(string username);
- ///
- /// Retrieves the active (non-revoked) credential for a user account.
- /// Uses stored procedure: USP_GetActiveUserCredentialByUserAccountId
- ///
- /// ID of the user account
- /// Active UserCredential if found, null otherwise
Task GetActiveCredentialByUserAccountIdAsync(Guid userAccountId);
- ///
- /// Rotates a user's credential by invalidating all existing credentials and creating a new one.
- /// Uses stored procedure: USP_RotateUserCredential
- ///
- /// ID of the user account
- /// New hashed password
+ /// Rotates a user's credential by invalidating all existing credentials and creating a new one.
Task RotateCredentialAsync(Guid userAccountId, string newPasswordHash);
- ///
- /// Marks a user account as confirmed.
- ///
- /// ID of the user account to confirm
- /// The confirmed UserAccount entity, or null if the user account does not exist
+ /// Marks a user account as confirmed. Idempotent if the account is already verified.
Task ConfirmUserAccountAsync(Guid userAccountId);
- ///
- /// Retrieves a user account by ID.
- ///
- /// ID of the user account
- /// UserAccount if found, null otherwise
Task GetUserByIdAsync(Guid userAccountId);
- ///
- /// Checks whether a user account has been verified.
- ///
- /// ID of the user account
- /// True if the user has a verification record, false otherwise
Task IsUserVerifiedAsync(Guid userAccountId);
}
diff --git a/web/backend/Features/Features.Auth/Services/ITokenService.cs b/web/backend/Features/Features.Auth/Services/ITokenService.cs
index 4285367a..5ac81ffc 100644
--- a/web/backend/Features/Features.Auth/Services/ITokenService.cs
+++ b/web/backend/Features/Features.Auth/Services/ITokenService.cs
@@ -18,20 +18,10 @@ public enum TokenType
ConfirmationToken,
}
-///
-/// Represents the result of successfully validating a token.
-///
-/// The unique identifier of the user the token belongs to.
-/// The username extracted from the token's claims.
-/// The produced from the validated token.
+/// Represents the result of successfully validating a token.
public record ValidatedToken(Guid UserId, string Username, ClaimsPrincipal Principal);
-///
-/// Represents the result of refreshing a user's session.
-///
-/// The user account associated with the refreshed session.
-/// The newly issued refresh token.
-/// The newly issued access token.
+/// Represents the result of refreshing a user's session.
public record RefreshTokenResult(UserAccount UserAccount, string RefreshToken, string AccessToken);
///
@@ -39,14 +29,13 @@ public record RefreshTokenResult(UserAccount UserAccount, string RefreshToken, s
///
public static class TokenServiceExpirationHours
{
- /// The expiration window, in hours, for access tokens.
public const double AccessTokenHours = 1;
- /// The expiration window, in hours, for refresh tokens (21 days).
- public const double RefreshTokenHours = 504; // 21 days
+ /// 21 days.
+ public const double RefreshTokenHours = 504;
- /// The expiration window, in hours, for confirmation tokens (30 minutes).
- public const double ConfirmationTokenHours = 0.5; // 30 minutes
+ /// 30 minutes.
+ public const double ConfirmationTokenHours = 0.5;
}
///
@@ -54,61 +43,23 @@ public static class TokenServiceExpirationHours
///
public interface ITokenService
{
- ///
- /// Generates a new access token for the given user.
- ///
- /// The user account to generate the token for.
- /// The signed access token string.
string GenerateAccessToken(UserAccount user);
- ///
- /// Generates a new refresh token for the given user.
- ///
- /// The user account to generate the token for.
- /// The signed refresh token string.
string GenerateRefreshToken(UserAccount user);
- ///
- /// Generates a new confirmation token for the given user.
- ///
- /// The user account to generate the token for.
- /// The signed confirmation token string.
string GenerateConfirmationToken(UserAccount user);
- ///
- /// Generates a token of the type specified by , which must be .
- ///
- /// The enum type identifying which kind of token to generate. Must be .
- /// The user account to generate the token for.
- /// The signed token string corresponding to the requested token type.
+ /// Generates a token of the type specified by .
+ /// Must be .
string GenerateToken(UserAccount user)
where T : struct, Enum;
- ///
- /// Validates an access token.
- ///
- /// The access token string to validate.
- /// A describing the token's claims.
Task ValidateAccessTokenAsync(string token);
- ///
- /// Validates a refresh token.
- ///
- /// The refresh token string to validate.
- /// A describing the token's claims.
Task ValidateRefreshTokenAsync(string token);
- ///
- /// Validates a confirmation token.
- ///
- /// The confirmation token string to validate.
- /// A describing the token's claims.
Task ValidateConfirmationTokenAsync(string token);
- ///
- /// Validates a refresh token and issues a new access/refresh token pair for the associated user.
- ///
- /// The refresh token string to validate and exchange.
- /// A containing the user and newly issued tokens.
+ /// Validates a refresh token and issues a new access/refresh token pair for the associated user.
Task RefreshTokenAsync(string refreshTokenString);
}
diff --git a/web/backend/Features/Features.Auth/Services/TokenService.cs b/web/backend/Features/Features.Auth/Services/TokenService.cs
index 1bbf13f2..8d389bab 100644
--- a/web/backend/Features/Features.Auth/Services/TokenService.cs
+++ b/web/backend/Features/Features.Auth/Services/TokenService.cs
@@ -19,12 +19,7 @@ public class TokenService : ITokenService
private readonly string _refreshTokenSecret;
private readonly ITokenInfrastructure _tokenInfrastructure;
- ///
- /// Initializes a new instance of , loading the access, refresh, and
- /// confirmation token signing secrets from environment variables.
- ///
- /// The infrastructure component used to generate and validate JWTs.
- /// Repository used to look up user accounts during token refresh.
+ /// Initializes a new instance of the class.
///
/// Thrown when any of the ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET, or
/// CONFIRMATION_TOKEN_SECRET environment variables are not set.
@@ -53,12 +48,6 @@ public class TokenService : ITokenService
);
}
- ///
- /// Generates an access token for the given user, signed with the access token secret and
- /// expiring after hours.
- ///
- /// The user account to generate the token for.
- /// The signed access token string.
public string GenerateAccessToken(UserAccount user)
{
DateTime expiresAt = DateTime.UtcNow.AddHours(TokenServiceExpirationHours.AccessTokenHours);
@@ -70,12 +59,6 @@ public class TokenService : ITokenService
);
}
- ///
- /// Generates a refresh token for the given user, signed with the refresh token secret and
- /// expiring after hours.
- ///
- /// The user account to generate the token for.
- /// The signed refresh token string.
public string GenerateRefreshToken(UserAccount user)
{
DateTime expiresAt = DateTime.UtcNow.AddHours(
@@ -89,12 +72,6 @@ public class TokenService : ITokenService
);
}
- ///
- /// Generates a confirmation token for the given user, signed with the confirmation token secret and
- /// expiring after hours.
- ///
- /// The user account to generate the token for.
- /// The signed confirmation token string.
public string GenerateConfirmationToken(UserAccount user)
{
DateTime expiresAt = DateTime.UtcNow.AddHours(
@@ -111,11 +88,9 @@ public class TokenService : ITokenService
///
/// Generates a token of the kind specified by , dispatching to
/// , , or
- /// based on the corresponding value.
+ /// .
///
- /// The enum type identifying which kind of token to generate. Must be .
- /// The user account to generate the token for.
- /// The signed token string corresponding to the requested token type.
+ /// Must be .
///
/// Thrown when is not or does not resolve to a known token type.
///
@@ -139,11 +114,6 @@ public class TokenService : ITokenService
};
}
- ///
- /// Validates an access token against the access token secret.
- ///
- /// The access token string to validate.
- /// A describing the token's claims.
///
/// Thrown when the token is missing required claims, has a malformed user ID, or otherwise fails validation.
///
@@ -152,11 +122,6 @@ public class TokenService : ITokenService
return await ValidateTokenInternalAsync(token, _accessTokenSecret, "access");
}
- ///
- /// Validates a refresh token against the refresh token secret.
- ///
- /// The refresh token string to validate.
- /// A describing the token's claims.
///
/// Thrown when the token is missing required claims, has a malformed user ID, or otherwise fails validation.
///
@@ -165,11 +130,6 @@ public class TokenService : ITokenService
return await ValidateTokenInternalAsync(token, _refreshTokenSecret, "refresh");
}
- ///
- /// Validates a confirmation token against the confirmation token secret.
- ///
- /// The confirmation token string to validate.
- /// A describing the token's claims.
///
/// Thrown when the token is missing required claims, has a malformed user ID, or otherwise fails validation.
///
@@ -178,12 +138,6 @@ public class TokenService : ITokenService
return await ValidateTokenInternalAsync(token, _confirmationTokenSecret, "confirmation");
}
- ///
- /// Validates the given refresh token, looks up the associated user, and issues a fresh
- /// access/refresh token pair.
- ///
- /// The refresh token string to validate and exchange.
- /// A containing the user and newly issued tokens.
///
/// Thrown when the refresh token is invalid, or when the user account it refers to no longer exists.
///
@@ -204,10 +158,7 @@ public class TokenService : ITokenService
/// Performs the shared validation logic for access, refresh, and confirmation tokens:
/// validates the JWT signature/expiration, then extracts and parses the user ID and username claims.
///
- /// The token string to validate.
- /// The secret key to validate the token's signature against.
/// A human-readable label (e.g. "access", "refresh", "confirmation") used in error messages.
- /// A describing the token's claims.
///
/// Thrown when required claims are missing, the user ID claim is not a valid ,
/// or the underlying token validation fails for any other reason (e.g. expired or invalid signature).
diff --git a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryCommand.cs b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryCommand.cs
index a06dadc3..19ad1406 100644
--- a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryCommand.cs
+++ b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryCommand.cs
@@ -3,9 +3,6 @@ using MediatR;
namespace Features.Breweries.Commands.CreateBrewery;
-///
-/// Location data required to create a new brewery post, supplied as part of .
-///
public record CreateBreweryLocation(
Guid CityId,
string AddressLine1,
diff --git a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryHandler.cs b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryHandler.cs
index 07c0f1d3..324eca28 100644
--- a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryHandler.cs
+++ b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryHandler.cs
@@ -5,19 +5,10 @@ using MediatR;
namespace Features.Breweries.Commands.CreateBrewery;
-///
-/// Handles by persisting a new brewery post and its location.
-///
-/// Repository used to persist the new brewery post.
public class CreateBreweryHandler(IBreweryRepository repository)
: IRequestHandler
{
- ///
- /// Creates a new brewery post, generating new identifiers for the post and its location.
- ///
- /// The details of the brewery post to create.
- /// A token to observe for cancellation requests.
- /// The newly created brewery post.
+ /// Creates a new brewery post, generating new identifiers for the post and its location.
public async Task Handle(
CreateBreweryCommand request,
CancellationToken cancellationToken
diff --git a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryValidator.cs b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryValidator.cs
index ad5f528f..3f9e44f4 100644
--- a/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryValidator.cs
+++ b/web/backend/Features/Features.Breweries/Commands/CreateBrewery/CreateBreweryValidator.cs
@@ -2,17 +2,8 @@ using FluentValidation;
namespace Features.Breweries.Commands.CreateBrewery;
-///
-/// Validates instances before they are processed.
-///
public class CreateBreweryValidator : AbstractValidator
{
- ///
- /// Configures validation rules requiring ,
- /// , , and
- /// to be present, with length limits on the name, description,
- /// address line 1, and postal code fields.
- ///
public CreateBreweryValidator()
{
RuleFor(x => x.PostedById).NotEmpty().WithMessage("PostedById is required.");
diff --git a/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryCommand.cs b/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryCommand.cs
index 2b07ec6f..5e939d16 100644
--- a/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryCommand.cs
+++ b/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryCommand.cs
@@ -2,7 +2,4 @@ using MediatR;
namespace Features.Breweries.Commands.DeleteBrewery;
-///
-/// Deletes a brewery post by its unique identifier.
-///
public record DeleteBreweryCommand(Guid BreweryPostId) : IRequest;
diff --git a/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryHandler.cs b/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryHandler.cs
index 226a0d04..7cf2dac9 100644
--- a/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryHandler.cs
+++ b/web/backend/Features/Features.Breweries/Commands/DeleteBrewery/DeleteBreweryHandler.cs
@@ -3,10 +3,6 @@ using MediatR;
namespace Features.Breweries.Commands.DeleteBrewery;
-///
-/// Handles by deleting the matching brewery post.
-///
-/// Repository used to delete the brewery post.
public class DeleteBreweryHandler(IBreweryRepository repository)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryCommand.cs b/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryCommand.cs
index f2dc90db..00377407 100644
--- a/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryCommand.cs
+++ b/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryCommand.cs
@@ -3,9 +3,6 @@ using MediatR;
namespace Features.Breweries.Commands.UpdateBrewery;
-///
-/// Location data for an existing brewery post, supplied as part of .
-///
public record UpdateBreweryLocation(
Guid BreweryPostLocationId,
Guid CityId,
diff --git a/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryHandler.cs b/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryHandler.cs
index cb6c033a..5ba89607 100644
--- a/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryHandler.cs
+++ b/web/backend/Features/Features.Breweries/Commands/UpdateBrewery/UpdateBreweryHandler.cs
@@ -5,10 +5,6 @@ using MediatR;
namespace Features.Breweries.Commands.UpdateBrewery;
-///
-/// Handles by persisting changes to an existing brewery post.
-///
-/// Repository used to persist the updated brewery post.
public class UpdateBreweryHandler(IBreweryRepository repository)
: IRequestHandler
{
@@ -16,9 +12,6 @@ public class UpdateBreweryHandler(IBreweryRepository repository)
/// Updates an existing brewery post. If has no Location,
/// the brewery's location is cleared.
///
- /// The updated details of the brewery post.
- /// A token to observe for cancellation requests.
- /// The updated brewery post.
public async Task Handle(
UpdateBreweryCommand request,
CancellationToken cancellationToken
diff --git a/web/backend/Features/Features.Breweries/Controllers/BreweryController.cs b/web/backend/Features/Features.Breweries/Controllers/BreweryController.cs
index 25eb393c..115d6008 100644
--- a/web/backend/Features/Features.Breweries/Controllers/BreweryController.cs
+++ b/web/backend/Features/Features.Breweries/Controllers/BreweryController.cs
@@ -11,28 +11,17 @@ using Shared.Contracts;
namespace Features.Breweries.Controllers;
-///
-/// Provides CRUD endpoints for managing brewery posts.
-///
///
-/// The controller is decorated with [Authorize(AuthenticationSchemes = "JWT")] by default; read endpoints
-/// ( and ) opt out via [AllowAnonymous].
+/// Requires JWT authentication by default; and opt out via
+/// [AllowAnonymous].
///
-/// Used to dispatch brewery commands and queries to their handlers.
[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "JWT")]
public class BreweryController(IMediator mediator) : ControllerBase
{
- ///
- /// Retrieves a single brewery post by its unique identifier.
- ///
/// Allows anonymous access.
- /// The unique identifier of the brewery post to retrieve.
- ///
- /// A 200 OK result wrapping a of if found;
- /// otherwise a 404 Not Found result wrapping a error message.
- ///
+ /// 200 OK with the brewery if found; otherwise 404 Not Found.
[AllowAnonymous]
[HttpGet("{id:guid}")]
public async Task>> GetById(Guid id)
@@ -50,13 +39,7 @@ public class BreweryController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Retrieves a paginated list of brewery posts.
- ///
/// Allows anonymous access.
- /// The maximum number of brewery posts to return, or null for no limit.
- /// The number of brewery posts to skip before returning results, or null for no offset.
- /// A 200 OK result wrapping a of a collection of .
[AllowAnonymous]
[HttpGet]
public async Task>>> GetAll(
@@ -76,14 +59,7 @@ public class BreweryController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Creates a new brewery post.
- ///
- /// The brewery details to create, including the posting user, name, description, and location.
- ///
- /// A 201 Created result wrapping a of the newly created
- /// .
- ///
+ /// 201 Created with the newly created brewery.
[HttpPost]
public async Task>> Create(
[FromBody] CreateBreweryCommand command
@@ -100,22 +76,8 @@ public class BreweryController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Updates an existing brewery post.
- ///
- ///
- /// The unique identifier of the brewery post from the route, which must match
- /// 's ID.
- ///
- ///
- /// The updated brewery details, including the posting user, name, description, and optional
- /// location.
- ///
- ///
- /// A 200 OK result wrapping a of the updated if the
- /// update succeeds; otherwise a 400 Bad Request result wrapping a error message
- /// when the route ID does not match the payload ID.
- ///
+ /// Must match 's BreweryPostId.
+ /// 200 OK with the updated brewery; or 400 Bad Request if the route ID does not match the payload ID.
[HttpPut("{id:guid}")]
public async Task>> Update(
Guid id,
@@ -135,11 +97,7 @@ public class BreweryController(IMediator mediator) : ControllerBase
);
}
- ///
- /// Deletes a brewery post.
- ///
- /// The unique identifier of the brewery post to delete.
- /// A 200 OK result wrapping a confirming the deletion.
+ /// 200 OK confirming the deletion.
[HttpDelete("{id:guid}")]
public async Task> Delete(Guid id)
{
diff --git a/web/backend/Features/Features.Breweries/Dtos/BreweryDto.cs b/web/backend/Features/Features.Breweries/Dtos/BreweryDto.cs
index 616cacf4..cbbfc2a3 100644
--- a/web/backend/Features/Features.Breweries/Dtos/BreweryDto.cs
+++ b/web/backend/Features/Features.Breweries/Dtos/BreweryDto.cs
@@ -1,89 +1,39 @@
namespace Features.Breweries.Dtos;
-///
-/// Represents the location details of an existing brewery, as returned in .
-///
public class BreweryLocationDto
{
- ///
- /// The unique identifier of the brewery's location record.
- ///
public Guid BreweryPostLocationId { get; set; }
- ///
- /// The unique identifier of the brewery post that this location belongs to.
- ///
public Guid BreweryPostId { get; set; }
- ///
- /// The unique identifier of the city in which the brewery is located.
- ///
public Guid CityId { get; set; }
- ///
- /// The primary street address line of the brewery.
- ///
public string AddressLine1 { get; set; } = string.Empty;
- ///
- /// An optional secondary address line (e.g. suite or unit number).
- ///
public string? AddressLine2 { get; set; }
- ///
- /// The postal/ZIP code of the brewery's address.
- ///
public string PostalCode { get; set; } = string.Empty;
- ///
- /// The optional geographic coordinates of the brewery, in a raw binary representation.
- ///
+ /// Gets or sets the brewery's geographic coordinates, in a raw binary representation.
public byte[]? Coordinates { get; set; }
}
-///
-/// Represents a brewery post as returned by the brewery endpoints, including its metadata and
-/// optional location.
-///
public class BreweryDto
{
- ///
- /// The unique identifier of the brewery post.
- ///
public Guid BreweryPostId { get; set; }
- ///
- /// The unique identifier of the user account that created the brewery post.
- ///
public Guid PostedById { get; set; }
- ///
- /// The name of the brewery.
- ///
public string BreweryName { get; set; } = string.Empty;
- ///
- /// A description of the brewery.
- ///
public string Description { get; set; } = string.Empty;
- ///
- /// The date and time at which the brewery post was created.
- ///
public DateTime CreatedAt { get; set; }
- ///
- /// The date and time at which the brewery post was last updated, or null if it has never been updated.
- ///
public DateTime? UpdatedAt { get; set; }
- ///
- /// A row-version/concurrency token used to detect conflicting concurrent updates to the brewery post.
- ///
+ /// Gets or sets the row-version/concurrency token used to detect conflicting concurrent updates.
public byte[]? Timer { get; set; }
- ///
- /// The location details of the brewery, or null if no location is associated with it.
- ///
public BreweryLocationDto? Location { get; set; }
}
diff --git a/web/backend/Features/Features.Breweries/Dtos/BreweryDtoMapper.cs b/web/backend/Features/Features.Breweries/Dtos/BreweryDtoMapper.cs
index 4cba3518..89ce7e54 100644
--- a/web/backend/Features/Features.Breweries/Dtos/BreweryDtoMapper.cs
+++ b/web/backend/Features/Features.Breweries/Dtos/BreweryDtoMapper.cs
@@ -2,17 +2,8 @@ using Domain.Entities;
namespace Features.Breweries.Dtos;
-///
-/// Maps domain entities to their wire representation.
-///
public static class BreweryDtoMapper
{
- ///
- /// Maps a domain entity to its representation,
- /// including its location, if present.
- ///
- /// The brewery post entity to map.
- /// The mapped .
public static BreweryDto ToDto(this BreweryPost brewery)
{
return new BreweryDto
diff --git a/web/backend/Features/Features.Breweries/Queries/GetAllBreweries/GetAllBreweriesHandler.cs b/web/backend/Features/Features.Breweries/Queries/GetAllBreweries/GetAllBreweriesHandler.cs
index e9a37484..6f06ada8 100644
--- a/web/backend/Features/Features.Breweries/Queries/GetAllBreweries/GetAllBreweriesHandler.cs
+++ b/web/backend/Features/Features.Breweries/Queries/GetAllBreweries/GetAllBreweriesHandler.cs
@@ -5,10 +5,6 @@ using MediatR;
namespace Features.Breweries.Queries.GetAllBreweries;
-///
-/// Handles by retrieving a paginated list of brewery posts.
-///
-/// Repository used to query brewery post data.
public class GetAllBreweriesHandler(IBreweryRepository repository)
: IRequestHandler>
{
diff --git a/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdHandler.cs b/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdHandler.cs
index 72f510e1..e80ec1c8 100644
--- a/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdHandler.cs
+++ b/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdHandler.cs
@@ -5,10 +5,6 @@ using MediatR;
namespace Features.Breweries.Queries.GetBreweryById;
-///
-/// Handles by looking up the matching brewery post.
-///
-/// Repository used to query brewery post data.
public class GetBreweryByIdHandler(IBreweryRepository repository)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdQuery.cs b/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdQuery.cs
index 5f4fc13f..ece9133d 100644
--- a/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdQuery.cs
+++ b/web/backend/Features/Features.Breweries/Queries/GetBreweryById/GetBreweryByIdQuery.cs
@@ -3,7 +3,4 @@ using MediatR;
namespace Features.Breweries.Queries.GetBreweryById;
-///
-/// Retrieves a single brewery post by its unique identifier.
-///
public record GetBreweryByIdQuery(Guid BreweryPostId) : IRequest;
diff --git a/web/backend/Features/Features.Breweries/Repository/BreweryRepository.cs b/web/backend/Features/Features.Breweries/Repository/BreweryRepository.cs
index cc5e24b6..4baa9c43 100644
--- a/web/backend/Features/Features.Breweries/Repository/BreweryRepository.cs
+++ b/web/backend/Features/Features.Breweries/Repository/BreweryRepository.cs
@@ -9,17 +9,11 @@ namespace Features.Breweries.Repository;
/// ADO.NET-based implementation of backed by SQL Server stored
/// procedures.
///
-/// The factory used to create database connections.
public class BreweryRepository(ISqlConnectionFactory connectionFactory)
: Repository(connectionFactory),
IBreweryRepository
{
- ///
- /// Retrieves a brewery post by ID using the USP_GetBreweryById stored procedure.
- ///
- /// The unique identifier of the brewery post.
- /// The matching , or null if not found.
- /// Thrown when the database command fails.
+ /// Retrieves a brewery post by ID using the USP_GetBreweryById stored procedure.
public async Task GetByIdAsync(Guid id)
{
await using DbConnection connection = await CreateConnection();
@@ -40,10 +34,6 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
/// stored procedure. The @Limit and @Offset parameters are only added when their
/// corresponding argument has a value.
///
- /// The maximum number of records to return, or null for no limit.
- /// The number of records to skip, or null for no offset.
- /// The collection of matching records.
- /// Thrown when the database command fails.
public async Task> GetAllAsync(int? limit, int? offset)
{
await using DbConnection connection = await CreateConnection();
@@ -71,8 +61,6 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
/// USP_UpdateBrewery stored procedure. When .Location is
/// null, any existing location for the brewery is removed.
///
- /// The brewery post containing updated values.
- /// Thrown when the database command fails.
public async Task UpdateAsync(BreweryPost brewery)
{
await using DbConnection connection = await CreateConnection();
@@ -97,8 +85,6 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
/// Deletes a brewery post by ID using the USP_DeleteBrewery stored procedure. Its location
/// and photos are removed via cascading foreign keys.
///
- /// The unique identifier of the brewery post to delete.
- /// Thrown when the database command fails.
public async Task DeleteAsync(Guid id)
{
await using DbConnection connection = await CreateConnection();
@@ -110,12 +96,8 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await command.ExecuteNonQueryAsync();
}
- ///
- /// Creates a new brewery post and its location using the USP_CreateBrewery stored procedure.
- ///
- /// The brewery post to create. Must have a non-null Location.
+ /// Creates a new brewery post and its location using the USP_CreateBrewery stored procedure.
/// Thrown when .Location is null.
- /// Thrown when the database command fails.
public async Task CreateAsync(BreweryPost brewery)
{
await using DbConnection connection = await CreateConnection();
@@ -139,12 +121,9 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
}
///
- /// Maps the current row of a data reader to a entity, including its
- /// rowversion Timer field and, if location columns are present in the result set, its
- /// associated .
+ /// Maps the current row of to a , including its
+ /// associated if location columns are present in the result set.
///
- /// The data reader positioned on the row to map.
- /// The mapped instance.
protected override BreweryPost MapToEntity(DbDataReader reader)
{
BreweryPost brewery = new();
@@ -212,13 +191,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
return brewery;
}
- ///
- /// Helper method to add a parameter to a database command, converting null values to
- /// .
- ///
- /// The command to add the parameter to.
- /// The parameter name (including any prefix, e.g. "@BreweryName").
- /// The parameter value, or null to bind .
+ /// Adds a parameter to , converting null to .
private static void AddParameter(DbCommand command, string name, object? value)
{
DbParameter p = command.CreateParameter();
diff --git a/web/backend/Features/Features.Breweries/Repository/IBreweryRepository.cs b/web/backend/Features/Features.Breweries/Repository/IBreweryRepository.cs
index e976c2ad..a23ab59e 100644
--- a/web/backend/Features/Features.Breweries/Repository/IBreweryRepository.cs
+++ b/web/backend/Features/Features.Breweries/Repository/IBreweryRepository.cs
@@ -7,37 +7,16 @@ namespace Features.Breweries.Repository;
///
public interface IBreweryRepository
{
- ///
- /// Retrieves a brewery post by its unique identifier.
- ///
- /// The unique identifier of the brewery post.
- /// The matching , or null if not found.
+ /// Retrieves a brewery post by ID, or null if not found.
Task GetByIdAsync(Guid id);
- ///
- /// Retrieves all brewery posts, optionally paginated.
- ///
- /// The maximum number of records to return, or null for no limit.
- /// The number of records to skip, or null for no offset.
- /// The collection of matching records.
Task> GetAllAsync(int? limit, int? offset);
- ///
- /// Updates an existing brewery post.
- ///
- /// The brewery post containing updated values.
Task UpdateAsync(BreweryPost brewery);
- ///
- /// Deletes a brewery post by its unique identifier.
- ///
- /// The unique identifier of the brewery post to delete.
Task DeleteAsync(Guid id);
- ///
- /// Creates a new brewery post, including its location details.
- ///
- /// The brewery post to create. Must have a non-null Location.
+ /// Creates a new brewery post, including its location details.
/// Thrown when has no Location.
Task CreateAsync(BreweryPost brewery);
}
diff --git a/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs b/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs
index 0da0cdce..31981b69 100644
--- a/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs
+++ b/web/backend/Features/Features.Emails/Commands/SendRegistrationEmail/SendRegistrationEmailHandler.cs
@@ -8,7 +8,6 @@ namespace Features.Emails.Commands.SendRegistrationEmail;
/// Handles , the cross-slice command sent by Features.Auth
/// after a new user registers.
///
-/// Dispatcher used to render and send the email.
public class SendRegistrationEmailHandler(IEmailDispatcher emailDispatcher)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs b/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs
index 17f52009..d04419b9 100644
--- a/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs
+++ b/web/backend/Features/Features.Emails/Commands/SendResendConfirmationEmail/SendResendConfirmationEmailHandler.cs
@@ -8,7 +8,6 @@ namespace Features.Emails.Commands.SendResendConfirmationEmail;
/// Handles , the cross-slice command sent by Features.Auth
/// when a user requests a fresh confirmation link.
///
-/// Dispatcher used to render and send the email.
public class SendResendConfirmationEmailHandler(IEmailDispatcher emailDispatcher)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.Emails/DependencyInjection/FeaturesEmailsServiceCollectionExtensions.cs b/web/backend/Features/Features.Emails/DependencyInjection/FeaturesEmailsServiceCollectionExtensions.cs
index 8b97dbdb..5a64d9db 100644
--- a/web/backend/Features/Features.Emails/DependencyInjection/FeaturesEmailsServiceCollectionExtensions.cs
+++ b/web/backend/Features/Features.Emails/DependencyInjection/FeaturesEmailsServiceCollectionExtensions.cs
@@ -5,9 +5,6 @@ using Microsoft.Extensions.DependencyInjection;
namespace Features.Emails.DependencyInjection;
-///
-/// Registers the services owned by the Emails feature slice.
-///
public static class FeaturesEmailsServiceCollectionExtensions
{
public static IServiceCollection AddFeaturesEmails(this IServiceCollection services)
diff --git a/web/backend/Features/Features.Emails/Services/EmailDispatcher.cs b/web/backend/Features/Features.Emails/Services/EmailDispatcher.cs
index 436560e6..01c42c37 100644
--- a/web/backend/Features/Features.Emails/Services/EmailDispatcher.cs
+++ b/web/backend/Features/Features.Emails/Services/EmailDispatcher.cs
@@ -4,11 +4,8 @@ using Infrastructure.Email.Templates.Rendering;
namespace Features.Emails.Services;
///
-/// Default implementation of that renders email templates and dispatches
-/// them via an .
+/// Default implementation of .
///
-/// Provider used to deliver the rendered emails.
-/// Provider used to render HTML email bodies from templates.
public class EmailDispatcher(
IEmailProvider emailProvider,
IEmailTemplateProvider emailTemplateProvider
@@ -25,10 +22,6 @@ public class EmailDispatcher(
Environment.GetEnvironmentVariable("WEBSITE_BASE_URL")
?? throw new InvalidOperationException("WEBSITE_BASE_URL environment variable is not set");
- ///
- /// Builds a confirmation link from the given token, renders the registration welcome email template,
- /// and sends it to the newly created user.
- ///
public async Task SendRegistrationEmailAsync(
string firstName,
string email,
@@ -45,10 +38,6 @@ public class EmailDispatcher(
await emailProvider.SendAsync(email, "Welcome to The Biergarten App!", emailHtml, true);
}
- ///
- /// Builds a confirmation link from the given token, renders the resend-confirmation email template,
- /// and sends it to the user.
- ///
public async Task SendResendConfirmationEmailAsync(
string firstName,
string email,
diff --git a/web/backend/Features/Features.Emails/Services/IEmailDispatcher.cs b/web/backend/Features/Features.Emails/Services/IEmailDispatcher.cs
index 8a4b3267..686a98a6 100644
--- a/web/backend/Features/Features.Emails/Services/IEmailDispatcher.cs
+++ b/web/backend/Features/Features.Emails/Services/IEmailDispatcher.cs
@@ -1,25 +1,17 @@
namespace Features.Emails.Services;
///
-/// Defines operations for sending account-related emails, such as registration and confirmation resend emails.
+/// Defines operations for sending account-related emails.
///
public interface IEmailDispatcher
{
///
/// Sends a welcome email containing an account confirmation link to a newly registered user.
///
- /// The recipient's first name, used to personalize the email.
- /// The recipient's email address.
- /// The confirmation token to embed in the confirmation link.
- /// A task that completes once the email has been sent.
Task SendRegistrationEmailAsync(string firstName, string email, string confirmationToken);
///
/// Sends an email containing a fresh account confirmation link to a user who requested a resend.
///
- /// The recipient's first name, used to personalize the email.
- /// The recipient's email address.
- /// The confirmation token to embed in the confirmation link.
- /// A task that completes once the email has been sent.
Task SendResendConfirmationEmailAsync(string firstName, string email, string confirmationToken);
}
diff --git a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs b/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs
index cee83da1..4967b127 100644
--- a/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs
+++ b/web/backend/Features/Features.UserManagement/Commands/UpdateUser/UpdateUserHandler.cs
@@ -3,10 +3,6 @@ using MediatR;
namespace Features.UserManagement.Commands.UpdateUser;
-///
-/// Handles by persisting changes to an existing user account.
-///
-/// Repository used to persist the updated user account.
public class UpdateUserHandler(IUserAccountRepository repository)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.UserManagement/Controllers/UserController.cs b/web/backend/Features/Features.UserManagement/Controllers/UserController.cs
index 90987d65..1bd98ce7 100644
--- a/web/backend/Features/Features.UserManagement/Controllers/UserController.cs
+++ b/web/backend/Features/Features.UserManagement/Controllers/UserController.cs
@@ -6,20 +6,12 @@ using Microsoft.AspNetCore.Mvc;
namespace Features.UserManagement.Controllers;
-///
-/// Provides read-only endpoints for retrieving user accounts.
-///
-/// Used to dispatch user queries to their handlers.
[ApiController]
[Route("api/[controller]")]
public class UserController(IMediator mediator) : ControllerBase
{
- ///
- /// Retrieves a paginated list of user accounts.
- ///
- /// The maximum number of user accounts to return, or null for no limit.
- /// The number of user accounts to skip before returning results, or null for no offset.
- /// A 200 OK result containing the collection of entities.
+ /// null for no limit.
+ /// null for no offset.
[HttpGet]
public async Task>> GetAll(
[FromQuery] int? limit,
@@ -30,11 +22,6 @@ public class UserController(IMediator mediator) : ControllerBase
return Ok(users);
}
- ///
- /// Retrieves a single user account by its unique identifier.
- ///
- /// The unique identifier of the user account to retrieve.
- /// A 200 OK result containing the matching .
[HttpGet("{id:guid}")]
public async Task> GetById(Guid id)
{
diff --git a/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs b/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs
index 1c6c7947..ebd3c081 100644
--- a/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs
+++ b/web/backend/Features/Features.UserManagement/DependencyInjection/FeaturesUserManagementServiceCollectionExtensions.cs
@@ -3,9 +3,6 @@ using Microsoft.Extensions.DependencyInjection;
namespace Features.UserManagement.DependencyInjection;
-///
-/// Registers the services owned by the UserManagement feature slice.
-///
public static class FeaturesUserManagementServiceCollectionExtensions
{
public static IServiceCollection AddFeaturesUserManagement(this IServiceCollection services)
diff --git a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs b/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs
index 10b566af..4e8afe82 100644
--- a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs
+++ b/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersHandler.cs
@@ -4,10 +4,6 @@ using MediatR;
namespace Features.UserManagement.Queries.GetAllUsers;
-///
-/// Handles by retrieving a paginated list of user accounts.
-///
-/// Repository used to query user account data.
public class GetAllUsersHandler(IUserAccountRepository repository)
: IRequestHandler>
{
diff --git a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs b/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs
index a1a32416..90adf926 100644
--- a/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs
+++ b/web/backend/Features/Features.UserManagement/Queries/GetAllUsers/GetAllUsersQuery.cs
@@ -3,7 +3,4 @@ using MediatR;
namespace Features.UserManagement.Queries.GetAllUsers;
-///
-/// Retrieves a paginated list of user accounts.
-///
public record GetAllUsersQuery(int? Limit, int? Offset) : IRequest>;
diff --git a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs b/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs
index 405afec7..d664310e 100644
--- a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs
+++ b/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdHandler.cs
@@ -5,10 +5,6 @@ using MediatR;
namespace Features.UserManagement.Queries.GetUserById;
-///
-/// Handles by looking up the matching user account.
-///
-/// Repository used to query user account data.
public class GetUserByIdHandler(IUserAccountRepository repository)
: IRequestHandler
{
diff --git a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs b/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs
index dab2a1cd..8337b7a9 100644
--- a/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs
+++ b/web/backend/Features/Features.UserManagement/Queries/GetUserById/GetUserByIdQuery.cs
@@ -3,7 +3,4 @@ using MediatR;
namespace Features.UserManagement.Queries.GetUserById;
-///
-/// Retrieves a single user account by its unique identifier.
-///
public record GetUserByIdQuery(Guid UserAccountId) : IRequest;
diff --git a/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs b/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs
index 94973010..7ba4c08d 100644
--- a/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs
+++ b/web/backend/Features/Features.UserManagement/Repository/IUserAccountRepository.cs
@@ -8,43 +8,29 @@ namespace Features.UserManagement.Repository;
public interface IUserAccountRepository
{
///
- /// Retrieves a user account by its unique identifier.
+ /// Retrieves a user account by its unique identifier, or null if not found.
///
- /// The unique identifier of the user account.
- /// The matching , or null if not found.
Task GetByIdAsync(Guid id);
///
/// Retrieves all user accounts, optionally paginated.
///
- /// The maximum number of records to return, or null for no limit.
- /// The number of records to skip, or null for no offset.
- /// The collection of matching records.
+ /// null for no limit.
+ /// null for no offset.
Task> GetAllAsync(int? limit, int? offset);
- ///
- /// Updates an existing user account's details.
- ///
- /// The user account containing updated values. Must have a valid UserAccountId.
+ /// Must have a valid UserAccountId.
Task UpdateAsync(UserAccount userAccount);
- ///
- /// Deletes a user account by its unique identifier.
- ///
- /// The unique identifier of the user account to delete.
Task DeleteAsync(Guid id);
///
- /// Retrieves a user account by username.
+ /// Retrieves a user account by username, or null if not found.
///
- /// The username to search for.
- /// The matching , or null if not found.
Task GetByUsernameAsync(string username);
///
- /// Retrieves a user account by email address.
+ /// Retrieves a user account by email address, or null if not found.
///
- /// The email address to search for.
- /// The matching , or null if not found.
Task GetByEmailAsync(string email);
}
diff --git a/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs b/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs
index 743d05e1..f03d49d6 100644
--- a/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs
+++ b/web/backend/Features/Features.UserManagement/Repository/UserAccountRepository.cs
@@ -9,17 +9,12 @@ namespace Features.UserManagement.Repository;
/// ADO.NET-based implementation of backed by SQL Server
/// stored procedures.
///
-/// The factory used to create database connections.
public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
: Repository(connectionFactory),
IUserAccountRepository
{
- ///
- /// Retrieves a user account by ID using the usp_GetUserAccountById stored procedure.
- ///
- /// The unique identifier of the user account.
- /// The matching , or null if not found.
- /// Thrown when the database command fails.
+ /// Uses the usp_GetUserAccountById stored procedure.
+ ///
public async Task GetByIdAsync(Guid id)
{
await using DbConnection connection = await CreateConnection();
@@ -34,14 +29,10 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
}
///
- /// Retrieves all user accounts, optionally paginated, using the usp_GetAllUserAccounts
- /// stored procedure. The @Limit and @Offset parameters are only added when their
- /// corresponding argument has a value.
+ /// Uses the usp_GetAllUserAccounts stored procedure. The @Limit and @Offset
+ /// parameters are only added when their corresponding argument has a value.
///
- /// The maximum number of records to return, or null for no limit.
- /// The number of records to skip, or null for no offset.
- /// The collection of matching records.
- /// Thrown when the database command fails.
+ ///
public async Task> GetAllAsync(int? limit, int? offset)
{
await using DbConnection connection = await CreateConnection();
@@ -68,8 +59,7 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
/// Updates a user account's username, first name, last name, email, and date of birth using
/// the usp_UpdateUserAccount stored procedure.
///
- /// The user account containing updated values. Must have a valid UserAccountId.
- /// Thrown when the database command fails.
+ ///
public async Task UpdateAsync(UserAccount userAccount)
{
await using DbConnection connection = await CreateConnection();
@@ -87,11 +77,8 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
await command.ExecuteNonQueryAsync();
}
- ///
- /// Deletes a user account by ID using the usp_DeleteUserAccount stored procedure.
- ///
- /// The unique identifier of the user account to delete.
- /// Thrown when the database command fails.
+ /// Uses the usp_DeleteUserAccount stored procedure.
+ ///
public async Task DeleteAsync(Guid id)
{
await using DbConnection connection = await CreateConnection();
@@ -103,12 +90,8 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
await command.ExecuteNonQueryAsync();
}
- ///
- /// Retrieves a user account by username using the usp_GetUserAccountByUsername stored procedure.
- ///
- /// The username to search for.
- /// The matching , or null if not found.
- /// Thrown when the database command fails.
+ /// Uses the usp_GetUserAccountByUsername stored procedure.
+ ///
public async Task GetByUsernameAsync(string username)
{
await using DbConnection connection = await CreateConnection();
@@ -122,12 +105,8 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
return await reader.ReadAsync() ? MapToEntity(reader) : null;
}
- ///
- /// Retrieves a user account by email address using the usp_GetUserAccountByEmail stored procedure.
- ///
- /// The email address to search for.
- /// The matching , or null if not found.
- /// Thrown when the database command fails.
+ /// Uses the usp_GetUserAccountByEmail stored procedure.
+ ///
public async Task GetByEmailAsync(string email)
{
await using DbConnection connection = await CreateConnection();
@@ -141,11 +120,6 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
return await reader.ReadAsync() ? MapToEntity(reader) : null;
}
- ///
- /// Maps the current row of a data reader to a entity.
- ///
- /// The data reader positioned on the row to map.
- /// The mapped instance.
protected override UserAccount MapToEntity(DbDataReader reader)
{
return new UserAccount
@@ -164,13 +138,7 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
};
}
- ///
- /// Helper method to add a parameter to a database command, converting null values to
- /// .
- ///
- /// The command to add the parameter to.
- /// The parameter name (including any prefix, e.g. "@Username").
- /// The parameter value, or null to bind .
+ /// Converts null values to when adding the parameter.
private static void AddParameter(DbCommand command, string name, object? value)
{
DbParameter p = command.CreateParameter();