From 9f76b203e3f462dad9e72ce59a0be5d511938a8c Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 3 Sep 2026 16:37:25 +0200 Subject: [PATCH] Added service level caching to IdentityService, Communication and Evidence --- .../GetApplicantInviteEndpoint.cs | 6 +- .../Communications/GetInvitesEndpoint.cs | 4 +- .../Communications/SendInviteEndpoint.cs | 3 +- .../Evidence/CreateEvidenceEndpoint.cs | 4 +- .../Evidence/CreateIndicatorEndpoint.cs | 3 +- .../Evidence/CreateMilestoneEndpoint.cs | 3 +- .../Endpoints/Evidence/GetEvidenceEndpoint.cs | 6 +- .../Evidence/GetEvidenceFilesEndpoint.cs | 4 +- .../Evidence/GetIndicatorEndpoint.cs | 6 +- .../Evidence/GetIndicatorsEndpoint.cs | 4 +- .../Evidence/GetMilestoneEvidenceEndpoint.cs | 4 +- .../Evidence/GetProjectEvidenceEndpoint.cs | 4 +- .../Evidence/RecordIndicatorAmountEndpoint.cs | 4 +- .../Evidence/UpdateEvidenceEndpoint.cs | 9 +-- .../Endpoints/Users/GetUserEndpoint.cs | 6 +- .../Endpoints/Users/GetUsersEndpoint.cs | 3 +- .../Endpoints/Users/SyncUserEndpoint.cs | 4 +- .../Users/UpdateUserStatusEndpoint.cs | 6 +- PostFundManagement.Api/Program.cs | 3 +- .../Services/ICommunicationsService.cs | 14 +++++ .../Abstractions/Services/IEvidenceService.cs | 30 +++++++++ .../Abstractions/Services/IIdentityService.cs | 6 ++ .../Abstractions/Services/IUserService.cs | 16 +++++ .../Extensions/General.cs | 35 ++++++++--- .../Filters/ActiveUserFilter.cs | 4 +- .../PostFundManagement.Application.csproj | 1 + .../CommunicationsCacheService.cs | 22 +++++++ .../Communications/CommunicationsService.cs | 5 +- .../Services/Evidence/EvidenceCacheService.cs | 54 ++++++++++++++++ .../Services/Evidence/EvidenceService.cs | 27 ++++++-- .../Services/Shared/IdentityCacheService.cs | 31 ++++++++++ .../Services/Shared/IdentityService.cs | 6 +- .../Services/Users/UserCacheService.cs | 62 +++++++++++++++++++ .../Services/Users/UserService.cs | 6 +- .../PostFundManagement.Domain.csproj | 3 +- 35 files changed, 344 insertions(+), 64 deletions(-) create mode 100644 PostFundManagement.Application/Abstractions/Services/ICommunicationsService.cs create mode 100644 PostFundManagement.Application/Abstractions/Services/IEvidenceService.cs create mode 100644 PostFundManagement.Application/Abstractions/Services/IIdentityService.cs create mode 100644 PostFundManagement.Application/Abstractions/Services/IUserService.cs create mode 100644 PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs create mode 100644 PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs create mode 100644 PostFundManagement.Application/Services/Shared/IdentityCacheService.cs create mode 100644 PostFundManagement.Application/Services/Users/UserCacheService.cs diff --git a/PostFundManagement.Api/Endpoints/Communications/GetApplicantInviteEndpoint.cs b/PostFundManagement.Api/Endpoints/Communications/GetApplicantInviteEndpoint.cs index a5c7612..2045f6b 100644 --- a/PostFundManagement.Api/Endpoints/Communications/GetApplicantInviteEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Communications/GetApplicantInviteEndpoint.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Communications; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -14,7 +14,7 @@ public sealed class GetApplicantInviteEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/communications/invites/applicant/{userId:Guid}", async (Guid userId, CommunicationsService service, + builder.MapGet("api/communications/invites/applicant/{userId:Guid}", async (Guid userId, ICommunicationsService service, HttpContext context, CancellationToken cancellationToken = default) => await service.GetApplicantInviteAsync(userId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Communications/GetInvitesEndpoint.cs b/PostFundManagement.Api/Endpoints/Communications/GetInvitesEndpoint.cs index 59c307f..78b4090 100644 --- a/PostFundManagement.Api/Endpoints/Communications/GetInvitesEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Communications/GetInvitesEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Communications; using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Extensions; @@ -15,7 +15,7 @@ public sealed class GetInvitesEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/communications/invites/{page:int}/{pageSize:int}", async (CommunicationsService service, + builder.MapGet("api/communications/invites/{page:int}/{pageSize:int}", async (ICommunicationsService service, int page = 1, int pageSize = 100, CancellationToken cancellationToken = default) => await service.GetInvitesAsync(Pagination.Create(page, pageSize), cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Communications/SendInviteEndpoint.cs b/PostFundManagement.Api/Endpoints/Communications/SendInviteEndpoint.cs index 5ba08c4..589581d 100644 --- a/PostFundManagement.Api/Endpoints/Communications/SendInviteEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Communications/SendInviteEndpoint.cs @@ -1,3 +1,4 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Communications; using PostFundManagement.Domain.Abstractions; @@ -15,7 +16,7 @@ public sealed class SendInviteEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapPost("api/communications/invite", async (InviteRequest request, - HttpContext context, CommunicationsService service, CancellationToken cancellationToken = default) => + HttpContext context, ICommunicationsService service, CancellationToken cancellationToken = default) => await service.SendInviteAsync(request, context.GetUserId(), cancellationToken) switch { { IsSuccess: true, Value: var invite } => Results.Ok(invite), diff --git a/PostFundManagement.Api/Endpoints/Evidence/CreateEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/CreateEvidenceEndpoint.cs index c694dc8..08683f5 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/CreateEvidenceEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/CreateEvidenceEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -13,7 +13,7 @@ public class CreateEvidenceEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapPut("api/evidence/file", async (HttpRequest request, EvidenceService service, + builder.MapPut("api/evidence/file", async (HttpRequest request, IEvidenceService service, CancellationToken cancellationToken = default) => { var userId = request.HttpContext.GetUserId(); diff --git a/PostFundManagement.Api/Endpoints/Evidence/CreateIndicatorEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/CreateIndicatorEndpoint.cs index cc641a9..1e1ae98 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/CreateIndicatorEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/CreateIndicatorEndpoint.cs @@ -1,3 +1,4 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; @@ -14,7 +15,7 @@ public class CreateIndicatorEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapPost("api/evidence/indicators", async (CreateIndicatorRequest request, HttpContext context, - EvidenceService service, CancellationToken cancellationToken = default) => + IEvidenceService service, CancellationToken cancellationToken = default) => await service.CreateIndicatorAsync(request, context.GetUserId(), cancellationToken) switch { { IsSuccess: true } => Results.Ok(), diff --git a/PostFundManagement.Api/Endpoints/Evidence/CreateMilestoneEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/CreateMilestoneEndpoint.cs index 14caaf9..209a1b6 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/CreateMilestoneEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/CreateMilestoneEndpoint.cs @@ -1,3 +1,4 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; @@ -14,7 +15,7 @@ public class CreateMilestoneEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapPost("api/evidence/milestones", async (CreateMilestoneRequest request, HttpContext context, - EvidenceService service, CancellationToken cancellationToken = default) => + IEvidenceService service, CancellationToken cancellationToken = default) => await service.CreateMilestoneAsync(request, context.GetUserId(), cancellationToken) switch { { IsSuccess: true } => Results.Ok(), diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs index df545b4..3268c7c 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceEndpoint.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -13,7 +13,7 @@ public sealed class GetEvidenceEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/{evidenceId}", async (string evidenceId, EvidenceService service, + builder.MapGet("api/evidence/{evidenceId}", async (string evidenceId, IEvidenceService service, CancellationToken cancellationToken = default) => await service.GetEvidenceAsync(evidenceId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceFilesEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceFilesEndpoint.cs index f771e10..f044cd8 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceFilesEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetEvidenceFilesEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Extensions; @@ -13,7 +13,7 @@ public class GetEvidenceFilesEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/files/{page:int}/{pageSize:int}", async (EvidenceService service, + builder.MapGet("api/evidence/files/{page:int}/{pageSize:int}", async (IEvidenceService service, int page = 1, int pageSize = 100, CancellationToken cancellationToken = default) => await service.GetEvidenceFilesAsync(Pagination.Create(page, pageSize), cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs index 856f65f..ff62c3a 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorEndpoint.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -14,7 +14,7 @@ public sealed class GetIndicatorEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/indicators/{indicatorId}", async (string indicatorId, EvidenceService service, + builder.MapGet("api/evidence/indicators/{indicatorId}", async (string indicatorId, IEvidenceService service, CancellationToken cancellationToken = default) => await service.GetIndicatorAsync(indicatorId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorsEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorsEndpoint.cs index 6e927e8..ab0640c 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorsEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetIndicatorsEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Extensions; @@ -14,7 +14,7 @@ public class GetIndicatorsEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/indicators/{page:int}/{pageSize:int}", async (EvidenceService service, + builder.MapGet("api/evidence/indicators/{page:int}/{pageSize:int}", async (IEvidenceService service, int page = 1, int pageSize = 100, CancellationToken cancellationToken = default) => await service.GetIndicatorsAsync(Pagination.Create(page, pageSize), cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEvidenceEndpoint.cs index 32d6845..cb9bc01 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEvidenceEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetMilestoneEvidenceEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -13,7 +13,7 @@ public class GetMilestoneEvidenceEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/milestone/{milestoneId}", async (string milestoneId, EvidenceService service, + builder.MapGet("api/evidence/milestone/{milestoneId}", async (string milestoneId, IEvidenceService service, CancellationToken cancellationToken = default) => await service.GetMilestoneEvidencesAsync(milestoneId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/GetProjectEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/GetProjectEvidenceEndpoint.cs index 9eea96b..bab6199 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/GetProjectEvidenceEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/GetProjectEvidenceEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -13,7 +13,7 @@ public class GetProjectEvidenceEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/evidence/milestone/{projectId}", async (string projectId, EvidenceService service, + builder.MapGet("api/evidence/milestone/{projectId}", async (string projectId, IEvidenceService service, CancellationToken cancellationToken = default) => await service.GetProjectEvidencesAsync(projectId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Evidence/RecordIndicatorAmountEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/RecordIndicatorAmountEndpoint.cs index bb901ea..6e4cc69 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/RecordIndicatorAmountEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/RecordIndicatorAmountEndpoint.cs @@ -1,5 +1,5 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -14,7 +14,7 @@ public class RecordIndicatorAmountEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapPost("api/evidence/indicators/{indicatorId}/actuals/{actualAmount:decimal}", async (string indicatorId, decimal actualAmount, - HttpContext context, EvidenceService service, CancellationToken cancellationToken = default) => + HttpContext context, IEvidenceService service, CancellationToken cancellationToken = default) => await service.RecordIndicatorActualAmountAsync(indicatorId, actualAmount, context.GetUserId(), cancellationToken) switch { { IsSuccess: true } => Results.Ok(), diff --git a/PostFundManagement.Api/Endpoints/Evidence/UpdateEvidenceEndpoint.cs b/PostFundManagement.Api/Endpoints/Evidence/UpdateEvidenceEndpoint.cs index efee423..f798759 100644 --- a/PostFundManagement.Api/Endpoints/Evidence/UpdateEvidenceEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Evidence/UpdateEvidenceEndpoint.cs @@ -1,4 +1,5 @@ -using PostFundManagement.Application.Extensions; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Evidence; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; @@ -13,19 +14,19 @@ public sealed class UpdateEvidenceEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapPut("api/evidence", async (UpdateEvidenceRequest request, HttpContext context, EvidenceService service, + builder.MapPut("api/evidence", async (UpdateEvidenceRequest request, HttpContext context, IEvidenceService service, CancellationToken cancellationToken = default) => await service.UpdateEvidenceAsync(request, context.GetUserId(), cancellationToken) switch { { IsSuccess: true } => Results.Ok(), - var r when r.HasError() => Results.Forbid(), + var r when r.HasError() => Results.NotFound(), var r when r.HasError() => Results.BadRequest(r.Errors.ToProblems()), var r => Results.InternalServerError(r.Errors.ToProblems()) }) .WithDescription("Updates a specific evidence record metadata") .WithName(typeof(UpdateEvidenceEndpoint).ToEndpointName()) .MapToApiVersion(new ApiVersion(1)) - .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status403Forbidden) .Produces(StatusCodes.Status401Unauthorized) diff --git a/PostFundManagement.Api/Endpoints/Users/GetUserEndpoint.cs b/PostFundManagement.Api/Endpoints/Users/GetUserEndpoint.cs index 727f8ad..406f419 100644 --- a/PostFundManagement.Api/Endpoints/Users/GetUserEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Users/GetUserEndpoint.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Users; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -14,7 +14,7 @@ public sealed class GetUserEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapGet("api/users/{userId:Guid}", async (Guid userId, UserService service, + builder.MapGet("api/users/{userId:Guid}", async (Guid userId, IUserService service, HttpContext context, CancellationToken cancellationToken = default) => await service.GetUserAsync(userId, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Users/GetUsersEndpoint.cs b/PostFundManagement.Api/Endpoints/Users/GetUsersEndpoint.cs index 9fde2c8..af35a2c 100644 --- a/PostFundManagement.Api/Endpoints/Users/GetUsersEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Users/GetUsersEndpoint.cs @@ -1,3 +1,4 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Users; using PostFundManagement.Domain; @@ -14,7 +15,7 @@ public class GetUsersEndpoint : IEndpoint { public void Map(IEndpointRouteBuilder builder) { - builder.MapPost("api/users/{page:int}/{pageSize:int}", async (UserFilterRequest request, UserService service, + builder.MapPost("api/users/{page:int}/{pageSize:int}", async (UserFilterRequest request, IUserService service, int page = 1, int pageSize = 100, CancellationToken cancellationToken = default) => await service.GetUsersAsync(Pagination.Create(page, pageSize), request, cancellationToken) switch { diff --git a/PostFundManagement.Api/Endpoints/Users/SyncUserEndpoint.cs b/PostFundManagement.Api/Endpoints/Users/SyncUserEndpoint.cs index ab3e381..5938d3a 100644 --- a/PostFundManagement.Api/Endpoints/Users/SyncUserEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Users/SyncUserEndpoint.cs @@ -1,6 +1,6 @@ +using PostFundManagement.Application.Abstractions.Services; using PostFundManagement.Application.Extensions; using PostFundManagement.Application.Services.Communications.Events; -using PostFundManagement.Application.Services.Users; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -15,7 +15,7 @@ public class SyncUserEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapPost("api/integration/sync", async (IJobOrchestrator jobOrchestrator, - HttpContext context, UserService service, CancellationToken cancellationToken = default) => + HttpContext context, IUserService service, CancellationToken cancellationToken = default) => { var result = await service.SyncUserAsync(context.GetUserId(), context.GetUserEmail(), cancellationToken); diff --git a/PostFundManagement.Api/Endpoints/Users/UpdateUserStatusEndpoint.cs b/PostFundManagement.Api/Endpoints/Users/UpdateUserStatusEndpoint.cs index 38b9b21..3da2556 100644 --- a/PostFundManagement.Api/Endpoints/Users/UpdateUserStatusEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Users/UpdateUserStatusEndpoint.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Application.Extensions; -using PostFundManagement.Application.Services.Users; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; @@ -15,7 +15,7 @@ public sealed class UpdateUserStatusEndpoint : IEndpoint public void Map(IEndpointRouteBuilder builder) { builder.MapGet("api/users/{userId:Guid}/status/{status:int}", async (Guid userId, ActivityStatus status, - UserService service, CancellationToken cancellationToken = default) => + IUserService service, CancellationToken cancellationToken = default) => await service.UpdateUserStatusAsync(userId, status, cancellationToken) switch { { IsSuccess: true } => Results.Ok(), diff --git a/PostFundManagement.Api/Program.cs b/PostFundManagement.Api/Program.cs index 11b6485..697c834 100644 --- a/PostFundManagement.Api/Program.cs +++ b/PostFundManagement.Api/Program.cs @@ -15,7 +15,8 @@ builder.Services.AddScoped(); builder.Services.AddEndpoints(Assembly.GetExecutingAssembly()); builder.Services.AddApiServices(builder.Configuration); -builder.Services.AddRegisterServices(builder.Configuration); +builder.Services.AddSharedServices(); +builder.Services.AddRegisterServicesWithCaching(builder.Configuration); builder.Services.AddEndpointAndServiceCaching(builder.Configuration); builder.Services.AddMediator(); diff --git a/PostFundManagement.Application/Abstractions/Services/ICommunicationsService.cs b/PostFundManagement.Application/Abstractions/Services/ICommunicationsService.cs new file mode 100644 index 0000000..1e3e77a --- /dev/null +++ b/PostFundManagement.Application/Abstractions/Services/ICommunicationsService.cs @@ -0,0 +1,14 @@ +using PostFundManagement.Application.Services.Communications; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Abstractions.Services; + +public interface ICommunicationsService +{ + ValueTask> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default); + + ValueTask> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default); + + ValueTask> GetApplicantInviteAsync(Guid userId, CancellationToken cancellationToken = default); +} diff --git a/PostFundManagement.Application/Abstractions/Services/IEvidenceService.cs b/PostFundManagement.Application/Abstractions/Services/IEvidenceService.cs new file mode 100644 index 0000000..e0f4a2f --- /dev/null +++ b/PostFundManagement.Application/Abstractions/Services/IEvidenceService.cs @@ -0,0 +1,30 @@ +using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Abstractions.Services; + +public interface IEvidenceService +{ + ValueTask CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default); + + ValueTask RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default); + + ValueTask> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default); + + ValueTask> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default); + + ValueTask CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default); + + ValueTask CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default); + + ValueTask> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken); + + ValueTask> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default); + + ValueTask> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default); + + ValueTask> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default); + + ValueTask UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default); +} diff --git a/PostFundManagement.Application/Abstractions/Services/IIdentityService.cs b/PostFundManagement.Application/Abstractions/Services/IIdentityService.cs new file mode 100644 index 0000000..bb4036e --- /dev/null +++ b/PostFundManagement.Application/Abstractions/Services/IIdentityService.cs @@ -0,0 +1,6 @@ +namespace PostFundManagement.Application.Abstractions.Services; + +public interface IIdentityService +{ + ValueTask UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default); +} diff --git a/PostFundManagement.Application/Abstractions/Services/IUserService.cs b/PostFundManagement.Application/Abstractions/Services/IUserService.cs new file mode 100644 index 0000000..3cd5bdc --- /dev/null +++ b/PostFundManagement.Application/Abstractions/Services/IUserService.cs @@ -0,0 +1,16 @@ +using PostFundManagement.Application.Services.Users; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Abstractions.Services; + +public interface IUserService +{ + ValueTask SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default); + + ValueTask> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default); + + ValueTask UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default); + + ValueTask> GetUserAsync(Guid userId, CancellationToken cancellationToken); +} diff --git a/PostFundManagement.Application/Extensions/General.cs b/PostFundManagement.Application/Extensions/General.cs index f12cedf..0d5e55e 100644 --- a/PostFundManagement.Application/Extensions/General.cs +++ b/PostFundManagement.Application/Extensions/General.cs @@ -1,19 +1,28 @@ -using Microsoft.Extensions.Caching.Hybrid; -using PostFundManagement.Application.Abstractions; +using PostFundManagement.Application.Abstractions; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Services.Communications; +using PostFundManagement.Application.Services.Evidence; +using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Application.Services.Users; using PostFundManagement.Domain.Abstractions; namespace PostFundManagement.Application.Extensions; public static class General { - public static IServiceCollection AddRegisterServices(this IServiceCollection services, IConfiguration configuration) + public static IServiceCollection AddRegisterServicesWithCaching(this IServiceCollection services, IConfiguration configuration) { - var serviceType = typeof(IService); + services.AddScoped(); + services.Decorate(); - var sharedImplementations = typeof(IApplication).Assembly.GetTypes() - .Where(t => serviceType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract); + services.AddScoped(); + services.Decorate(); - foreach (var sharedImplementation in sharedImplementations) services.AddScoped(sharedImplementation); + services.AddScoped(); + services.Decorate(); + + services.AddScoped(); + services.Decorate(); services.AddStackExchangeRedisCache(options => options.Configuration = configuration.GetConnectionString("Redis")); @@ -27,6 +36,18 @@ public static class General return services; } + public static IServiceCollection AddSharedServices(this IServiceCollection services) + { + var serviceType = typeof(IService); + + var sharedImplementations = typeof(IApplication).Assembly.GetTypes() + .Where(t => serviceType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract); + + foreach (var sharedImplementation in sharedImplementations) services.AddScoped(sharedImplementation); + + return services; + } + public static Guid GetUserId(this HttpContext context) => (Guid)context.Items[Domain.Extensions.Constants.UserIdItemKey]!; public static string GetUserEmail(this HttpContext context) => (string)context.Items[Domain.Extensions.Constants.EmailtemKey]!; diff --git a/PostFundManagement.Application/Filters/ActiveUserFilter.cs b/PostFundManagement.Application/Filters/ActiveUserFilter.cs index db49dce..feba9b0 100644 --- a/PostFundManagement.Application/Filters/ActiveUserFilter.cs +++ b/PostFundManagement.Application/Filters/ActiveUserFilter.cs @@ -1,10 +1,10 @@ -using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Application.Abstractions.Services; using static PostFundManagement.Application.Extensions.General; using static PostFundManagement.Domain.Extensions.Constants; namespace PostFundManagement.Application.Filters; -public sealed class ActiveUserFilter(IdentityService identityService) : IEndpointFilter +public sealed class ActiveUserFilter(IIdentityService identityService) : IEndpointFilter { public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) { diff --git a/PostFundManagement.Application/PostFundManagement.Application.csproj b/PostFundManagement.Application/PostFundManagement.Application.csproj index b027ade..b6d027c 100644 --- a/PostFundManagement.Application/PostFundManagement.Application.csproj +++ b/PostFundManagement.Application/PostFundManagement.Application.csproj @@ -26,6 +26,7 @@ + diff --git a/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs b/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs new file mode 100644 index 0000000..611b8b5 --- /dev/null +++ b/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs @@ -0,0 +1,22 @@ +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Services.Communications; + +public sealed class CommunicationsCacheService(CommunicationsService service, HybridCache cache) : ICommunicationsService +{ + public async ValueTask> GetApplicantInviteAsync(Guid userId, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getapplicantinvite-{userId}").Value, + async cancel => await service.GetApplicantInviteAsync(userId, cancellationToken)))); + + public async ValueTask> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getinvites-{pagination.Page}-{pagination.PageSize}").Value, + async cancel => await service.GetInvitesAsync(pagination, cancellationToken)))); + + public async ValueTask> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) => + await service.SendInviteAsync(request, userId, cancellationToken); +} diff --git a/PostFundManagement.Application/Services/Communications/CommunicationsService.cs b/PostFundManagement.Application/Services/Communications/CommunicationsService.cs index 93476fa..237bf7f 100644 --- a/PostFundManagement.Application/Services/Communications/CommunicationsService.cs +++ b/PostFundManagement.Application/Services/Communications/CommunicationsService.cs @@ -1,4 +1,5 @@ -using PostFundManagement.Domain; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; @@ -7,7 +8,7 @@ using PostFundManagement.Infrastructure.Database; namespace PostFundManagement.Application.Services.Communications; -public sealed class CommunicationsService(IDbContextFactory contextFactory) : IService +public sealed class CommunicationsService(IDbContextFactory contextFactory) : ICommunicationsService { public async ValueTask> SendInviteAsync(InviteRequest request, Guid userId, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => diff --git a/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs b/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs new file mode 100644 index 0000000..90644e6 --- /dev/null +++ b/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs @@ -0,0 +1,54 @@ +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Services.Evidence; + +public sealed class EvidenceCacheService(EvidenceService service, HybridCache cache) : IEvidenceService +{ + public async ValueTask CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) => + await service.CreateEvidenceAsync(userId, form, file, cancellationToken); + + public async ValueTask CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) => + await service.CreateIndicatorAsync(request, userId, cancellationToken); + + public async ValueTask CreateMilestoneAsync(CreateMilestoneRequest request, Guid userId, CancellationToken cancellationToken = default) => + await service.CreateMilestoneAsync(request, userId, cancellationToken); + + public async ValueTask> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getevidence-{evidenceId}").Value, + async cancel => await service.GetEvidenceAsync(evidenceId, cancellationToken)))); + + public async ValueTask> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getevidencefiles-{pagination.Page}-{pagination.PageSize}").Value, + async cancel => await service.GetEvidenceFilesAsync(pagination, cancellationToken)))); + + public async ValueTask> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getindicator-{indicatorId}").Value, + async cancel => await service.GetIndicatorAsync(indicatorId, cancellationToken)))); + + public async ValueTask> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getindicators-{pagination.Page}-{pagination.PageSize}").Value, + async cancel => await service.GetIndicatorsAsync(pagination, cancellationToken)))); + + public async ValueTask> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getmilestoneevidences-{milestoneIdHash}").Value, + async cancel => await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken)))); + + public async ValueTask> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + await cache.GetOrCreateAsync(HashService.ToMd5Hash($"getprojectevidences-{projectIdHash}").Value, + async cancel => await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken)))); + + public async ValueTask RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) => + await service.RecordIndicatorActualAmountAsync(indicatorIdHash, amount, userId, cancellationToken); + + public async ValueTask UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) => + await service.UpdateEvidenceAsync(request, userId, cancellationToken); +} diff --git a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs index 3d7bb18..998c6a9 100644 --- a/PostFundManagement.Application/Services/Evidence/EvidenceService.cs +++ b/PostFundManagement.Application/Services/Evidence/EvidenceService.cs @@ -1,4 +1,5 @@ -using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Services.Shared; using PostFundManagement.Domain; using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; @@ -9,7 +10,7 @@ using PostFundManagement.Infrastructure.Database; namespace PostFundManagement.Application.Services.Evidence; public sealed class EvidenceService(IDbContextFactory contextFactory, HashService hashService, - [FromKeyedServices(Constants.EvidenceBucketName)] IS3Service s3Service) : IService + [FromKeyedServices(Constants.EvidenceBucketName)] IS3Service s3Service) : IEvidenceService { public async ValueTask CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => @@ -217,8 +218,22 @@ public sealed class EvidenceService(IDbContextFactory cont return Result.Ok(evidences.Select(e => e.Map()).ToArray()); })); - public async Task UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public async ValueTask UpdateEvidenceAsync(UpdateEvidenceRequest request, Guid userId, CancellationToken cancellationToken = default) => + await Result.Try((Func>)(async () => + { + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + + if (!await context.Evidences.AnyAsync(e => e.Id == request.EvidenceId, cancellationToken)) + return Result.Fail(NotFoundError.New); + + var changedTotal = await context.Evidences.Where(e => e.Id == request.EvidenceId) + .ExecuteUpdateAsync(f => f + .SetProperty(f => f.Version, request.Version) + .SetProperty(f => f.Type, request.EvidenceType) + .SetProperty(f => f.Status, request.Status) + .SetProperty(f => f.UpdatedBy, userId) + .SetProperty(f => f.UpdatedAt, DateTime.UtcNow), cancellationToken); + + return Result.FailIf(changedTotal <= 0, UpdateError.New); + })); } diff --git a/PostFundManagement.Application/Services/Shared/IdentityCacheService.cs b/PostFundManagement.Application/Services/Shared/IdentityCacheService.cs new file mode 100644 index 0000000..d635950 --- /dev/null +++ b/PostFundManagement.Application/Services/Shared/IdentityCacheService.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Caching.Distributed; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Domain.Errors; + +namespace PostFundManagement.Application.Services.Shared; + +public sealed class IdentityCacheService(IdentityService service, IDistributedCache cache) : IIdentityService +{ + public async ValueTask UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) => + await Result.Try((Func>)(async () => + { + var cacheKey = HashService.ToMd5Hash($"userisauthorised-{userId}").Value; + + var cached = await cache.GetStringAsync(cacheKey); + + if (string.IsNullOrWhiteSpace(cached)) + { + var result = await service.UserIsAuthorisedAsync(userId, cancellationToken); ; + + if (result.IsFailed) return result; + + await cache.SetStringAsync(cacheKey, "true", cancellationToken); + + return Result.Ok(); + } + + return cached.Equals("true", StringComparison.OrdinalIgnoreCase) + ? Result.Ok() + : Result.Fail(NotFoundError.New); + })); +} diff --git a/PostFundManagement.Application/Services/Shared/IdentityService.cs b/PostFundManagement.Application/Services/Shared/IdentityService.cs index 5293eea..06e83a4 100644 --- a/PostFundManagement.Application/Services/Shared/IdentityService.cs +++ b/PostFundManagement.Application/Services/Shared/IdentityService.cs @@ -1,11 +1,11 @@ -using PostFundManagement.Domain; -using PostFundManagement.Domain.Abstractions; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Domain; using PostFundManagement.Domain.Errors; using PostFundManagement.Infrastructure.Database; namespace PostFundManagement.Application.Services.Shared; -public sealed class IdentityService(IDbContextFactory contextFactory) : IService +public sealed class IdentityService(IDbContextFactory contextFactory) : IIdentityService { public async ValueTask UserIsAuthorisedAsync(Guid userId, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => diff --git a/PostFundManagement.Application/Services/Users/UserCacheService.cs b/PostFundManagement.Application/Services/Users/UserCacheService.cs new file mode 100644 index 0000000..992bd29 --- /dev/null +++ b/PostFundManagement.Application/Services/Users/UserCacheService.cs @@ -0,0 +1,62 @@ +using Microsoft.Extensions.Caching.Distributed; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Services.Shared; +using PostFundManagement.Domain; +using PostFundManagement.Domain.Models; + +namespace PostFundManagement.Application.Services.Users; + +public sealed class UserCacheService(UserService service, IDistributedCache cache) : IUserService +{ + public async ValueTask> GetUserAsync(Guid userId, CancellationToken cancellationToken) => + await Result.Try((Func>>)(async () => + { + var cacheKey = HashService.ToMd5Hash($"getuser-{userId}").Value; + + var cached = await cache.GetStringAsync(cacheKey, cancellationToken); + + if(string.IsNullOrWhiteSpace(cached)) + { + var userResult = await service.GetUserAsync(userId, cancellationToken); + + if (userResult.IsFailed) return userResult; + + await cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(userResult.Value)); + + return userResult; + } + + var restored = JsonSerializer.Deserialize(cached)!; + + return Result.Ok(restored); + })); + + public async ValueTask> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) => + await Result.Try((Func>>)(async () => + { + var cacheKey = HashService.ToMd5Hash($"getusers-{pagination.Page}-{pagination.PageSize}-{request.Email}-{request.Status}").Value; + + var cached = await cache.GetStringAsync(cacheKey, cancellationToken); + + if (string.IsNullOrWhiteSpace(cached)) + { + var usersResult = await service.GetUsersAsync(pagination, request, cancellationToken); + + if (usersResult.IsFailed) return usersResult; + + await cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(usersResult.Value)); + + return usersResult; + } + + var restored = JsonSerializer.Deserialize(cached)!; + + return Result.Ok(restored); + })); + + public async ValueTask SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) => + await service.SyncUserAsync(userId, email, cancellationToken); + + public async ValueTask UpdateUserStatusAsync(Guid userId, ActivityStatus status, CancellationToken cancellationToken = default) => + await service.UpdateUserStatusAsync(userId, status, cancellationToken); +} diff --git a/PostFundManagement.Application/Services/Users/UserService.cs b/PostFundManagement.Application/Services/Users/UserService.cs index 6be2ad9..861f2ff 100644 --- a/PostFundManagement.Application/Services/Users/UserService.cs +++ b/PostFundManagement.Application/Services/Users/UserService.cs @@ -1,5 +1,5 @@ -using PostFundManagement.Domain; -using PostFundManagement.Domain.Abstractions; +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Domain; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Extensions; using PostFundManagement.Domain.Models; @@ -7,7 +7,7 @@ using PostFundManagement.Infrastructure.Database; namespace PostFundManagement.Application.Services.Users; -public sealed class UserService(IDbContextFactory contextFactory) : IService +public sealed class UserService(IDbContextFactory contextFactory) : IUserService { public async ValueTask SyncUserAsync(Guid userId, string email, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => diff --git a/PostFundManagement.Domain/PostFundManagement.Domain.csproj b/PostFundManagement.Domain/PostFundManagement.Domain.csproj index e85fa52..f16e0cb 100644 --- a/PostFundManagement.Domain/PostFundManagement.Domain.csproj +++ b/PostFundManagement.Domain/PostFundManagement.Domain.csproj @@ -15,6 +15,7 @@ + @@ -72,7 +73,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive