Files
shop-server/docs/superpowers/specs/2026-05-18-notifications-improvements-design.md
T

113 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Улучшение системы оповещений
**Дата:** 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` админ не получает дубликат