# Исправление Push-уведомлений
## Проблема
Push-уведомления не работали по следующим причинам:
### 1. **Кнопка "Включить уведомления" не зависела от состояния разрешения**
#### До:
```tsx
{!pushEnabled && 'Notification' in window && (
)}
```
**Проблема:** Кнопка показывалась, даже если пользователь заблокировал уведомления (`Notification.permission === 'denied'`). Клик по ней приводил к ошибке, так как браузер не давал повторно запросить разрешение.
#### После:
```tsx
{!pushEnabled && 'Notification' in window && pushPermission !== 'denied' && (
)}
{pushPermission === 'denied' && (
Push-уведомления заблокированы. Разрешите их в настройках браузера.
)}
```
**Решение:**
- Кнопка показывается только когда `pushPermission === 'default'` (не запрашивалось)
- Если `pushPermission === 'denied'`, показывается предупреждение с инструкцией
### 2. **Service Worker мог не копироваться в dist при сборке**
#### До:
```typescript
// vite.config.ts
export default defineConfig({
plugins: [react()],
})
```
**Проблема:** Файл `public/service-worker.js` не копировался автоматически в `dist/` при сборке, что приводило к 404 ошибке при регистрации.
#### После:
```typescript
export default defineConfig({
plugins: [
react(),
{
name: 'copy-service-worker',
writeBundle() {
copyFileSync(
resolve(__dirname, 'public/service-worker.js'),
resolve(__dirname, 'dist/service-worker.js')
)
console.log('✅ Service worker скопирован в dist/')
}
}
],
})
```
**Решение:** Добавлен плагин Vite, который автоматически копирует `service-worker.js` в корень `dist/` при каждой сборке.
### 3. **Недостаточная диагностика ошибок**
#### До:
```typescript
console.error('Ошибка подключения Push-уведомлений:', error);
```
#### После:
```typescript
console.log('📝 Регистрируем Service Worker...');
const registration = await navigator.serviceWorker.register('/service-worker.js');
console.log('✅ Service Worker зарегистрирован:', registration);
console.log('📝 Получаем VAPID ключ...');
const vapidPublicKey = await getVapidKey();
console.log('✅ VAPID ключ получен:', vapidPublicKey.substring(0, 20) + '...');
console.log('📝 Создаём Push подписку...');
const subscription = await registration.pushManager.subscribe({...});
console.log('✅ Push подписка создана:', subscription.endpoint);
```
**Решение:** Добавлены подробные логи на каждом этапе подключения Push-уведомлений для быстрой диагностики проблем.
## Архитектура Push-уведомлений
### Frontend (`notificationService.ts`)
```
1. Notification.requestPermission() → Запрос разрешения
2. navigator.serviceWorker.register() → Регистрация SW
3. GET /api/notifications/vapid-key → Получение публичного ключа
4. registration.pushManager.subscribe() → Создание подписки
5. POST /api/notifications/subscribe-push → Отправка подписки на сервер
```
### Backend
```
1. GET /api/notifications/vapid-key → Возвращает VAPID_PUBLIC_KEY из .env
2. POST /api/notifications/subscribe-push → Сохраняет подписку в PushSubscription
3. Отправка уведомлений → webpush.sendNotification() для каждой подписки
```
### Service Worker (`public/service-worker.js`)
```javascript
self.addEventListener('push', (event) => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon || '/favicon.svg',
...
});
});
```
## Проверка работы
### 1. Проверка VAPID ключей
```bash
curl https://ospab.host:5000/api/notifications/vapid-key \
-H "Authorization: Bearer YOUR_TOKEN"
```
Должен вернуть:
```json
{
"success": true,
"publicKey": "BPtLNi3TY1ifUWTkgZrhxoEH6ihDgknFcgzc3xzFQg07PeuJ1TsJDQZqA32VqlxUo03g_mG0yKCKqADb4r5fnsM"
}
```
### 2. Проверка Service Worker
Откройте `https://ospab.host` → DevTools → Application → Service Workers
Должен быть зарегистрирован: `/service-worker.js` со статусом **Activated**
### 3. Проверка подписки
После нажатия "Включить уведомления" в консоли должны появиться:
```
📝 Запрашиваем разрешение на уведомления...
📝 Результат запроса разрешения: granted
📝 Регистрируем Service Worker...
✅ Service Worker зарегистрирован: ServiceWorkerRegistration {...}
📝 Ожидаем готовности Service Worker...
✅ Service Worker готов
📝 Получаем VAPID ключ...
✅ VAPID ключ получен: BPtLNi3TY1ifUWTk...
📝 Создаём Push подписку...
✅ Push подписка создана: https://fcm.googleapis.com/fcm/send/...
📝 Отправляем подписку на сервер...
✅ Push-уведомления успешно подключены
```
### 4. Проверка в базе данных
```sql
SELECT * FROM PushSubscription WHERE userId = YOUR_USER_ID;
```
Должна быть запись с endpoint, p256dh, auth.
### 5. Тестовая отправка
Можно создать тестовую отправку через backend:
```typescript
import { sendPushNotification } from './modules/notification/push.service';
await sendPushNotification(userId, {
title: 'Тестовое уведомление',
body: 'Push-уведомления работают!',
icon: '/logo192.png'
});
```
## Состояния Notification.permission
| Состояние | Описание | UI |
|-----------|----------|-----|
| `default` | Разрешение не запрашивалось | Показывается синяя кнопка "Включить уведомления" |
| `granted` | Разрешение получено | Кнопка скрыта, уведомления работают |
| `denied` | Пользователь заблокировал | Показывается красное предупреждение с инструкцией |
## Разблокировка в браузерах
### Chrome/Edge
1. Нажмите на иконку 🔒 (замок) слева от адресной строки
2. Найдите "Уведомления"
3. Выберите "Разрешить"
4. Обновите страницу
### Firefox
1. Откройте Настройки → Приватность и защита
2. Прокрутите до раздела "Разрешения"
3. Нажмите "Настройки" рядом с "Уведомления"
4. Найдите `ospab.host` и измените на "Разрешить"
### Safari
1. Safari → Настройки → Веб-сайты
2. Выберите "Уведомления"
3. Найдите `ospab.host` и выберите "Разрешить"
## Файлы изменены
1. ✅ `frontend/src/pages/dashboard/notifications.tsx`
- Добавлено состояние `pushPermission`
- Условный рендеринг кнопки/предупреждения
- Обновление состояния после запроса
2. ✅ `frontend/src/services/notificationService.ts`
- Добавлены подробные логи в `requestPushPermission()`
- Эмодзи-маркеры для быстрого поиска в консоли
3. ✅ `frontend/vite.config.ts`
- Плагин копирования `service-worker.js` в `dist/`
## Деплой
```bash
# Frontend
cd frontend
npm run build
# Скопируйте dist/ на production сервер
# Backend (если были изменения)
cd backend
npm run build
pm2 restart ospab-backend
```
## Возможные проблемы
### Service Worker не регистрируется
- **Проверка:** DevTools → Application → Service Workers
- **Причина:** Файл `service-worker.js` не доступен по адресу `https://ospab.host/service-worker.js`
- **Решение:** Убедитесь, что файл скопирован в корень `dist/` и доступен через nginx
### 403 Forbidden при запросе VAPID ключа
- **Проверка:** Network → `/api/notifications/vapid-key` → Response
- **Причина:** Не передаётся токен авторизации
- **Решение:** Проверьте, что в localStorage есть `access_token`
### Push-уведомления не приходят
- **Проверка:** Console → Ошибки от `webpush.sendNotification()`
- **Причина:** Неправильные VAPID ключи или подписка устарела
- **Решение:** Перегенерируйте VAPID ключи (`npx web-push generate-vapid-keys`) и переподпишитесь
### Подписка создаётся, но не сохраняется в БД
- **Проверка:** Console → Network → `/api/notifications/subscribe-push` → Response
- **Причина:** Ошибка на backend при сохранении в Prisma
- **Решение:** Проверьте логи backend (`pm2 logs ospab-backend`)
---
**Статус:** ✅ Исправлено и готово к тестированию
**Дата:** 2025-01-20