feat: add RabbitMQ worker, contracts, usage UI in channels screen

- Add HrynCo.NotificationService.Contracts project with SendEmailMessage and NotificationResultMessage
- Add SendEmailConsumer (RabbitMQ worker) with reply-to pattern via CorrelationContext.ReplyTo
- Add SendEmailHandler owning SMTP send + usage increment as business logic
- Add GetChannelUsageSummaryHandler with single DB query via navigation property
- Merge usage stats inline into channels list (daily/monthly with progress bars)
- Refactor AdminChannelsController.Index to use GetChannelUsageSummaryQuery
- Add RabbitMQ service to docker-compose files
- Remove dead AdminChannelUsageController, ChannelUsageViewModel, ChannelUsageSummary

Ref: IT-628

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anatolii Grynchuk
2026-05-02 14:00:58 +03:00
parent 395f5573a1
commit b0996833bc
29 changed files with 569 additions and 78 deletions
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HrynCo.RabbitMq" />
</ItemGroup>
</Project>
@@ -0,0 +1,14 @@
namespace HrynCo.NotificationService.Contracts.Messages;
public record NotificationResultData
{
public required string ServiceName { get; init; }
public required string RecipientEmail { get; init; }
public required string TemplateKey { get; init; }
public required DateTimeOffset Timestamp { get; init; }
/// <summary>Null when delivery succeeded; contains error details on failure.</summary>
public string? ErrorMessage { get; init; }
public bool IsSuccess => ErrorMessage is null;
}
@@ -0,0 +1,9 @@
namespace HrynCo.NotificationService.Contracts.Messages;
using Hrynco.RabbitMq;
public record NotificationResultMessage : IRabbitMqMessage<NotificationResultData>
{
public CorrelationContext CorrelationContext { get; set; } = null!;
public NotificationResultData Data { get; set; } = null!;
}
@@ -0,0 +1,9 @@
namespace HrynCo.NotificationService.Contracts.Messages;
using Hrynco.RabbitMq;
public record SendEmailMessage : IRabbitMqMessage<SendEmailMessageData>
{
public CorrelationContext CorrelationContext { get; set; } = default!;
public SendEmailMessageData Data { get; set; } = default!;
}
@@ -0,0 +1,11 @@
namespace HrynCo.NotificationService.Contracts.Messages;
public record SendEmailMessageData
{
public required string ServiceName { get; init; }
public required string TemplateKey { get; init; }
public required string RecipientEmail { get; init; }
public required string RecipientName { get; init; }
public required IReadOnlyDictionary<string, string> Variables { get; init; }
public string? LanguageCode { get; init; }
}