Do you recommend adding a layer of abstraction on top of EF Core for example we have an API controller responsible for authentication do I just call EF Core methods directly in the controller or do I add a service that manages all the methods needed for authentication? An authService that uses EF Core methods or go further and make both a user repository and an authService that uses the user repository, I am honestly so confused to how I would go about this.
This is an example of how I would implement this:
[HttpPost("sign-up")]
[AllowAnonymous]
public async Task<IActionResult> RegisterUser([FromBody] EssentialSignUpCredentials registerCredentials)
{
    
    var clientEmail = registerCredentials.email;
    var clientUserName = registerCredentials.userName;
    var ipAddress = HttpContext.Connection.RemoteIpAddress?.MapToIPv4();
    var response=await authService.SignUpAsync(registerCredentials.email, registerCredentials.userName, ipAddress);
    
    return response.Match<IActionResult>(Ok, BadRequest);
}
public class AuthService(IJwtTokenService jwtTokenService, IUserService userService, DBContext dbContext) : IAuthService
{
    public async Task<Result<SignInResponse>> SignInAsync()
    {
        throw new NotImplementedException();
    }
    public async Task<Result> SignUpAsync(string email, string userName, IPAddress ipAddress)
    {
        await using var transaction = await dbContext.Database.BeginTransactionAsync();
        var response = await userService.CreateUserAsync(email, userName, ipAddress);
        return await response.MatchAsync<Result, User>(async success =>
        {
            var rolesResponse = await userService.AddRolesToUserAsync(success.Data);
            if (!rolesResponse.isSuccess)
                return Result.Failure(rolesResponse.FailureValue.errors.ToArray(),
                    rolesResponse.FailureValue.StatusCode);
            await transaction.CommitAsync();
            return Result.Success();
        }, failure => Result.Failure(response.FailureValue.errors.ToArray(), response.FailureValue.StatusCode));
    }
}
Do you recommend this sort of approach? Is the transaction in authorization service considered best practice? Is this considered clean code?

