feat(templates): add service language template management

Add normalized service and template catalogs, scoped administration, migration, validation, and regression coverage.

Ref: IT-1601
This commit is contained in:
2026-10-17 22:02:43 +03:00
parent 36810dc5f1
commit 81654c0d33
73 changed files with 4061 additions and 820 deletions
@@ -12,15 +12,18 @@ internal sealed class DevelopmentDataSeeder
private readonly IEmailChannelRepository _channels;
private readonly IEmailTemplateRepository _templates;
private readonly INotificationServiceRepository _services;
private readonly ILogger<DevelopmentDataSeeder> _logger;
public DevelopmentDataSeeder(
IEmailChannelRepository channels,
IEmailTemplateRepository templates,
INotificationServiceRepository services,
ILogger<DevelopmentDataSeeder> logger)
{
_channels = channels;
_templates = templates;
_services = services;
_logger = logger;
}
@@ -30,6 +33,7 @@ internal sealed class DevelopmentDataSeeder
throw new InvalidOperationException("Development seed service name is not configured.");
await SeedMailpitChannelAsync(serviceName, cancellationToken);
await SeedServiceAsync(serviceName, cancellationToken);
foreach (EmailTemplate template in CreateTemplates(serviceName))
{
@@ -51,6 +55,18 @@ internal sealed class DevelopmentDataSeeder
}
}
private async Task SeedServiceAsync(string serviceName, CancellationToken ct)
{
var services = await _services.GetAllAsync(ct);
var service = services.SingleOrDefault(s => s.Name == serviceName);
if (service?.Languages.Any(l => l.Code == DefaultLanguageCode) == true)
return;
var isNew = service is null;
service ??= new NotificationServiceInfo { Name = serviceName };
service.Languages = [..service.Languages, new ServiceLanguageInfo { Code = DefaultLanguageCode }];
await _services.SaveAsync(service, isNew, ct);
}
private async Task SeedMailpitChannelAsync(string serviceName, CancellationToken cancellationToken)
{
IReadOnlyList<EmailChannel> existingChannels = await _channels.GetByServiceAsync(