feat: improve notifications - fix auth code tg duplicate, double order notify, add PAID label, expand text, add deliveryFeeAdjusted event

This commit is contained in:
Kirill
2026-05-18 14:48:54 +05:00
parent 2f67c37502
commit d0b3c97803
17 changed files with 729 additions and 8 deletions
@@ -0,0 +1,112 @@
# Улучшение системы оповещений
**Дата:** 2026-05-18
## Проблемы
1. **Дублирование кода входа в Telegram** — настройка `authCodeDuplicate` не работает, т.к. `resolveAuthCodeTargets` импортирован, но не вызывается в диспетчере уведомлений.
2. **Двойное уведомление о новом заказе**`order:created` и `order:created:admin` оба проходят через `resolveAdminNotificationTargets('order:created')`, что даёт 2 одинаковых оповещения админу.
3. **Пропущен `PAID` в русских лейблах статусов** — в `telegram-templates.js` и `email-templates.js` нет ключа `PAID`.
4. **Текст оповещений слишком краткий** — нет подсказок о следующих действиях для пользователя и админа.
## Решения
### 1. Дублирование кода входа (гибридный подход)
- Письмо с кодом входа уходит **мгновенно** через прямой вызов `sendLoginCodeEmail` в `issueEmailCode` (без изменений).
- В `dispatchNotification` для `AUTH_CODE_REQUESTED` используется отдельный резолвер `resolveAuthCodeTargets` вместо общих `resolveUserNotificationTargets` / `resolveAdminNotificationTargets`.
- `resolveAuthCodeTargets` уже правильно реализован: отправляет email пользователю, а Telegram — только если `payload.isAdmin === true` и включена настройка `authCodeDuplicate`.
**Изменяемые файлы:**
- `server/src/index.js` — добавить условие в `dispatchNotification` для `AUTH_CODE_REQUESTED`
### 2. Двойное уведомление о новом заказе
- Удалить `ORDER_CREATED` из `adminEventFieldMap` в `preferences.js`.
- Админ получает уведомление о новом заказе только через событие `'order:created:admin'`.
**Изменяемые файлы:**
- `server/src/lib/notifications/preferences.js` — удалить `[ORDER_CREATED]: "newOrder"` из `adminEventFieldMap`
### 3. Добавление PAID в лейблы статусов
- `PAID: 'Оплачен'` в `telegram-templates.js` и `email-templates.js`.
**Изменяемые файлы:**
- `server/src/lib/notifications/templates/telegram-templates.js`
- `server/src/lib/notifications/templates/email-templates.js`
### 4. Расширение текста оповещений
#### 4a. Пользователь: Заказ создан
В событие `ORDER_CREATED` передаётся `deliveryType`:
- `deliveryType === 'pickup'`*"Ваш заказ №XXX успешно создан. Товаров: X | Сумма: XXX ₽. Ожидает оплаты."*
- `deliveryType === 'delivery'`*"Ваш заказ №XXX успешно создан. Товаров: X | Сумма: XXX ₽. Оплата будет доступна после уточнения стоимости доставки."*
**Изменяемые файлы:**
- `server/src/routes/user-orders.js` — добавить `deliveryType` в payload события `ORDER_CREATED`
- `server/src/lib/notifications/templates/telegram-templates.js` — обновить `renderOrderCreatedTg`
- `server/src/lib/notifications/templates/email-templates.js` — обновить `renderOrderCreatedEmail`
#### 4b. Новое событие: deliveryFeeAdjusted
При корректировке стоимости доставки (`PATCH /api/admin/orders/:id/delivery-fee`) отправлять пользователю уведомление:
- Текст: *"Стоимость доставки скорректирована. Ожидает оплаты."*
Событие: `'order:deliveryFeeAdjusted'` — добавляется в `NOTIFICATION_EVENTS`.
**Изменяемые файлы:**
- `shared/constants/notification-events.js` — добавить `DELIVERY_FEE_ADJUSTED`
- `shared/constants/notification-events.d.ts` — добавить `'order:deliveryFeeAdjusted'`
- `server/src/lib/notifications/preferences.js` — добавить `DELIVERY_FEE_ADJUSTED` в `userEventFieldMap`
- `server/src/routes/api/admin-orders.js` — emit `DELIVERY_FEE_ADJUSTED` после обновления
- `server/src/routes/user/notifications.js` — добавить поле в API
- `client/src/pages/me/ui/sections/NotificationsPage.tsx` — добавить переключатель
- `server/src/lib/notifications/templates/telegram-templates.js` — новый рендерер
- `server/src/lib/notifications/templates/email-templates.js` — новый рендерер
- `server/src/lib/notifications/channels/telegram-channel.js` — зарегистрировать шаблон
- `server/src/lib/notifications/channels/email-channel.js` — зарегистрировать шаблон
- `server/src/index.js` — подписаться на событие
Также нужно добавить миграцию Prisma для поля `deliveryFeeAdjusted` в `NotificationPreference`.
#### 4c. Админ: Новый заказ
В событие `'order:created:admin'` передаётся `deliveryType`:
- `deliveryType === 'delivery'` → добавить *"Скорректируйте стоимость доставки"*
- `deliveryType === 'pickup'` → как сейчас
**Изменяемые файлы:**
- `server/src/routes/user-orders.js` — добавить `deliveryType` в payload `'order:created:admin'`
- `server/src/lib/notifications/templates/telegram-templates.js` — обновить `renderAdminOrderCreatedTg`
- `server/src/lib/notifications/templates/email-templates.js` — обновить `renderAdminOrderCreatedEmail`
## Схема данных
### NotificationPreference (добавить поле)
```prisma
model NotificationPreference {
id String @id @default(cuid())
userId String @unique
globalEnabled Boolean @default(true)
orderCreated Boolean @default(true)
orderStatusChanged Boolean @default(true)
orderMessageReceived Boolean @default(true)
paymentStatusChanged Boolean @default(true)
deliveryFeeAdjusted Boolean @default(true) // НОВОЕ
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```
## Обработка ошибок
- Если при delivery-fee эмите не указан `userId` — событие не отправляется.
- Если рендерер не найден для события — `telegram-channel.js` и `email-channel.js` логируют warning (существующее поведение).
## Тестирование
- `server/src/lib/notifications/__tests__/preferences.test.js` — добавить тест для `resolveAuthCodeTargets` в контексте `dispatchNotification`
- Проверить, что после удаления `ORDER_CREATED` из `adminEventFieldMap` админ не получает дубликат