Notification Service
SMS, Email, Push, Telegram — шаблоны, приоритеты, дедупликация, multi-channel delivery.
Notification Service
Bounded Context: Notification & Messaging
Владелец данных: Template, DeliveryLog
Технологии: NestJS (Bun 1.3+), Drizzle ORM, PostgreSQL, ConnectRPC, RabbitMQ, BullMQ, Redis
Ответственность
Notification Service — единая точка отправки уведомлений клиентам и операторам по всем каналам. Аналог встроенных модулей уведомлений в Splynx и Hydra Billing, но вынесен в отдельный сервис для масштабирования и переиспользования.
- Multi-Channel: SMS (SMPP/HTTP), Email (SMTP/SendGrid), Push (FCM/APNs), Telegram Bot, Webhook. Выбор канала — по предпочтениям клиента или приоритету события.
- Templates: Шаблонизация сообщений (Handlebars / Nunjucks), локализация (i18next). Шаблоны управляются через CRM-интерфейс без деплоя.
- Prioritization: Критичные (мгновенно) → обычные (< 5 мин) → batch (1 раз в час). Dunning-уведомления всегда
HIGH. - Deduplication: Защита от спама — одинаковое уведомление одному клиенту не отправляется дважды за configurable window (по умолчанию 1 час).
- Delivery Tracking: Статус доставки (sent/delivered/failed/read), retry при ошибке провайдера, fallback на альтернативный канал.
- Compliance: Уважение opt-out предпочтений клиента (GDPR/ФЗ-152), тихие часы (не отправлять SMS с 22:00 до 08:00).
Типичные триггеры уведомлений (ISP)
| Событие | Канал | Приоритет | Шаблон |
|---|---|---|---|
| Баланс < 0 (dunning soft) | SMS + Email | HIGH | dunning_soft_warning |
| Блокировка (dunning hard) | SMS | HIGH | dunning_hard_block |
| Оплата получена | SMS + Push | NORMAL | payment_received |
| Подключение завершено | Email + SMS | NORMAL | welcome_connected |
| Смена тарифа | LOW | tariff_changed | |
| Выезд монтажника запланирован | SMS | HIGH | fsm_scheduled |
| Счёт сформирован | LOW | invoice_issued | |
| Массовая авария | SMS + Push + Telegram | CRITICAL | mass_outage |
Архитектура
ConnectRPC API
service NotificationService {
rpc Send(NotificationRequest) returns (NotificationResponse);
rpc ListTemplates(ListTemplatesRequest) returns (ListTemplatesResponse);
rpc GetDeliveryStatus(GetDeliveryStatusRequest) returns (GetDeliveryStatusResponse);
}| Метод | RBAC | Описание |
|---|---|---|
Send | isp-operator+ | Ручная отправка (для CRM) |
ListTemplates | isp-viewer+ | Список доступных шаблонов |
GetDeliveryStatus | isp-viewer+ | Статус конкретной доставки |
Входящие команды (RabbitMQ)
Exchange: notification.commands (Direct)
| Routing Key | Queue | Описание |
|---|---|---|
send.sms | notification.q.sms | Отправка SMS |
send.email | notification.q.email | Отправка Email |
send.push | notification.q.push | Отправка Push |
send.telegram | notification.q.telegram | Отправка в Telegram |
Также потребляет доменные события для автоматических уведомлений:
| Exchange | Routing Key | Queue | Шаблон |
|---|---|---|---|
customer.events | customer.created | notification.q.customer-created | welcome_sms |
billing.events | payment.received | notification.q.payment-received | payment_confirmation |
billing.events | balance.negative | notification.q.balance-negative | low_balance_warning |
billing.events | dunning.stage_changed | notification.q.dunning | service_restricted / service_blocked |
inventory.events | resource.exhausted | notification.q.resource-alert | ops_capacity_alert (→ операторам) |
Шаблоны
// src/notification/templates/payment-confirmation.ts
export const paymentConfirmation: NotificationTemplate = {
id: 'payment_confirmation',
channel: 'sms',
body: 'Оплата {{amount}} {{currency}} зачислена на л/с {{accountNumber}}. Баланс: {{balance}}',
};Шаблоны хранятся в PostgreSQL, кэшируются в памяти. Поддерживают переменные через map<string, string> variables в SendNotificationCommand.
Приоритеты и очереди
| Priority | SLA | Примеры | BullMQ Queue |
|---|---|---|---|
CRITICAL | < 10 сек | CoA failure, mass outage | notification_critical |
HIGH | < 1 мин | Dunning block, payment received | notification_high |
NORMAL | < 5 мин | Welcome, tariff change | notification_normal |
LOW | < 1 час (batch) | Промо, newsletter | notification_batch |
Дедупликация
Защита от повторной отправки одного и того же сообщения:
CREATE TABLE delivery_log (
id BIGSERIAL PRIMARY KEY,
customer_id UUID NOT NULL,
template_id TEXT NOT NULL,
channel TEXT NOT NULL,
dedup_key TEXT NOT NULL, -- hash(customer_id + template_id + period)
status TEXT NOT NULL, -- pending / sent / delivered / failed
provider_id TEXT, -- ID от SMS-шлюза
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
delivered_at TIMESTAMPTZ,
UNIQUE (dedup_key)
);Правило: один template_id для одного customer_id не чаще 1 раза в dedup_window (по умолчанию 1 час).
Background Jobs (BullMQ)
| Job | Расписание | Описание |
|---|---|---|
notification.batch_send | Каждый час | Отправка LOW-priority уведомлений пакетом |
notification.retry_failed | Каждые 5 мин | Retry неудачных доставок (max 3 attempts) |
notification.cleanup | Ежедневно | Удаление старых delivery_log (> 90 дней) |
Ссылки:
- Protobuf-контракт: notification/v1/notification_service.proto
- Слой BSS: BSS Layer