# Улучшение системы оповещений

**Дата:** 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` админ не получает дубликат
