NotificationTemplates
Este documento descreve todas as operações disponíveis para o agregado NotificationTemplates e seus recursos, seguindo os padrões de Domain-Driven Design (DDD) e Command Query Responsibility Segregation (CQRS).
Índice
- NotificationTemplates
- Índice
- Visão Geral
- Arquitetura
- Fluxo de Envio de Notificações
- Validação de Variáveis
- Commands (Comandos)
- Queries (Consultas)
- NotificationTemplateType
- Tipos e Enums
- Sistema de Prioridades
- Placeholders
- NotificationService
- Exemplos de Uso
- Observações Importantes
Visão Geral
O sistema de NotificationTemplates permite gerenciar templates de notificações enviadas aos usuários através de diferentes canais (Email, WhatsApp, SMS).
Características principais:
- Multi-canal: Suporta Email, WhatsApp e SMS
- Tipado: Templates são associados a um
NotificationTemplateTypeque define as variáveis obrigatórias - Validação de Variáveis: Sistema valida se todas as variáveis obrigatórias foram preenchidas antes do envio
- Contextual: Templates podem ser genéricos ou específicos para JobTasks
- Priorizado: Sistema de prioridades para múltiplos templates
- Dinâmico: Suporta placeholders para personalização
Arquitetura
O sistema é composto por três entidades principais:
NotificationTemplateType (Tipo)
├── Reason: NotificationTemplateReason
├── Variables: List<NotificationTemplateVariable>
│ ├── Variable 1 (isRequired: true)
│ ├── Variable 2 (isRequired: false, defaultValue: "...")
│ └── ...
└── Templates: List<NotificationTemplate>
├── Template Email
├── Template WhatsApp
└── Template SMS
NotificationTemplateType (Tipo de Template)
Define o tipo/motivo da notificação e quais variáveis estão disponíveis ou são obrigatórias.
| Campo | Tipo | Descrição |
|---|---|---|
Id |
Guid | Identificador único |
Name |
string | Nome do tipo (ex: "Serviço Disponível") |
Reason |
NotificationTemplateReason | Enum que define o motivo |
Description |
string? | Descrição do tipo |
Variables |
List | Lista de variáveis disponíveis |
Templates |
List | Templates associados a este tipo |
NotificationTemplate (Template)
Define o conteúdo da notificação para um canal específico.
| Campo | Tipo | Descrição |
|---|---|---|
Id |
Guid | Identificador único |
Name |
string | Nome do template |
Subject |
string | Assunto da notificação |
Body |
string | Corpo da mensagem (com placeholders) |
Channel |
NotificationTemplateChannel | Canal (Email, WhatsApp, SMS) |
NotificationTemplateTypeId |
Guid | FK para o tipo |
JobTaskId |
Guid? | FK para tarefa específica (null = genérico) |
IsActive |
bool | Status ativo/inativo |
Priority |
int | Prioridade (maior = preferência) |
IsGeneric |
bool | Calculado: !JobTaskId.HasValue |
NotificationTemplateVariable (Variável)
Define uma variável que pode ser usada nos templates de um tipo.
| Campo | Tipo | Descrição |
|---|---|---|
Id |
Guid | Identificador único |
Name |
string | Nome da variável (ex: "UrlAction") |
Description |
string? | Descrição da variável |
IsRequired |
bool | Se é obrigatória |
DefaultValue |
string? | Valor padrão (se não fornecido) |
NotificationTemplateTypeId |
Guid | FK para o tipo |
Fluxo de Envio de Notificações
1. Busca templates pelo Reason do tipo
└── GetActiveTemplatesByReasonAsync(reason, jobTaskId)
2. Para cada template encontrado:
├── 2.1 Aplica valores default das variáveis
│ ApplyDefaultVariables(template, providedVariables)
│
├── 2.2 Valida variáveis obrigatórias
│ template.ValidateVariablesForSend(variables)
│ └── Se faltar variável → RuleViolationDomainException
│
├── 2.3 Processa o template (substitui placeholders)
│ ProcessTemplateAsync(template, contextObject, variables)
│
└── 2.4 Envia a notificação pelo canal apropriado
SendNotificationByChannel(channel, email, phone, ...)
Validação de Variáveis
O sistema valida automaticamente se todas as variáveis obrigatórias foram fornecidas antes de enviar a notificação.
Como funciona:
-
No momento da criação do template: Verifica se o
BodyouSubjectcontém os placeholders das variáveis obrigatórias do tipo. -
No momento do envio: Verifica se o dicionário de variáveis contém todas as variáveis obrigatórias que estão presentes no template.
Exceções:
-
Criação/Atualização: Se uma variável obrigatória não estiver no template:
RuleViolationDomainException: Template body/subject is missing required variables: UrlAction -
Envio: Se uma variável obrigatória não for fornecida:
RuleViolationDomainException: Missing required variables for sending notification: UrlAction
Valores Default:
Variáveis com DefaultValue definido não geram erro mesmo se não forem passadas no dicionário, pois o sistema aplica o valor default automaticamente.
Commands (Comandos)
1. Criação de Template (CreateNotificationTemplate)
Contrato: CreateNotificationTemplateCommand
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
Name |
string | Sim | Nome do template |
Subject |
string | Sim | Assunto (máx 500 chars) |
Body |
string | Sim | Corpo da mensagem |
Channel |
NotificationTemplateChannel | Sim | Canal de envio |
NotificationTemplateTypeId |
Guid | Sim | ID do tipo de template |
JobTaskId |
Guid? | Não | ID da tarefa (null = genérico) |
IsActive |
bool | Sim | Status (padrão: true) |
Priority |
int | Sim | Prioridade (padrão: 0) |
Observation |
string? | Não | Observações |
Author |
string? | Não | Autor da operação |
Validações: - Body deve conter todas as variáveis obrigatórias do tipo - Channel deve ser válido - NotificationTemplateTypeId deve existir
Exemplo:
{
"name": "Serviço Disponível - WhatsApp",
"subject": "Serviço Disponível",
"body": "Olá {{ProfessionalUser.Name}}! Novo serviço disponível. Acesse: {{UrlAction}}",
"channel": "WhatsApp",
"notificationTemplateTypeId": "123e4567-e89b-12d3-a456-426614174000",
"jobTaskId": null,
"isActive": true,
"priority": 0,
"author": "admin@santamao.com"
}
2. Atualização de Template (UpdateNotificationTemplate)
Contrato: UpdateNotificationTemplateCommand
Mesmos campos da criação, com adição de:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
Id |
Guid | Sim | ID do template |
Validações: - Template deve existir - Body deve conter todas as variáveis obrigatórias do novo tipo
3. Exclusão de Template (DeleteNotificationTemplate)
Contrato: DeleteNotificationTemplateCommand
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
Id |
Guid | Sim | ID do template |
Recomendação: Use UpdateNotificationTemplate com IsActive = false para manter histórico.
Queries (Consultas)
1. Buscar Template por ID (GetNotificationTemplateById)
Contrato: GetNotificationTemplateByIdQuery
Retorno: Inclui dados do tipo e suas variáveis.
{
"id": "...",
"name": "Serviço Disponível - WhatsApp",
"subject": "Serviço Disponível",
"body": "Olá {{ProfessionalUser.Name}}! Novo serviço disponível. Acesse: {{UrlAction}}",
"channel": "WhatsApp",
"notificationTemplateType": {
"id": "...",
"name": "Serviço Disponível",
"reason": "ServiceAvailable",
"variables": [
{ "name": "UrlAction", "description": "URL para aceitar", "isRequired": true },
{ "name": "ProfessionalUser.Name", "description": "Nome do profissional", "isRequired": false }
]
},
"jobTaskId": null,
"isActive": true,
"priority": 0,
"isGeneric": true
}
2. Pesquisar Templates (SearchNotificationTemplates)
Contrato: SearchNotificationTemplatesQuery
| Campo | Tipo | Descrição |
|---|---|---|
Channel |
NotificationTemplateChannel? | Filtrar por canal |
Reason |
NotificationTemplateReason? | Filtrar por motivo (via tipo) |
JobTaskId |
Guid? | Filtrar por tarefa |
IsActive |
bool? | Filtrar por status |
IsGeneric |
bool? | Filtrar genéricos/específicos |
NotificationTemplateType
Estrutura
Cada tipo define:
- Reason: O motivo/contexto da notificação
- Variables: Lista de variáveis disponíveis para os templates deste tipo
Variáveis do Tipo
Variáveis são definidas no tipo e ficam disponíveis para todos os templates associados.
Exemplo de Tipo: ServiceAvailable
var type = new NotificationTemplateType(
name: "Serviço Disponível",
reason: NotificationTemplateReason.ServiceAvailable,
description: "Notificação enviada ao profissional quando um novo serviço está disponível"
);
// Variável obrigatória
type.AddVariable("UrlAction", "URL para aceitar o serviço", isRequired: true);
// Variáveis opcionais
type.AddVariable("ProfessionalUser.Name", "Nome do profissional", isRequired: false);
type.AddVariable("JobTask.Name", "Nome da tarefa", isRequired: false);
type.AddVariable("Order.StartDate", "Data de início do serviço", isRequired: false);
Tipos Padrão do Sistema
| Tipo | Reason | Variáveis Obrigatórias |
|---|---|---|
| Serviço Disponível | ServiceAvailable | UrlAction |
| Serviço Confirmado | ServiceConfirmed | UrlAction |
| Pagamento Pendente | PaymentPending | PaymentUrl, Amount |
Tipos e Enums
NotificationTemplateChannel
public enum NotificationTemplateChannel
{
Unknown, // Desconhecido
Email, // Email
WhatsApp, // WhatsApp
Sms // SMS
}
NotificationTemplateReason
public enum NotificationTemplateReason
{
// Serviços
ServiceAvailable,
ServiceUnavailable,
ServiceConfirmed,
ServiceCancelled,
ServiceCompleted,
ServiceInProgress,
// Agendamentos
AppointmentScheduled,
AppointmentReminder,
AppointmentConfirmed,
AppointmentCancelled,
AppointmentRescheduled,
// Pagamentos
PaymentApproved,
PaymentPending,
PaymentRejected,
PaymentRefunded,
// Usuários
WelcomeProfessional,
WelcomeClient,
ProfileApproved,
ProfileRejected,
PasswordReset,
EmailConfirmation,
// Sistema
SystemAlert,
MaintenanceNotice,
NewFeature
}
Sistema de Prioridades
Hierarquia de Seleção
- Template Específico de Alta Prioridade (JobTaskId != null, Priority alto)
- Template Específico de Baixa Prioridade (JobTaskId != null, Priority baixo)
- Template Genérico de Alta Prioridade (JobTaskId = null, Priority alto)
- Template Genérico de Baixa Prioridade (JobTaskId = null, Priority baixo)
Valores Recomendados
| Faixa | Uso |
|---|---|
| 0-10 | Templates padrão |
| 11-50 | Templates sazonais |
| 51-100 | Templates especiais/urgentes |
Placeholders
Sintaxe
Use duplas chaves: {{NomeDaVariavel}}
Formatos suportados:
{{VariavelSimples}} → Variável fornecida no dicionário
{{Objeto.Propriedade}} → Navegação em objetos do contexto
{VariavelSimples} → Formato alternativo (chave simples)
{Objeto.Propriedade} → Formato alternativo com navegação
Placeholders por Contexto
Usuários:
- {{User.Name}} - Nome do usuário
- {{User.Email}} - Email do usuário
- {{User.Phone}} - Telefone do usuário
Profissionais:
- {{ProfessionalUser.Name}} - Nome do profissional
- {{ProfessionalUser.Email}} - Email do profissional
- {{ProfessionalUser.Phone}} - Telefone do profissional
Pedidos:
- {{Order.Id}} - ID do pedido
- {{Order.StartDate}} - Data de início
Variáveis Extras (passadas no dicionário):
- {{UrlAction}} - URL de ação
- {{PaymentUrl}} - URL de pagamento
- {{Amount}} - Valor formatado
- {{ExpiresAt}} - Data de expiração
NotificationService
Métodos Genéricos
// Enviar notificação para qualquer destinatário
Task SendNotificationAsync<T>(
NotificationTemplateReason reason,
T contextObject,
Email? email,
Phone? phone,
Dictionary<string, string> variables,
Guid? jobTaskId = null,
Guid? correlationId = null,
CancellationToken cancellationToken = default);
// Enviar notificação para User
Task SendNotificationToUserAsync<T>(
NotificationTemplateReason reason,
User user,
T contextObject,
Dictionary<string, string> variables,
Guid? jobTaskId = null,
Guid? correlationId = null,
CancellationToken cancellationToken = default);
// Enviar notificação para ProfessionalUser
Task SendNotificationToProfessionalAsync<T>(
NotificationTemplateReason reason,
ProfessionalUser professionalUser,
T contextObject,
Dictionary<string, string> variables,
Guid? jobTaskId = null,
Guid? correlationId = null,
CancellationToken cancellationToken = default);
Métodos Específicos
// Notifica profissional sobre serviço disponível
Task SendServiceAvailableNotificationAsync(
ProfessionalUser professionalUser,
Guid correlationId,
CancellationToken cancellationToken);
// Variáveis: UrlAction (gerada automaticamente)
// Notifica usuário que profissional aceitou
Task SendResponseAcceptedNotificationAsync(
Order order,
Guid correlationId,
CancellationToken cancellationToken);
// Variáveis: UrlAction (gerada automaticamente)
// Notifica usuário sobre pagamento pendente
Task SendPaymentCreatedNotificationAsync(
Order order,
Guid correlationId,
CancellationToken cancellationToken);
// Variáveis: PaymentUrl, Amount, ExpiresAt (extraídas do OrderPayment)
Exemplos de Uso
Criando um Tipo com Variáveis
var type = new NotificationTemplateType(
name: "Pagamento Pendente",
reason: NotificationTemplateReason.PaymentPending,
description: "Notificação de pagamento pendente"
);
type.AddVariable("PaymentUrl", "URL para pagamento", isRequired: true);
type.AddVariable("Amount", "Valor do pagamento", isRequired: true);
type.AddVariable("ExpiresAt", "Data de expiração", isRequired: false);
type.AddVariable("User.Name", "Nome do usuário", isRequired: false);
Criando Templates para o Tipo
// Email
new NotificationTemplate(
name: "Pagamento Pendente - Email",
subject: "Pagamento pendente - Pedido #{{Order.Id}}",
body: @"Olá {{User.Name}},
Seu pagamento de {{Amount}} está pendente.
Válido até: {{ExpiresAt}}
Acesse: {{PaymentUrl}}",
channel: NotificationTemplateChannel.Email,
templateType: type
);
// WhatsApp
new NotificationTemplate(
name: "Pagamento Pendente - WhatsApp",
subject: "Pagamento Pendente",
body: "Pagamento pendente de {{Amount}}. Acesse: {{PaymentUrl}}",
channel: NotificationTemplateChannel.WhatsApp,
templateType: type
);
Enviando Notificação Genérica
await _notificationService.SendNotificationToUserAsync(
reason: NotificationTemplateReason.PaymentPending,
user: order.User,
contextObject: order,
variables: new Dictionary<string, string>
{
{ "PaymentUrl", "https://pay.example.com/123" },
{ "Amount", "R$ 150,00" },
{ "ExpiresAt", "15/01/2026 23:59" }
},
correlationId: Guid.CreateVersion7(),
cancellationToken: cancellationToken);
Observações Importantes
1. Validação de Variáveis
- Obrigatórias: Devem estar no template E serem passadas no envio
- Default: Se não passadas, usa o valor default
- Opcionais: Não geram erro se ausentes
2. Templates Genéricos vs Específicos
- Genéricos (
JobTaskId = null): Fallback para todas as tarefas - Específicos: Sobrescrevem genéricos para uma tarefa específica
3. Multi-Canal
| Canal | Características |
|---|---|
| HTML, links, imagens | |
| Emojis, Markdown limitado | |
| SMS | 160 chars, texto puro |
4. Melhores Práticas
- Defina variáveis obrigatórias apenas para dados essenciais
- Use valores default para variáveis comuns
- Teste templates antes de ativar
- Mantenha templates inativos para histórico
5. Performance
- Templates carregados por demanda
- Cache de templates ativos recomendado
- Índices em Channel, Reason, JobTaskId
6. Conformidade
- Email: Inclua link de unsubscribe (LGPD/GDPR)
- WhatsApp: Respeite janela de 24h
- SMS: Evite horários inadequados