```
## Workflow (Как это работает)
### 1. Инициализация при загрузке страницы
```
User opens page
↓
useWebPush hook initialized
↓
Check browser support (Service Worker + Push API + Notification API)
↓
✅ Supported → Continue
↓
Fetch VAPID public key from server
↓
Register Service Worker (/sw.js)
↓
Check current subscription (PushManager.getSubscription())
↓
isSubscribed = (subscription !== null)
```
### 2. Подписка на уведомления (User action)
```
User clicks "Включить уведомления"
↓
Check permission:
- 'default' → Request permission (Notification.requestPermission())
- 'denied' → Show error toast
- 'granted' → Continue
↓
Create push subscription (PushManager.subscribe())
- userVisibleOnly: true
- applicationServerKey: VAPID key
↓
Serialize subscription (endpoint + keys.p256dh + keys.auth)
↓
Send to backend (POST /api/v1/notifications/push/subscribe/)
↓
Backend saves to WebPushDevice table
↓
✅ Show success toast
```
### 3. Получение push уведомления
```
Backend sends push notification (django-push-notifications)
↓
Browser receives push event (даже если вкладка закрыта)
↓
Service Worker intercepts 'push' event
↓
Parse payload (JSON.parse(event.data.text()))
↓
Show native notification (registration.showNotification())
↓
User clicks notification
↓
Service Worker 'notificationclick' event
↓
Focus or open window with notification URL
```
### 4. Обновление списка уведомлений
```
NotificationCenter component mounts
↓
useNotifications() hook called
↓
Fetch notifications from API (GET /api/v1/notifications/)
↓
Display in dropdown with unread badge
↓
User clicks notification
↓
Mark as read (POST /api/v1/notifications/{id}/mark_read/)
↓
Navigate to action_url
```
## Интеграция в существующие компоненты
### AppShell.tsx
**Изменения:**
- Импортирован `NotificationCenter`
- Заменены статичные кнопки Bell на ``
- Добавлено в desktop версию (header)
- Добавлено в mobile версию (нижняя панель)
**До:**
```tsx
```
**После:**
```tsx
```
### Providers.tsx
**Изменения:**
- Импортирован `Toaster` из Sonner
- Добавлен `` в провайдеры
```tsx
import { Toaster } from 'sonner';
```
## Тестирование
### Тестовый сценарий 1: Подписка на уведомления
1. Открыть приложение в браузере
2. Кликнуть на иконку Bell в header
3. Кликнуть на "Настройки" (⚙️)
4. Кликнуть "Включить" в разделе Push уведомления
5. Браузер покажет запрос разрешения → Разрешить
6. Toast: "Подписка на уведомления активирована"
7. В настройках должно быть "Включены" и кнопка "Отключить"
### Тестовый сценарий 2: Получение push уведомления
**Из Django shell:**
```python
from notifications.services import NotificationService
from notifications.models import Notification
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.get(username='testuser')
notification = Notification.objects.filter(recipient=user).first()
# Отправить push
count = NotificationService.send_web_push_notification(notification)
print(f"Отправлено: {count}")
```
**Проверки:**
1. Нативное уведомление должно появиться (даже если вкладка закрыта)
2. При клике должна открыться нужная страница
3. В NotificationCenter должно появиться уведомление
4. Badge должен увеличиться
### Тестовый сценарий 3: Toast уведомления
**В любом компоненте:**
```tsx
import { toast } from 'sonner';
```
**Проверки:**
1. Toast появляется в правом верхнем углу
2. Автоматически исчезает через 4 секунды
3. Можно закрыть свайпом вправо
4. При наведении пауза на таймере
### Тестовый сценарий 4: NotificationCenter UI
1. Открыть NotificationCenter
2. Должен показаться список уведомлений
3. Непрочитанные - с синим фоном и точкой
4. При клике на уведомление:
- Отмечается как прочитанное
- Badge уменьшается
- Происходит навигация (если есть URL)
5. "Прочитать все" - все уведомления становятся прочитанными
## Браузерная совместимость
### Web Push API
| Браузер | Desktop | Mobile | Примечания |
|---------|---------|--------|------------|
| Chrome | ✅ 50+ | ✅ 50+ | Полная поддержка |
| Firefox | ✅ 44+ | ✅ 48+ | Полная поддержка |
| Safari | ✅ 16+ | ❌ | iOS не поддерживает |
| Edge | ✅ 79+ | ✅ | На базе Chromium |
| Opera | ✅ 37+ | ✅ | На базе Chromium |
**Важно:** iOS Safari НЕ поддерживает Web Push (даже в iOS 16+).
- Для iOS нужно использовать нативное приложение + APNS
### Fallback стратегия
```tsx
const { isSupported, isSubscribed } = useWebPush();
if (!isSupported) {
// Показываем альтернативу
return Push уведомления не поддерживаются вашим браузером
;
}
```
## Production checklist
- [ ] **HTTPS обязателен** - Service Worker требует HTTPS
- [ ] **VAPID ключи** - проверить что есть в production settings
- [ ] **Service Worker scope** - проверить что sw.js доступен в корне
- [ ] **Тестирование на реальных устройствах**
- Desktop Chrome/Firefox
- Android Chrome
- Desktop Safari (если поддержка добавится)
- [ ] **Мониторинг ошибок** - логировать ошибки Service Worker
- [ ] **Rate limiting** - защита от спама push уведомлений
## Конфигурация
### Environment variables (Backend)
```bash
# В .env или settings.py
VAPID_PUBLIC_KEY=BMTitZy9r4ygYJBgGdaZuCkb7rwR7iHLJv...
VAPID_PRIVATE_KEY=
VAPID_ADMIN_EMAIL=admin@example.com
```
### Next.js конфигурация
**`next.config.ts`** - добавить headers для Service Worker (если нужно):
```typescript
async headers() {
return [
{
source: '/sw.js',
headers: [
{
key: 'Service-Worker-Allowed',
value: '/'
}
]
}
];
}
```
## Troubleshooting
### Проблема: Service Worker не регистрируется
**Возможные причины:**
- Приложение запущено на HTTP (нужен HTTPS или localhost)
- sw.js недоступен (404)
- Браузер не поддерживает Service Worker
**Решение:**
```bash
# Проверить доступность sw.js
curl http://localhost:3000/sw.js
# В консоли браузера
navigator.serviceWorker.getRegistrations().then(console.log)
```
### Проблема: Push подписка не создается
**Возможные причины:**
- Разрешение denied
- VAPID ключ неверный
- PushManager не поддерживается
**Решение:**
```javascript
// В консоли браузера
console.log('Permission:', Notification.permission);
console.log('PushManager supported:', 'PushManager' in window);
// Проверить VAPID ключ
fetch('/api/v1/notifications/push/vapid-key/')
.then(r => r.json())
.then(console.log);
```
### Проблема: Уведомления не приходят
**Возможные причины:**
- Подписка истекла (endpoint недействителен)
- Backend не может отправить (VAPID ошибка)
- Service Worker не активен
**Решение:**
```python
# Django shell - проверить активные устройства
from push_notifications.models import WebPushDevice
devices = WebPushDevice.objects.filter(user=user, active=True)
print(devices.count())
# Отправить тестовое уведомление
devices.send_message('{"title": "Test", "body": "Hello"}')
```
## Дальнейшие улучшения
### Функциональность
- [ ] **Фильтры уведомлений** - по категориям (заявки, сообщения, календарь)
- [ ] **Группировка** - по дате или типу
- [ ] **Действия в уведомлении** - прямо из push (approve/reject)
- [ ] **Звук** - настраиваемый звук для разных типов
- [ ] **Badge на иконке приложения** - счетчик непрочитанных
### UX/UI
- [ ] **Skeleton loading** - вместо "Загрузка..."
- [ ] **Infinite scroll** - для списка уведомлений
- [ ] **Поиск** - по уведомлениям
- [ ] **Настройки по типам** - включить/выключить для каждого типа
- [ ] **Темная тема** - поддержка dark mode
### Производительность
- [ ] **WebSocket real-time** - мгновенное обновление списка
- [ ] **Service Worker cache** - кеширование данных уведомлений
- [ ] **Prefetch** - предзагрузка страниц из action_url
### Аналитика
- [ ] **Отслеживание открытий** - сколько push уведомлений открыто
- [ ] **Conversion tracking** - какие уведомления ведут к действиям
- [ ] **A/B тестирование** - разные тексты/форматы
## Заключение
✅ **Система уведомлений полностью реализована:**
**Backend:**
- django-push-notifications 3.1.0
- WebPushDevice модель
- VAPID ключи настроены
- API endpoints готовы
**Frontend:**
- Service Worker для Web Push
- NotificationCenter UI компонент
- useWebPush React хук
- Sonner для toast уведомлений
- Интеграция в AppShell
**Результат:**
- Нативные push уведомления (работают даже когда вкладка закрыта)
- Красивый UI с badge и историей
- Настройки подписок
- Респонсивный дизайн
- TypeScript типизация
**Готово к использованию!** 🎉