Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.
«Ring-powered» FCM — це єдина, незалежна від бекенду схема:
fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.(user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає.Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.
«Ring-powered» FCM — це єдина, незалежна від бекенду схема:
fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.(user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає.Ring Platform зберігає FCM-токени в основній базі даних (PostgreSQL або Firestore залежно від режиму бекенду) — по одному запису на користувача та пристрій. React-додатки реєструють токени через Server Action; інші клієнти використовують API з обмеженням частоти. Обидва шляхи викликають один і той самий серверний шар БД, тому поводження та безпека скрізь однакові.
«Ring-powered» FCM — це єдина, незалежна від бекенду схема:
fcm_tokens зберігає всі токени реєстрації. Корисне навантаження зберігається в колонці JSONB data де застосовно (PostgreSQL). Окремого кешу немає; реєстром слугує БД.(user_id, device_fingerprint) дає один запис на пристрій. Значення токена не унікальне, тому при ротації FCM-токена оновлюється той самий рядок, а не створюється дублікат.upsertFcmToken. Ідентифікатор користувача сервер бере лише з auth(); клієнт його не передає.POST /api/notifications/fcm/register з тим самим тілом запиту. Цей endpoint обмежений по частоті на користувача (наприклад, 10 запитів на хвилину).status (active | stale | invalid) та invalidatedAt. Реактивне очищення спрацьовує при помилках FCM по токену; за розкладом позначаються застарілі токени та за потреби виконується жорстке видалення.DB_BACKEND_MODE у PostgreSQL (наприклад k8s-postgres-fcm, supabase-fcm) або Firestore (firebase-full). Один код; розгалужень у Server Action чи API немає./firebase-messaging-sw.js.Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.
React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.
/firebase-messaging-sw.js.Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.
React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.
/firebase-messaging-sw.js.Використовуйте Server Action як основний спосіб реєстрації та оновлення FCM-токенів з будь-якого React- або Next.js-клієнта. Цей шлях не обмежений по частоті, на відміну від API, і ідентифікатор користувача лишається лише на сервері.
React-додаткам слід використовувати Server Action як основний шлях. API призначено для інших клієнтів і обмежений по частоті.
Отримайте стабільний device fingerprint
Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.
Запросіть дозвіл і отримайте FCM-токен
У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.
Викличте Server Action для реєстрації токена
Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().
Обробка оновлення токена
Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.
Отримайте стабільний device fingerprint
Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.
Запросіть дозвіл і отримайте FCM-токен
У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.
Викличте Server Action для реєстрації токена
Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().
Обробка оновлення токена
Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.
Отримайте стабільний device fingerprint
Згенеруйте або завантажте стабільне значення (наприклад, crypto.randomUUID() з localStorage) і використовуйте його при кожному завантаженні та при оновленні токена. Сервер за парою (user_id, device_fingerprint) виконує upsert одного рядка на пристрій.
Запросіть дозвіл і отримайте FCM-токен
У компоненті з 'use client' (наприклад усередині провайдера сповіщень) викличте Notification.requestPermission(). Після дозволу викличте getToken(messaging, { vapidKey }) з Firebase Messaging SDK. Не викликайте getToken() у Server Components — у них немає контексту браузера.
Викличте Server Action для реєстрації токена
Викличте upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Не передавайте userId; сервер бере його з auth().
Обробка оновлення токена
Коли Firebase SDK видає новий токен (наприклад через onTokenRefresh), знову викличте той самий Server Action з новим токеном і тим самим deviceFingerprint. Спільний шар БД оновить існуючий рядок для цього користувача та пристрою.
Приклад: реєстрація та оновлення токена в клієнтському компоненті.
Мобільні додатки та інші клієнти без 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 — Помилка сервераПриклад: реєстрація та оновлення токена в клієнтському компоненті.
Мобільні додатки та інші клієнти без 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 — Помилка сервераПриклад: реєстрація та оновлення токена в клієнтському компоненті.
Мобільні додатки та інші клієнти без 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 не повинні потрапляти на клієнт. Зберігайте їх лише на сервері.
Цей endpoint обмежений по частоті на користувача (наприклад 10 запитів на хвилину). Використовуйте Server Action з React-додатків, щоб не витрачати ліміт API.
Приклад з cURL (підставте cookie сесії або Bearer згідно з вашою налаштуванням auth):
Налаштування розділені так, щоб на клієнт потрапляли лише публічні та безпечні значення.
Приватний ключ VAPID та облікові дані Firebase service account не повинні потрапляти на клієнт. Зберігайте їх лише на сервері.
Цей 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 |
| Призначення | Змінні | Де |
|---|---|---|
| Клієнт (браузер / додаток) | 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 |
| Призначення | Змінні | Де |
|---|---|---|
| Клієнт (браузер / додаток) | 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 користувачем:
deleteToken(messaging) з Firebase client SDK, потім зніміть реєстрацію на сервері: DELETE /api/notifications/fcm/register з тілом { "deviceFingerprint": "same-uuid-as-register" }. Ідемпотентно; можна викликати навіть якщо запис уже видалено або інвалідовано.DELETE з тим самим deviceFingerprint, що й при реєстрації.Сервер позначає рядок як status: 'invalid' і встановлює invalidatedAt; доставка на цей токен припиняється.
При виході або вимкненні push користувачем:
deleteToken(messaging) з Firebase client SDK, потім зніміть реєстрацію на сервері: DELETE /api/notifications/fcm/register з тілом { "deviceFingerprint": "same-uuid-as-register" }. Ідемпотентно; можна викликати навіть якщо запис уже видалено або інвалідовано.DELETE з тим самим deviceFingerprint, що й при реєстрації.Сервер позначає рядок як status: 'invalid' і встановлює invalidatedAt; доставка на цей токен припиняється.
При виході або вимкненні push користувачем:
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 у тілі |
| Проблема | Причина | Дія |
|---|---|---|
| Permission denied або токен не отримано | Користувач відхилив сповіщення або дозвіл ще не запитували | Запросіть дозвіл перед викликом getToken(); обробляйте permission === 'denied' в інтерфейсі |
| 429 при реєстрації | Перевищено ліміт запитів | Використовуйте Server Action з React; для API-клієнтів дотримуйтесь Retry-After та зменшіть частоту реєстрації |
| Невірний deviceFingerprint | Помилка валідації | Рядок довжиною 1–128 символів: лише літери, цифри, дефіс та підкреслення |
| 401 при реєстрації | Не аутентифіковано | Переконайтесь, що надсилається діюча сесія (cookie або Bearer); не передавайте userId у тілі |
| Проблема | Причина | Дія |
|---|---|---|
| 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) у вашому клоні RingAI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправкиfcm_tokens (наприклад data/schema.sql, data/migrations/fcm_jsonb_schema.sql) у вашому клоні RingAI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправкиfcm_tokens (наприклад data/schema.sql, data/migrations/fcm_jsonb_schema.sql) у вашому клоні RingAI-LEGIOX/legiox-truth-lens/fcm-specialist.json) — життєвий цикл токенів, реактивне очищення та шлях відправки