Documentation

    Концепції, цінність і типові сценарії

    Ласкаво просимо до Ring
    Швидкий довідник
    Початок роботи
    Передумови
    Встановлення
    Валідація першого успіху
    Наступні кроки
    Функції
    Магазин
    SubscriptionConductor
    PaymentConductor
    Інтеграція платежів
    Інтеграція WayForPay
    Web3 Гаманець
    Реферальні коди (Refcodes)
    NFT Exhibition Marketplace
    Система Стейкінга Токенів
    Сутності
    Можливості
    Повідомлення
    Модуль Новин - Цифровий Газетний Досвід
    Блоги учасників
    Система Резервування Імен Користувачів
    Науковий редактор
    Notifications
    Push-сповіщення через FCM (Ring)
    Email AI-CRM
    Протокол Tunnel
    Authentication
    Безпека та відповідність
    Система локалей
    Мобільний Досвід
    Паттерни Оптимізації Продуктивності
    Приклади
    Швидкий старт
    Білий лейбл
    Інтеграція Web3
    Реальні приклади
    Кастомізація
    Швидкий старт — ваш перший клон Ring
    Повний посібник налаштування
    Брендування
    Теми
    Функції
    Локалізація
    Налаштування токеноміки
    Інтеграція платіжних шлюзів
    Еталонні деплої Ring
    Web3
    Token launch jurisdictions
    Інтеграції
    Ethereum гаманці (Wagmi v3)
    Розгортання
    Self-hosted розгортання
    Vercel
    Docker
    Конфігурація Середовища
    Моніторинг та аналітика
    Оптимізація продуктивності
    Резервне копіювання та відновлення
    Архітектура
    Data Model
    Security
    Real Time
    Архітектура PaymentConductor
    Розробка
    Ring MCP Server

    Швидкий вхід (CTO · аудитори · агенти)

    Вітаємо — місія та аудиторії
    Швидкий довідник
    Початок роботи
    Архітектура та Auth.js
    Режими бекенду та БД (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Деплой (Docker · k8s)
    Безпека та відповідність
    ringdom.org — база LegioX
    Код — ліцензія MIT (GitHub)

    Documentation

    Концепції, цінність і типові сценарії

    Ласкаво просимо до Ring
    Швидкий довідник
    Початок роботи
    Передумови
    Встановлення
    Валідація першого успіху
    Наступні кроки
    Функції
    Магазин
    SubscriptionConductor
    PaymentConductor
    Інтеграція платежів
    Інтеграція WayForPay
    Web3 Гаманець
    Реферальні коди (Refcodes)
    NFT Exhibition Marketplace
    Система Стейкінга Токенів
    Сутності
    Можливості
    Повідомлення
    Модуль Новин - Цифровий Газетний Досвід
    Блоги учасників
    Система Резервування Імен Користувачів
    Науковий редактор
    Notifications
    Push-сповіщення через FCM (Ring)
    Email AI-CRM
    Протокол Tunnel
    Authentication
    Безпека та відповідність
    Система локалей
    Мобільний Досвід
    Паттерни Оптимізації Продуктивності
    Приклади
    Швидкий старт
    Білий лейбл
    Інтеграція Web3
    Реальні приклади
    Кастомізація
    Швидкий старт — ваш перший клон Ring
    Повний посібник налаштування
    Брендування
    Теми
    Функції
    Локалізація
    Налаштування токеноміки
    Інтеграція платіжних шлюзів
    Еталонні деплої Ring
    Web3
    Token launch jurisdictions
    Інтеграції
    Ethereum гаманці (Wagmi v3)
    Розгортання
    Self-hosted розгортання
    Vercel
    Docker
    Конфігурація Середовища
    Моніторинг та аналітика
    Оптимізація продуктивності
    Резервне копіювання та відновлення
    Архітектура
    Data Model
    Security
    Real Time
    Архітектура PaymentConductor
    Розробка
    Ring MCP Server

    Швидкий вхід (CTO · аудитори · агенти)

    Вітаємо — місія та аудиторії
    Швидкий довідник
    Початок роботи
    Архітектура та Auth.js
    Режими бекенду та БД (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Деплой (Docker · k8s)
    Безпека та відповідність
    ringdom.org — база LegioX
    Код — ліцензія MIT (GitHub)

    Documentation

    Концепції, цінність і типові сценарії

    Ласкаво просимо до Ring
    Швидкий довідник
    Початок роботи
    Передумови
    Встановлення
    Валідація першого успіху
    Наступні кроки
    Функції
    Магазин
    SubscriptionConductor
    PaymentConductor
    Інтеграція платежів
    Інтеграція WayForPay
    Web3 Гаманець
    Реферальні коди (Refcodes)
    NFT Exhibition Marketplace
    Система Стейкінга Токенів
    Сутності
    Можливості
    Повідомлення
    Модуль Новин - Цифровий Газетний Досвід
    Блоги учасників
    Система Резервування Імен Користувачів
    Науковий редактор
    Notifications
    Push-сповіщення через FCM (Ring)
    Email AI-CRM
    Протокол Tunnel
    Authentication
    Безпека та відповідність
    Система локалей
    Мобільний Досвід
    Паттерни Оптимізації Продуктивності
    Приклади
    Швидкий старт
    Білий лейбл
    Інтеграція Web3
    Реальні приклади
    Кастомізація
    Швидкий старт — ваш перший клон Ring
    Повний посібник налаштування
    Брендування
    Теми
    Функції
    Локалізація
    Налаштування токеноміки
    Інтеграція платіжних шлюзів
    Еталонні деплої Ring
    Web3
    Token launch jurisdictions
    Інтеграції
    Ethereum гаманці (Wagmi v3)
    Розгортання
    Self-hosted розгортання
    Vercel
    Docker
    Конфігурація Середовища
    Моніторинг та аналітика
    Оптимізація продуктивності
    Резервне копіювання та відновлення
    Архітектура
    Data Model
    Security
    Real Time
    Архітектура PaymentConductor
    Розробка
    Ring MCP Server

    Швидкий вхід (CTO · аудитори · агенти)

    Вітаємо — місія та аудиторії
    Швидкий довідник
    Початок роботи
    Архітектура та Auth.js
    Режими бекенду та БД (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Деплой (Docker · k8s)
    Безпека та відповідність
    ringdom.org — база LegioX
    Код — ліцензія MIT (GitHub)
    1. Документація
    2. /Функції
    3. /Push-сповіщення через FCM (Ring)

    5 хв прослуховування

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Документація
    2. /Функції
    3. /Push-сповіщення через FCM (Ring)

    5 хв прослуховування

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Документація
    2. /Функції
    3. /Push-сповіщення через FCM (Ring)

    5 хв прослуховування

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    Push-сповіщення через FCM (Ring)

    Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.

    Огляд: логіка FCM у Ring

    «Ring-powered» FCM — це єдина, незалежна від бекенду схема:

    • Сховище токенів як джерело істини — Таблиця (або колекція) fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.
    • Один рядок на пристрій і користувача — Складне унікальне обмеження по (user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.
    • React-додаток → Server Action — Основний шлях для браузера та React Native web — Server Action upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.
    • Інші клієнти → API — Мобільні додатки або зовнішні сервіси викликають POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).
    • Життєвий цикл у даних — У кожному рядку зберігаються status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.
    • Режим бекенду — Сховище токенів не прив’язане до конкретного бекенду. BackendSelector направляє запити по DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає.
    Реєстрація та доставка FCM у Ring

    Передумови

    • Аутентифікація — Виконано вхід (сесія Auth.js). Реєстрація токена завжди прив’язана до аутентифікованого користувача; сервер не довіряє ідентифікатору користувача від клієнта.
    • Web Push (браузер) — HTTPS (або localhost під час розробки), підтримка Web Push у браузері, зареєстрований service worker та Firebase client SDK. Файл service worker зазвичай доступний за /firebase-messaging-sw.js.
    • API-клієнти — Діюча сесія (cookie або Bearer) та той самий контракт тіла запиту (token, deviceFingerprint, deviceInfo).

    React-додаток: шлях через Server Action

    Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.

    Основний шлях

    React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.

    1. 1

      Отримайте стабільний device fingerprint

      Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.

    2. 2

      Запросіть дозвіл і отримайте FCM-токен

      У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.

    3. 3

      Викличте Server Action для реєстрації токена

      Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().

    4. 4

      Обробка оновлення токена

      Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.

    Приклад: реєстрація та оновлення токена в клієнтському компоненті.

    Інші клієнти: API

    Мобільні додатки та інші клієнти без React реєструють токени через той самий контракт по HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Тіло запиту:

    • token (string, обов’язково) — FCM registration token з клієнтського SDK.
    • deviceFingerprint (string, обов’язково) — Стабільний ідентифікатор пристрою (наприклад UUID у local storage). Не більше 128 символів; лише літери, цифри, дефіс та підкреслення.
    • deviceInfo (object, необов’язково) — Довільні метадані пристрою (наприклад platform, userAgent).

    Аутентифікація: Обов’язкова (session cookie або Bearer). Сервер використовує ідентифікатор аутентифікованого користувача; не передавайте userId у тілі.

    Відповіді:

    • 200 — { "success": true }
    • 400 — Помилка валідації (наприклад відсутній або невірний deviceFingerprint)
    • 401 — Не аутентифіковано
    • 429 — Перевищено ліміт запитів (заголовок Retry-After)
    • 500 — Помилка сервера
    Ліміт запитів

    Цей endpoint обмежений по частоті на користувача (наприклад 10 запитів на хвилину). Використовуйте Server Action з React-додатків, щоб не витрачати ліміт API.

    Приклад з cURL (підставте cookie сесії або Bearer згідно з вашою налаштуванням auth):

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

    Налаштування розділені так, щоб на клієнт потрапляли лише публічні та безпечні значення.

    Безпека

    Приватний ключ VAPID та облікові дані Firebase service account не повинні потрапляти на клієнт. Зберігайте їх лише на сервері.

    ПризначенняЗмінніДе
    Клієнт (браузер / додаток)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYБезпечні для клієнта; використовуються Firebase client SDK та service worker
    Сервер (сховище токенів, відправка FCM)FIREBASE_SERVICE_ACCOUNT_* або шлях до JSON сервісного акаунта; DB_BACKEND_MODE (наприклад k8s-postgres-fcm, firebase-full, supabase-fcm)Лише сервер; використовуються BackendSelector та Firebase Admin SDK

    Зняття реєстрації та вихід

    При виході або вимкненні push користувачем:

    • Браузер / React — Викличте deleteToken(messaging) з Firebase client SDK, потім зніміть реєстрацію на сервері: DELETE /api/notifications/fcm/register з тілом { "deviceFingerprint": "same-uuid-as-register" }. Ідемпотентно; можна викликати навіть якщо запис уже видалено або інвалідовано.
    • Інші клієнти — Той самий запит DELETE з тим самим deviceFingerprint, що й при реєстрації.

    Сервер позначає рядок як status: 'invalid' і встановлює invalidatedAt; доставка на цей токен припиняється.

    Усунення несправностей

    ПроблемаПричинаДія
    Permission denied або токен не отриманоКористувач відхилив сповіщення або дозвіл ще не запитувалиЗапросіть дозвіл перед викликом getToken(); обробляйте permission === 'denied' в інтерфейсі
    429 при реєстраціїПеревищено ліміт запитівВикористовуйте Server Action з React; для API-клієнтів дотримуйтесь Retry-After та зменшіть частоту реєстрації
    Невірний deviceFingerprintПомилка валідаціїРядок довжиною 1–128 символів: лише літери, цифри, дефіс та підкреслення
    401 при реєстраціїНе аутентифікованоПереконайтесь, що надсилається діюча сесія (cookie або Bearer); не передавайте userId у тілі

    Див. також

    • Сповіщення — Типи сповіщень, канали та налаштування
    • Схема та міграції для fcm_tokens (наприклад data/schema.sql, data/migrations/fcm_jsonb_schema.sql) у вашому клоні Ring
    • Truth lens FCM-фахівця (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправки

    Push-сповіщення через FCM (Ring)

    Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.

    Огляд: логіка FCM у Ring

    «Ring-powered» FCM — це єдина, незалежна від бекенду схема:

    • Сховище токенів як джерело істини — Таблиця (або колекція) fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.
    • Один рядок на пристрій і користувача — Складне унікальне обмеження по (user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.
    • React-додаток → Server Action — Основний шлях для браузера та React Native web — Server Action upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.
    • Інші клієнти → API — Мобільні додатки або зовнішні сервіси викликають POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).
    • Життєвий цикл у даних — У кожному рядку зберігаються status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.
    • Режим бекенду — Сховище токенів не прив’язане до конкретного бекенду. BackendSelector направляє запити по DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає.
    Реєстрація та доставка FCM у Ring

    Передумови

    • Аутентифікація — Виконано вхід (сесія Auth.js). Реєстрація токена завжди прив’язана до аутентифікованого користувача; сервер не довіряє ідентифікатору користувача від клієнта.
    • Web Push (браузер) — HTTPS (або localhost під час розробки), підтримка Web Push у браузері, зареєстрований service worker та Firebase client SDK. Файл service worker зазвичай доступний за /firebase-messaging-sw.js.
    • API-клієнти — Діюча сесія (cookie або Bearer) та той самий контракт тіла запиту (token, deviceFingerprint, deviceInfo).

    React-додаток: шлях через Server Action

    Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.

    Основний шлях

    React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.

    1. 1

      Отримайте стабільний device fingerprint

      Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.

    2. 2

      Запросіть дозвіл і отримайте FCM-токен

      У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.

    3. 3

      Викличте Server Action для реєстрації токена

      Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().

    4. 4

      Обробка оновлення токена

      Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.

    Приклад: реєстрація та оновлення токена в клієнтському компоненті.

    Інші клієнти: API

    Мобільні додатки та інші клієнти без React реєструють токени через той самий контракт по HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Тіло запиту:

    • token (string, обов’язково) — FCM registration token з клієнтського SDK.
    • deviceFingerprint (string, обов’язково) — Стабільний ідентифікатор пристрою (наприклад UUID у local storage). Не більше 128 символів; лише літери, цифри, дефіс та підкреслення.
    • deviceInfo (object, необов’язково) — Довільні метадані пристрою (наприклад platform, userAgent).

    Аутентифікація: Обов’язкова (session cookie або Bearer). Сервер використовує ідентифікатор аутентифікованого користувача; не передавайте userId у тілі.

    Відповіді:

    • 200 — { "success": true }
    • 400 — Помилка валідації (наприклад відсутній або невірний deviceFingerprint)
    • 401 — Не аутентифіковано
    • 429 — Перевищено ліміт запитів (заголовок Retry-After)
    • 500 — Помилка сервера
    Ліміт запитів

    Цей endpoint обмежений по частоті на користувача (наприклад 10 запитів на хвилину). Використовуйте Server Action з React-додатків, щоб не витрачати ліміт API.

    Приклад з cURL (підставте cookie сесії або Bearer згідно з вашою налаштуванням auth):

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

    Налаштування розділені так, щоб на клієнт потрапляли лише публічні та безпечні значення.

    Безпека

    Приватний ключ VAPID та облікові дані Firebase service account не повинні потрапляти на клієнт. Зберігайте їх лише на сервері.

    ПризначенняЗмінніДе
    Клієнт (браузер / додаток)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYБезпечні для клієнта; використовуються Firebase client SDK та service worker
    Сервер (сховище токенів, відправка FCM)FIREBASE_SERVICE_ACCOUNT_* або шлях до JSON сервісного акаунта; DB_BACKEND_MODE (наприклад k8s-postgres-fcm, firebase-full, supabase-fcm)Лише сервер; використовуються BackendSelector та Firebase Admin SDK

    Зняття реєстрації та вихід

    При виході або вимкненні push користувачем:

    • Браузер / React — Викличте deleteToken(messaging) з Firebase client SDK, потім зніміть реєстрацію на сервері: DELETE /api/notifications/fcm/register з тілом { "deviceFingerprint": "same-uuid-as-register" }. Ідемпотентно; можна викликати навіть якщо запис уже видалено або інвалідовано.
    • Інші клієнти — Той самий запит DELETE з тим самим deviceFingerprint, що й при реєстрації.

    Сервер позначає рядок як status: 'invalid' і встановлює invalidatedAt; доставка на цей токен припиняється.

    Усунення несправностей

    ПроблемаПричинаДія
    Permission denied або токен не отриманоКористувач відхилив сповіщення або дозвіл ще не запитувалиЗапросіть дозвіл перед викликом getToken(); обробляйте permission === 'denied' в інтерфейсі
    429 при реєстраціїПеревищено ліміт запитівВикористовуйте Server Action з React; для API-клієнтів дотримуйтесь Retry-After та зменшіть частоту реєстрації
    Невірний deviceFingerprintПомилка валідаціїРядок довжиною 1–128 символів: лише літери, цифри, дефіс та підкреслення
    401 при реєстраціїНе аутентифікованоПереконайтесь, що надсилається діюча сесія (cookie або Bearer); не передавайте userId у тілі

    Див. також

    • Сповіщення — Типи сповіщень, канали та налаштування
    • Схема та міграції для fcm_tokens (наприклад data/schema.sql, data/migrations/fcm_jsonb_schema.sql) у вашому клоні Ring
    • Truth lens FCM-фахівця (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправки

    Push-сповіщення через FCM (Ring)

    Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.

    Огляд: логіка FCM у Ring

    «Ring-powered» FCM — це єдина, незалежна від бекенду схема:

    • Сховище токенів як джерело істини — Таблиця (або колекція) fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.
    • Один рядок на пристрій і користувача — Складне унікальне обмеження по (user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.
    • React-додаток → Server Action — Основний шлях для браузера та React Native web — Server Action upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.
    • Інші клієнти → API — Мобільні додатки або зовнішні сервіси викликають POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).
    • Життєвий цикл у даних — У кожному рядку зберігаються status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.
    • Режим бекенду — Сховище токенів не прив’язане до конкретного бекенду. BackendSelector направляє запити по DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає.
    Реєстрація та доставка FCM у Ring

    Передумови

    • Аутентифікація — Виконано вхід (сесія Auth.js). Реєстрація токена завжди прив’язана до аутентифікованого користувача; сервер не довіряє ідентифікатору користувача від клієнта.
    • Web Push (браузер) — HTTPS (або localhost під час розробки), підтримка Web Push у браузері, зареєстрований service worker та Firebase client SDK. Файл service worker зазвичай доступний за /firebase-messaging-sw.js.
    • API-клієнти — Діюча сесія (cookie або Bearer) та той самий контракт тіла запиту (token, deviceFingerprint, deviceInfo).

    React-додаток: шлях через Server Action

    Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.

    Основний шлях

    React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.

    1. 1

      Отримайте стабільний device fingerprint

      Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.

    2. 2

      Запросіть дозвіл і отримайте FCM-токен

      У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.

    3. 3

      Викличте Server Action для реєстрації токена

      Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().

    4. 4

      Обробка оновлення токена

      Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.

    Приклад: реєстрація та оновлення токена в клієнтському компоненті.

    Інші клієнти: API

    Мобільні додатки та інші клієнти без React реєструють токени через той самий контракт по HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Тіло запиту:

    • token (string, обов’язково) — FCM registration token з клієнтського SDK.
    • deviceFingerprint (string, обов’язково) — Стабільний ідентифікатор пристрою (наприклад UUID у local storage). Не більше 128 символів; лише літери, цифри, дефіс та підкреслення.
    • deviceInfo (object, необов’язково) — Довільні метадані пристрою (наприклад platform, userAgent).

    Аутентифікація: Обов’язкова (session cookie або Bearer). Сервер використовує ідентифікатор аутентифікованого користувача; не передавайте userId у тілі.

    Відповіді:

    • 200 — { "success": true }
    • 400 — Помилка валідації (наприклад відсутній або невірний deviceFingerprint)
    • 401 — Не аутентифіковано
    • 429 — Перевищено ліміт запитів (заголовок Retry-After)
    • 500 — Помилка сервера
    Ліміт запитів

    Цей endpoint обмежений по частоті на користувача (наприклад 10 запитів на хвилину). Використовуйте Server Action з React-додатків, щоб не витрачати ліміт API.

    Приклад з cURL (підставте cookie сесії або Bearer згідно з вашою налаштуванням auth):

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

    Налаштування розділені так, щоб на клієнт потрапляли лише публічні та безпечні значення.

    Безпека

    Приватний ключ VAPID та облікові дані Firebase service account не повинні потрапляти на клієнт. Зберігайте їх лише на сервері.

    ПризначенняЗмінніДе
    Клієнт (браузер / додаток)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYБезпечні для клієнта; використовуються Firebase client SDK та service worker
    Сервер (сховище токенів, відправка FCM)FIREBASE_SERVICE_ACCOUNT_* або шлях до JSON сервісного акаунта; DB_BACKEND_MODE (наприклад k8s-postgres-fcm, firebase-full, supabase-fcm)Лише сервер; використовуються BackendSelector та Firebase Admin SDK

    Зняття реєстрації та вихід

    При виході або вимкненні push користувачем:

    • Браузер / React — Викличте deleteToken(messaging) з Firebase client SDK, потім зніміть реєстрацію на сервері: DELETE /api/notifications/fcm/register з тілом { "deviceFingerprint": "same-uuid-as-register" }. Ідемпотентно; можна викликати навіть якщо запис уже видалено або інвалідовано.
    • Інші клієнти — Той самий запит DELETE з тим самим deviceFingerprint, що й при реєстрації.

    Сервер позначає рядок як status: 'invalid' і встановлює invalidatedAt; доставка на цей токен припиняється.

    Усунення несправностей

    ПроблемаПричинаДія
    Permission denied або токен не отриманоКористувач відхилив сповіщення або дозвіл ще не запитувалиЗапросіть дозвіл перед викликом getToken(); обробляйте permission === 'denied' в інтерфейсі
    429 при реєстраціїПеревищено ліміт запитівВикористовуйте Server Action з React; для API-клієнтів дотримуйтесь Retry-After та зменшіть частоту реєстрації
    Невірний deviceFingerprintПомилка валідаціїРядок довжиною 1–128 символів: лише літери, цифри, дефіс та підкреслення
    401 при реєстраціїНе аутентифікованоПереконайтесь, що надсилається діюча сесія (cookie або Bearer); не передавайте userId у тілі

    Див. також

    • Сповіщення — Типи сповіщень, канали та налаштування
    • Схема та міграції для fcm_tokens (наприклад data/schema.sql, data/migrations/fcm_jsonb_schema.sql) у вашому клоні Ring
    • Truth lens FCM-фахівця (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправки