---
title: "API повідомлень"
description: "Повна документація API системи повідомлень платформи Ring з доставкою у режимі реального часу, push-сповіщеннями FCM та комплексним управлінням"
locale: "uk"
---
# API повідомлень

Платформа Ring надає комплексну систему повідомлень із **9 REST кінцевими точками** та доставкою через **Tunnel Protocol** (native WSS, SSE, poll). Система підтримує push-сповіщення FCM, налаштування користувачів, масові операції та детальну аналітику.

**Tunnel Protocol** — `publishToUserTunnel` на `notifications:unread`, клієнт `useRealtimeNotifications`. k8s: `/api/tunnel/ws`.

## 🏗️ Архітектура системи

### Потік повідомлень

```
Подія тригер → Сервіс повідомлень → Доставка у режимі реального часу → Налаштування користувачів → Push FCM → Аналітика
```

### Стратегія зберігання

- **Первинне**: PostgreSQL з оптимізованими запитами
- **Кешування**: Redis для зберігання сесій (необов'язково)
- **Реальний час**: TunnelHub WSS / SSE / poll через `publishToUserTunnel`
- **Push**: Firebase Cloud Messaging (FCM) інтеграція

## 📋 Довідка кінцевих точок API

### `GET /api/notifications`

Список повідомлень користувачів із розширеним фільтруванням та пагінацією.

#### Параметри

| Параметр | Тип | Обов'язковий | Опис |
|-----------|-----|--------------|------|
| `page` | number | Ні | Номер сторінки (за замовчуванням: 1) |
| `limit` | number | Ні | Елементів на сторінку (за замовчуванням: 20, макс: 100) |
| `status` | string | Ні | Фільтр за статусом: `unread`, `read`, `archived` |
| `type` | string | Ні | Фільтр за типом: `OPPORTUNITY`, `MESSAGE`, `ENTITY`, `SYSTEM`, `WALLET` |
| `priority` | string | Ні | Фільтр за пріоритетом: `low`, `normal`, `high`, `urgent` |
| `before` | string | Ні | ISO дата - показати повідомлення до цієї дати |
| `after` | string | Ні | ISO дата - показати повідомлення після цієї дати |

#### Приклад запиту

{`-H "Authorization: Bearer your-session-token"`}

#### Відповідь

{`"notifications": [
    {
      "id": "notif_123456",
      "userId": "user_789",
      "type": "OPPORTUNITY",
      "title": "Нова можливість партнерства",
      "message": "TechCorp шукає партнерів з розробки AI",
      "data": {
        "opportunityId": "opp_456",
        "entityId": "ent_123",
        "actionUrl": "/opportunities/opp_456"
      },
      "priority": "normal",
      "status": "unread",
      "createdAt": "2025-10-16T10:30:00Z",
      "readAt": null,
      "expiresAt": "2025-11-16T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 47,
    "totalPages": 5,
    "hasNext": true,
    "hasPrev": false
  },
  "unreadCount": 23
}`}

### `POST /api/notifications`

Створити нове повідомлення (використання переважно системою/адміном).

#### Тіло запиту

{`"userId": "user_789",
  "type": "SYSTEM",
  "title": "Обслуговування платформи",
  "message": "Заплановане обслуговування за 2 години",
  "priority": "high",
  "data": {
    "maintenanceStart": "2025-10-16T14:00:00Z",
    "expectedDuration": "30 хвилин"
  },
  "expiresAt": "2025-10-16T16:00:00Z"
}`}

#### Відповідь

{`"notification": {
    "id": "notif_123457",
    "userId": "user_789",
    "type": "SYSTEM",
    "title": "Обслуговування платформи",
    "message": "Заплановане обслуговування за 2 години",
    "priority": "high",
    "status": "unread",
    "createdAt": "2025-10-16T12:00:00Z",
    "expiresAt": "2025-10-16T16:00:00Z"
  },
  "delivered": true,
  "pushSent": true
}`}

### `PUT /api/notifications/{id}/read`

Позначити конкретне повідомлення як прочитане.

#### Приклад запиту

{`-H "Authorization: Bearer your-session-token"`}

#### Відповідь

{`"notification": {
    "id": "notif_123456",
    "status": "read",
    "readAt": "2025-10-16T12:30:00Z"
  },
  "unreadCount": 22
}`}

### `PUT /api/notifications/read-all`

Позначити всі повідомлення користувача як прочитані.

#### Параметри

| Параметр | Тип | Обов'язковий | Опис |
|-----------|-----|--------------|------|
| `type` | string | Ні | Позначити тільки конкретний тип як прочитаний |
| `before` | string | Ні | Позначити тільки повідомлення до цієї дати |

#### Приклад запиту

{`-H "Authorization: Bearer your-session-token"`}

#### Відповідь

{`"markedCount": 15,
  "unreadCount": 8
}`}

### `DELETE /api/notifications/{id}`

Видалити конкретне повідомлення.

#### Приклад запиту

{`-H "Authorization: Bearer your-session-token"`}

#### Відповідь

{`"deleted": true,
  "notificationId": "notif_123456"
}`}

### `GET /api/notifications/preferences`

Отримати поточні налаштування повідомлень користувача.

#### Відповідь

{`"preferences": {
    "emailNotifications": true,
    "pushNotifications": true,
    "smsNotifications": false,
    "types": {
      "OPPORTUNITY": {
        "enabled": true,
        "email": true,
        "push": true,
        "sms": false
      },
      "MESSAGE": {
        "enabled": true,
        "email": false,
        "push": true,
        "sms": false
      },
      "ENTITY": {
        "enabled": true,
        "email": true,
        "push": false,
        "sms": false
      },
      "SYSTEM": {
        "enabled": true,
        "email": true,
        "push": true,
        "sms": false
      },
      "WALLET": {
        "enabled": true,
        "email": true,
        "push": true,
        "sms": true
      }
    },
    "quietHours": {
      "enabled": false,
      "start": "22:00",
      "end": "08:00",
      "timezone": "UTC"
    },
    "frequency": "immediate"
  }
}`}

### `PUT /api/notifications/preferences`

Оновити налаштування повідомлень користувача.

#### Тіло запиту

{`"emailNotifications": true,
  "pushNotifications": false,
  "types": {
    "OPPORTUNITY": {
      "enabled": true,
      "email": true,
      "push": false
    },
    "MESSAGE": {
      "enabled": true,
      "email": false,
      "push": true
    }
  },
  "quietHours": {
    "enabled": true,
    "start": "23:00",
    "end": "07:00"
  }
}`}

#### Відповідь

{`"updated": true,
  "preferences": { /* оновлені налаштування */ }
}`}

### `POST /api/notifications/fcm/register`

Зареєструвати токен FCM для push-сповіщень.

#### Тіло запиту

{`"token": "fcm_token_from_firebase_sdk",
  "deviceType": "web",
  "deviceId": "unique-device-identifier",
  "userAgent": "Mozilla/5.0..."
}`}

#### Відповідь

{`"registered": true,
  "tokenId": "fcm_123456",
  "previousToken": "fcm_123455"
}`}

### `POST /api/notifications/bulk`

Надіслати масові повідомлення кільком користувачам (тільки адмін).

#### Тіло запиту

{`"userIds": ["user_123", "user_456", "user_789"],
  "notification": {
    "type": "SYSTEM",
    "title": "Важливе оновлення",
    "message": "Доступні нові функції",
    "priority": "normal",
    "data": {
      "actionUrl": "/updates"
    }
  },
  "sendPush": true,
  "sendEmail": false
}`}

#### Відповідь

{`"sent": true,
  "totalUsers": 3,
  "successful": 3,
  "failed": 0,
  "notificationIds": ["notif_123", "notif_124", "notif_125"]
}`}

### `GET /api/notifications/analytics`

Отримати аналітику повідомлень (тільки адмін).

#### Параметри

| Параметр | Тип | Обов'язковий | Опис |
|-----------|-----|--------------|------|
| `period` | string | Ні | Період часу: `day`, `week`, `month` (за замовчуванням: `week`) |
| `startDate` | string | Ні | ISO дата для власного діапазону |
| `endDate` | string | Ні | ISO дата для власного діапазону |

#### Відповідь

{`"period": "week",
  "totalSent": 1250,
  "totalRead": 980,
  "readRate": 78.4,
  "byType": {
    "OPPORTUNITY": { "sent": 450, "read": 380, "rate": 84.4 },
    "MESSAGE": { "sent": 320, "read": 280, "rate": 87.5 },
    "SYSTEM": { "sent": 180, "read": 120, "rate": 66.7 },
    "ENTITY": { "sent": 150, "read": 110, "rate": 73.3 },
    "WALLET": { "sent": 150, "read": 90, "rate": 60.0 }
  },
  "byPriority": {
    "urgent": { "sent": 50, "read": 48, "rate": 96.0 },
    "high": { "sent": 200, "read": 175, "rate": 87.5 },
    "normal": { "sent": 800, "read": 620, "rate": 77.5 },
    "low": { "sent": 200, "read": 137, "rate": 68.5 }
  },
  "deliveryStats": {
    "realTimeDelivered": 1200,
    "pushDelivered": 1100,
    "emailDelivered": 950
  }
}`}

## 🔄 Повідомлення у режимі реального часу

### Інтеграція Tunnel

Платформа Ring використовує **Tunnel Protocol** — `publishToUserTunnel` на `notifications:unread`, клієнт `useSync` / `useRealtimeNotifications`.

{`import { useRealtimeNotifications } from '@/hooks/use-realtime'

const { notifications, unreadCount, lastNotification } = useRealtimeNotifications()

// TunnelProvider керує WSS (k8s) або SSE (vercel) автоматично`}

### Фолбек Server-Sent Events (SSE)

Для середовищ без підтримки WebSocket:

// SSE з'єднання для повідомлень

{`const eventSource = new EventSource('/api/notifications/stream')

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data)
  if (data.type === 'notification') {
    handleNewNotification(data.notification)
  }
}`}

## 📱 Push-сповіщення

### Інтеграція FCM

Платформа Ring інтегрується з Firebase Cloud Messaging для кросплатформних push-сповіщень.

#### Налаштування клієнта

// Ініціалізація Firebase

{`import { initializeApp } from 'firebase/app'
import { getMessaging, getToken, onMessage } from 'firebase/messaging'

const app = initializeApp(firebaseConfig)
const messaging = getMessaging(app)

// Запит дозволу та отримання токена
const token = await getToken(messaging, {
  vapidKey: 'your-vapid-key'
})

// Реєстрація токена на Ring Platform
await fetch('/api/notifications/fcm/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token, deviceType: 'web' })
})

// Обробка вхідних повідомлень
onMessage(messaging, (payload) => {
  console.log('Отримано push-сповіщення:', payload)
  showNotification(payload.notification)
})`}

#### Service Worker

// public/firebase-messaging-sw.js

{`importScripts('https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js')
importScripts('https://www.gstatic.com/firebasejs/9.22.0/firebase-messaging-compat.js')

const app = firebase.initializeApp(firebaseConfig)
const messaging = firebase.messaging()

messaging.onBackgroundMessage((payload) => {
  console.log('Фонове повідомлення:', payload)

  self.registration.showNotification(payload.notification.title, {
    body: payload.notification.body,
    icon: '/icon-192x192.png',
    badge: '/badge-72x72.png',
    data: payload.data
  })
})`}

## 🎯 Типи повідомлень

### OPPORTUNITY

Тригериться коли:
- Нові можливості відповідають налаштуванням користувача
- Отримано заявки на можливості
- Наближаються дедлайни можливостей

{`"type": "OPPORTUNITY",
  "title": "Нова можливість відповідності",
  "message": "AI-підібрано: потрібен старший розробник React",
  "data": {
    "opportunityId": "opp_123",
    "matchScore": 95,
    "actionUrl": "/opportunities/opp_123"
  }
}`}

### MESSAGE

Тригериться коли:
- Отримано нові прямі повідомлення
- Оновлення групових розмов
- Повідомлення про згадки

{`"type": "MESSAGE",
  "title": "Нове повідомлення",
  "message": "John Doe: Давай обговоримо пропозицію проекту",
  "data": {
    "conversationId": "conv_456",
    "senderId": "user_789",
    "actionUrl": "/messages/conv_456"
  }
}`}

### ENTITY

Тригериться коли:
- Отримано запрошення сутностей
- Оновлення та оголошення сутностей
- Зміни статусу верифікації

{`"type": "ENTITY",
  "title": "Запрошення сутності",
  "message": "TechCorp запросив вас приєднатися до їх мережі",
  "data": {
    "entityId": "ent_123",
    "invitationId": "inv_456",
    "actionUrl": "/entities/ent_123"
  }
}`}

### SYSTEM

Для:
- Оголошення платформи
- Повідомлення про обслуговування
- Сповіщення безпеки
- Оновлення функцій

{`"type": "SYSTEM",
  "title": "Доступна нова функція",
  "message": "AI-підібрані можливості тепер у режимі онлайн!",
  "data": {
    "feature": "ai-matching",
    "actionUrl": "/features/ai-matching"
  }
}`}

### WALLET

Для:
- Підтвердження транзакцій
- Оновлення балансів
- Нагороди стейкінгу
- Квитанції платежів

{`"type": "WALLET",
  "title": "Отримано платіж",
  "message": "Отримано 500 токенів RING від завершеного проекту",
  "data": {
    "transactionId": "tx_123",
    "amount": "500",
    "currency": "RING",
    "actionUrl": "/wallet/transactions/tx_123"
  }
}`}

## 🔧 Приклади реалізації

### React Hook для повідомлень

// hooks/useNotifications.ts — використовуйте useRealtimeNotifications

{`import { useRealtimeNotifications } from '@/hooks/use-realtime'

export function useNotifications() {
  const {
    notifications,
    unreadCount,
    markAsRead,
    markAllAsRead,
    refresh
  } = useRealtimeNotifications()

  return { notifications, unreadCount, markAsRead, markAllAsRead, refresh }
}`}

### Компонент центру повідомлень

// components/NotificationCenter.tsx

{`import { useNotifications } from '@/hooks/useNotifications'
import { Bell, Check } from 'lucide-react'

export function NotificationCenter() {
  const { notifications, unreadCount, markAsRead } = useNotifications()

  return (
    
      
        
        Повідомлення
        {unreadCount > 0 && (
          
            {unreadCount}
          
        )}
      

      
        {notifications.map(notification => (
          
            
              
                {notification.title}
                
                  {notification.message}
                
                
                  {new Date(notification.createdAt).toLocaleString()}
                
              
              {notification.status === 'unread' && (
                 markAsRead(notification.id)}
                  className="ml-2 p-1 hover:bg-gray-100 rounded"
                >
                  
                
              )}
            
          
        ))}
      
    
  )
}`}

## 🚨 Обробка помилок

### Поширені відповіді про помилки

// Помилка аутентифікації

{`{
  "error": "Unauthorized",
  "message": "Необхідна аутентифікація",
  "statusCode": 401
}

// Помилка валідації
{
  "error": "ValidationError",
  "message": "Недійсні дані повідомлення",
  "details": {
    "type": "Недійсний тип повідомлення",
    "userId": "ID користувача обов'язковий"
  },
  "statusCode": 400
}

// Помилка обмеження швидкості
{
  "error": "RateLimitError",
  "message": "Забагато запитів",
  "retryAfter": 60,
  "statusCode": 429
}

// Серверна помилка
{
  "error": "InternalServerError",
  "message": "Не вдалося надіслати повідомлення",
  "requestId": "req_123456",
  "statusCode": 500
}`}

## 🔒 Заходи безпеки

### Аутентифікація
- Усі кінцеві точки вимагають дійсної аутентифікації сесії
- Адмін кінцеві точки вимагають ролі `ADMIN`
- FCM токени зашифровані та безпечно збережені

### Обмеження швидкості
- Стандартні користувачі: 100 запитів/хвилину
- Адмін користувачі: 500 запитів/хвилину
- Масові операції: 10 операцій/хвилину

### Валідація даних
- Усі вхідні дані валідуються за допомогою схем Zod
- HTML контент санітізується для запобігання XSS
- Завантаження файлів сканується на віруси та шкідливе ПЗ

### Конфіденційність
- Повідомлення поважають налаштування користувачів
- Ніякої конфіденційної інформації у корисних даних push-сповіщень
- GDPR-сумісна обробка даних

## 📊 Моніторинг та аналітика

### Метрики у режимі реального часу

// Відстеження подій повідомлень

{`import { trackEvent } from '@/lib/analytics'
import { useRealtimeNotifications } from '@/hooks/use-realtime'

const { lastNotification } = useRealtimeNotifications()

trackEvent('notification_received', {
  type: lastNotification?.type,
  deliveryMethod: 'tunnel'
})

trackEvent('notification_delivered', {
  deliveryTime: Date.now() - startTime,
  method: 'tunnel'
})`}

## 🎛️ Конфігурація

### Змінні середовища

FCM (клієнт + Admin). Див. також [Push notifications (FCM)](/docs/features/push-notifications-fcm.md) (EN).

{`NEXT_PUBLIC_FIREBASE_PROJECT_ID=…
NEXT_PUBLIC_FIREBASE_VAPID_KEY=…   # Console → Cloud Messaging → Web Push certificates
AUTH_FIREBASE_PROJECT_ID=…
AUTH_FIREBASE_CLIENT_EMAIL=…
AUTH_FIREBASE_PRIVATE_KEY="…"
DB_BACKEND_MODE=k8s-postgres-fcm
# Staged (not read yet): VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT`}

### Схема бази даних

{`CREATE TABLE notifications (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES users(id),
  type VARCHAR(50) NOT NULL,
  title VARCHAR(255) NOT NULL,
  message TEXT NOT NULL,
  data JSONB,
  priority VARCHAR(20) DEFAULT 'normal',
  status VARCHAR(20) DEFAULT 'unread',
  created_at TIMESTAMP DEFAULT NOW(),
  read_at TIMESTAMP,
  expires_at TIMESTAMP
);

-- Налаштування користувачів
CREATE TABLE notification_preferences (
  user_id UUID PRIMARY KEY REFERENCES users(id),
  email_notifications BOOLEAN DEFAULT true,
  push_notifications BOOLEAN DEFAULT true,
  preferences JSONB DEFAULT '{}',
  updated_at TIMESTAMP DEFAULT NOW()
);`}

---

*Система повідомлень платформи Ring забезпечує надійність корпоративного рівня з доставкою у режимі реального часу, комплексною аналітикою та кросплатформною сумісністю.*
