Підготовка контенту платформи 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) — жизненный цикл токенов, реактивная очистка и путь отправки