Documentation

    Documentation

    Documentation

    Ring Platform Logo

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

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

    Ring Platform Logo

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

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

    Ring Platform Logo

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

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

    1. /
    2. /Режим k8s-postgres-fcm

    Оновлено 28 черв. 2026 р.6 хв прослуховування

    1. /
    2. /Режим k8s-postgres-fcm

    Оновлено 28 черв. 2026 р.6 хв прослуховування

    1. /
    2. /Режим k8s-postgres-fcm

    Оновлено 28 черв. 2026 р.6 хв прослуховування

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

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

    Швидкий вхід (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)

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

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

    Швидкий вхід (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)

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

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

    Швидкий вхід (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)
    Документація
    Бекенд Сервіси
    Документація
    Бекенд Сервіси
    Документація
    Бекенд Сервіси

    Режим k8s-postgres-fcm

    k8s-postgres-fcm — це рекомендований бекенд-режим для продакшну та локальної розробки. PostgreSQL на Kubernetes (або локально) обробляє всі дані застосунку, тоді як Firebase Admin SDK ініціалізується виключно для FCM push-повідомлень та Apple Push. Жодної залежності від Firebase для даних застосунку.

    Що дає вам k8s-postgres-fcm

    • Повне володіння даними застосунку — зберігаються в PostgreSQL 16 на вашій інфраструктурі. Жодних читань чи записів до Firestore.
    • Відсутність залежності від Firebase для даних — міграція або зміна провайдера потребує лише зміни рядка підключення до бази даних, а не коду застосунку.
    • Необов'язкові push-сповіщення — FCM та Apple Push залишаються доступними без надання доступу до вашої бази даних Firebase.
    • Інтеграція Auth.js v5 — таблиці автентифікації (користувачі, облікові записи, сесії) зберігаються в PostgreSQL разом з бізнес-даними.
    • Підтримка PostGIS — можливість просторових запитів для радіусу доставки магазину, розташування сутностей, місць проведення подій та функцій нерухомості.
    • Нативний WebSocket транспорт — тунель використовує нативний WSS через TUNNEL_HUB_MODE=k8s-postgres (або in-memory хаб для локальної розробки).

    Коли обирати цей режим

    СценарійРекомендований режим
    Власний продакшн на k3sk8s-postgres-fcm
    Локальна розробка з PostgreSQLk8s-postgres-fcm
    Хмарний PostgreSQL (без K8s)supabase-fcm
    Швидке прототипування / Vercel Edgefirebase-full
    Push-сповіщення потрібнібудь-який режим — FCM є опціональним у всіх трьох

    Вартісний профіль

    • PostgreSQL — працює на вашій власній інфраструктурі (Kubernetes StatefulSet, bare metal або Docker). Без вартості за запит.
    • Firebase FCM — push-сповіщення безкоштовні на будь-якому масштабі. Облікові дані проєкту Firebase потрібні лише якщо ви вмикаєте push.
    • Відсутність витрат на Firestore — Firestore ніколи не використовується для даних застосунку в цьому режимі. Виклик getAdminDb() повертає імітацію Firestore, яка ніколи не підключається.

    Архітектура

    Ключові точки прийняття рішень у коді:

    • shouldUseFirebaseForDatabase() повертає false — getAdminDb() повертає імітацію Firestore з build-mock.server.ts, яка ніколи не підключається до Firebase.
    • shouldInitializeFirebaseFCM() повертає true — Firebase Admin SDK ініціалізується лише для push-повідомлень.
    • shouldInitializeApplePush() повертає true — сервіс Apple Push Notification Service доступний.
    • PostgreSQLAdapter реалізує IDatabaseService та обробляє всі CRUD, запити, транзакції та операції підрахунку.

    Необхідні змінні середовища

    ЗміннаОбов'язковоЗа замовчуваннямОпис
    DB_BACKEND_MODEТак—Має бути k8s-postgres-fcm
    DB_HOSTТакlocalhostХост PostgreSQL
    DB_PORTНі5432Порт PostgreSQL

    Режим k8s-postgres-fcm

    k8s-postgres-fcm — це рекомендований бекенд-режим для продакшну та локальної розробки. PostgreSQL на Kubernetes (або локально) обробляє всі дані застосунку, тоді як Firebase Admin SDK ініціалізується виключно для FCM push-повідомлень та Apple Push. Жодної залежності від Firebase для даних застосунку.

    Що дає вам k8s-postgres-fcm

    • Повне володіння даними застосунку — зберігаються в PostgreSQL 16 на вашій інфраструктурі. Жодних читань чи записів до Firestore.
    • Відсутність залежності від Firebase для даних — міграція або зміна провайдера потребує лише зміни рядка підключення до бази даних, а не коду застосунку.
    • Необов'язкові push-сповіщення — FCM та Apple Push залишаються доступними без надання доступу до вашої бази даних Firebase.
    • Інтеграція Auth.js v5 — таблиці автентифікації (користувачі, облікові записи, сесії) зберігаються в PostgreSQL разом з бізнес-даними.
    • Підтримка PostGIS — можливість просторових запитів для радіусу доставки магазину, розташування сутностей, місць проведення подій та функцій нерухомості.
    • Нативний WebSocket транспорт — тунель використовує нативний WSS через TUNNEL_HUB_MODE=k8s-postgres (або in-memory хаб для локальної розробки).

    Коли обирати цей режим

    СценарійРекомендований режим
    Власний продакшн на k3sk8s-postgres-fcm
    Локальна розробка з PostgreSQLk8s-postgres-fcm
    Хмарний PostgreSQL (без K8s)supabase-fcm
    Швидке прототипування / Vercel Edgefirebase-full
    Push-сповіщення потрібнібудь-який режим — FCM є опціональним у всіх трьох

    Вартісний профіль

    • PostgreSQL — працює на вашій власній інфраструктурі (Kubernetes StatefulSet, bare metal або Docker). Без вартості за запит.
    • Firebase FCM — push-сповіщення безкоштовні на будь-якому масштабі. Облікові дані проєкту Firebase потрібні лише якщо ви вмикаєте push.
    • Відсутність витрат на Firestore — Firestore ніколи не використовується для даних застосунку в цьому режимі. Виклик getAdminDb() повертає імітацію Firestore, яка ніколи не підключається.

    Архітектура

    Ключові точки прийняття рішень у коді:

    • shouldUseFirebaseForDatabase() повертає false — getAdminDb() повертає імітацію Firestore з build-mock.server.ts, яка ніколи не підключається до Firebase.
    • shouldInitializeFirebaseFCM() повертає true — Firebase Admin SDK ініціалізується лише для push-повідомлень.
    • shouldInitializeApplePush() повертає true — сервіс Apple Push Notification Service доступний.
    • PostgreSQLAdapter реалізує IDatabaseService та обробляє всі CRUD, запити, транзакції та операції підрахунку.

    Необхідні змінні середовища

    ЗміннаОбов'язковоЗа замовчуваннямОпис
    DB_BACKEND_MODEТак—Має бути k8s-postgres-fcm
    DB_HOSTТакlocalhostХост PostgreSQL
    DB_PORTНі5432Порт PostgreSQL

    Режим k8s-postgres-fcm

    k8s-postgres-fcm — це рекомендований бекенд-режим для продакшну та локальної розробки. PostgreSQL на Kubernetes (або локально) обробляє всі дані застосунку, тоді як Firebase Admin SDK ініціалізується виключно для FCM push-повідомлень та Apple Push. Жодної залежності від Firebase для даних застосунку.

    Що дає вам k8s-postgres-fcm

    • Повне володіння даними застосунку — зберігаються в PostgreSQL 16 на вашій інфраструктурі. Жодних читань чи записів до Firestore.
    • Відсутність залежності від Firebase для даних — міграція або зміна провайдера потребує лише зміни рядка підключення до бази даних, а не коду застосунку.
    • Необов'язкові push-сповіщення — FCM та Apple Push залишаються доступними без надання доступу до вашої бази даних Firebase.
    • Інтеграція Auth.js v5 — таблиці автентифікації (користувачі, облікові записи, сесії) зберігаються в PostgreSQL разом з бізнес-даними.
    • Підтримка PostGIS — можливість просторових запитів для радіусу доставки магазину, розташування сутностей, місць проведення подій та функцій нерухомості.
    • Нативний WebSocket транспорт — тунель використовує нативний WSS через TUNNEL_HUB_MODE=k8s-postgres (або in-memory хаб для локальної розробки).

    Коли обирати цей режим

    СценарійРекомендований режим
    Власний продакшн на k3sk8s-postgres-fcm
    Локальна розробка з PostgreSQLk8s-postgres-fcm
    Хмарний PostgreSQL (без K8s)supabase-fcm
    Швидке прототипування / Vercel Edgefirebase-full
    Push-сповіщення потрібнібудь-який режим — FCM є опціональним у всіх трьох

    Вартісний профіль

    • PostgreSQL — працює на вашій власній інфраструктурі (Kubernetes StatefulSet, bare metal або Docker). Без вартості за запит.
    • Firebase FCM — push-сповіщення безкоштовні на будь-якому масштабі. Облікові дані проєкту Firebase потрібні лише якщо ви вмикаєте push.
    • Відсутність витрат на Firestore — Firestore ніколи не використовується для даних застосунку в цьому режимі. Виклик getAdminDb() повертає імітацію Firestore, яка ніколи не підключається.

    Архітектура

    Ключові точки прийняття рішень у коді:

    • shouldUseFirebaseForDatabase() повертає false — getAdminDb() повертає імітацію Firestore з build-mock.server.ts, яка ніколи не підключається до Firebase.
    • shouldInitializeFirebaseFCM() повертає true — Firebase Admin SDK ініціалізується лише для push-повідомлень.
    • shouldInitializeApplePush() повертає true — сервіс Apple Push Notification Service доступний.
    • PostgreSQLAdapter реалізує IDatabaseService та обробляє всі CRUD, запити, транзакції та операції підрахунку.

    Необхідні змінні середовища

    ЗміннаОбов'язковоЗа замовчуваннямОпис
    DB_BACKEND_MODEТак—Має бути k8s-postgres-fcm
    DB_HOSTТакlocalhostХост PostgreSQL
    DB_PORTНі5432Порт PostgreSQL
    DB_NAMEТакring_platformНазва бази даних
    DB_USERТакring_userКористувач бази даних
    DB_PASSWORDТакring_dev_passwordПароль бази даних
    DB_POOL_SIZEНі20Максимальний розмір пулу з'єднань
    DB_TIMEOUTНі30000Час очікування з'єднання (мс)
    DB_RETRIESНі3Кількість повторних спроб
    DB_SSLНіfalseУвімкнути TLS для PostgreSQL
    DB_ENABLE_POSTGISНіfalseУвімкнути розширення PostGIS

    Необов'язкові змінні середовища FCM / Firebase

    Потрібні лише якщо вам потрібні push-сповіщення. Без них платформа працює виключно з PostgreSQL.

    Конфігурація підключення PostgreSQL

    PostgreSQLAdapter будує конфігурацію пулу зі змінних середовища. Джерело: lib/database/adapters/PostgreSQLAdapter.ts:

    Адаптер використовує гібридну JSONB-схему: більшість таблиць зберігають бізнес-дані в стовпці data типу JSONB разом із загальними стовпцями id, created_at, updated_at. Таблиці з повністю нормалізованими схемами (наприклад, vendor_applications, vendor_profiles») перераховують усі стовпці в мапі fieldMappings, тому конструктор запитів використовує прямі посилання на стовпці замість data->>'field'`.

    Адаптер підтримує повний контракт DatabaseService:

    Локальне налаштування

    1. Запустіть PostgreSQL (два варіанти):

      bash
      
      # Варіант A: Docker (рекомендовано)
      docker run -d --name ring-postgres-dev \
        -e POSTGRES_USER=ring_user \
        -e POSTGRES_PASSWORD=ring_password_2024 \
        -e POSTGRES_DB=ring_platform \
        -p 5432:5432 \
        postgres:16-alpine
      
      # Варіант B: Homebrew (macOS)
      brew install postgresql@16
      brew services start postgresql@16
      createdb ring_platform
    2. Створіть .env.local з шаблону та встановіть:

      bash
      
      DB_BACKEND_MODE=k8s-postgres-fcm
      DB_HOST=localhost
      DB_PORT=5432
      DB_NAME=ring_platform
      DB_USER=ring_user
      DB_PASSWORD=ring_password_2024
    3. Застосуйте схему:

      bash
      
      psql -h localhost -U ring_user -d ring_platform -f data/schema.sql
    4. Запустіть сервер розробки:

      bash
      
      npm run dev

      Платформа перевіряє DB_BACKEND_MODE під час запуску та логує конфігурацію бекенду. Ви маєте побачити Database: PostgreSQL у логах запуску.

    Тунельний хаб для функцій реального часу:

    У локальній розробці тунель за замовчуванням використовує in-memory хаб. Для поведінки, наближеної до продакшну, встановіть:

    Це зберігає стан тунелю в PostgreSQL замість пам'яті процесу.

    Налаштування продакшну на K8s

    1. Ізоляція просторів імен

    Кожен клон ring отримує власний простір імен: k8s/namespace.yaml

    2. StatefulSet PostgreSQL

    Маніфест k8s/postgres.yaml розгортає PostgreSQL 16 (образ: postgres:15) як Deployment з одним реплікою та сервісом ClusterIP:

    • ConfigMap (postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
    • Init SQL — створює користувача застосунку (platform_org_user) та надає привілеї
    • Розширення — uuid-ossp та btree_gin увімкнено за замовчуванням
    • Сховище — том hostPath за шляхом /data/postgres-<clone-name>
    • Сервіс — розпізнається як postgres.<namespace>.svc.cluster.local

    3. Секрети та ConfigMap

    Секрети (k8s/secrets.yaml — Opaque, stringData):

    ConfigMap (k8s/secrets.yaml — секція ConfigMap):

    Важливо: DB_PASSWORD має бути в Secret, а не в ConfigMap. Розгортання посилається на нього через secretKeyRef.

    4. Розгортання застосунку

    k8s/deployment.yaml — застосунок Next.js 16 з:

    • Образ: ghcr.io/connectplatform/ring:v<version>-<clone>-amd64
    • 256Mi запит / 1Gi ліміт пам'яті
    • 200m / 1000m CPU
    • Liveness + readiness + startup проби (/api/health)
    • Змінні середовища з ConfigMap (нечутливі) та Secret (чутливі)
    • Постійний том для завантажених файлів (pvc-local-file-storage.yaml — 20Gi)
    • Pod anti-affinity для високої доступності

    5. Ingress

    k8s/ingress.yaml — контролер ingress nginx з:

    • Let's Encrypt TLS (cert-manager letsencrypt-prod)
    • Підтримка WebSocket (тайм-аут проксі 3600с, анотація websocket-services)
    • Великий буфер проксі (32k — Next.js надсилає великі Link-заголовки для hreflang)
    • Обмеження швидкості (100 RPS, 50 з'єднань)
    • Ліміт розміру тіла 50MB

    6. Застосування стеку

    Налаштування Docker

    Для локальних або продакшн-розгортань на основі Docker docker-compose.yml підтримує режим k8s-postgres-fcm. Переконайтеся, що ваш .env містить DB_BACKEND_MODE=k8s-postgres-fcm та змінні для підключення PostgreSQL:

    Примітка: Стандартний docker-compose.yml не включає сервіс PostgreSQL. Ви повинні або:

    • Запустити PostgreSQL окремо (власне встановлення або docker run postgres:16-alpine)
    • Додати сервіс postgres до вашого перевизначення (docker/docker-compose.dev.yml)

    Нотатки щодо підключення FCM

    Цей режим використовує Firebase Admin виключно для push:

    1. Ініціалізація Admin SDK — застосунок Firebase Admin створюється, якщо присутні змінні середовища AUTH_FIREBASE_*. SDK потрібен для генерації FCM-токенів та надсилання push-повідомлень.
    2. Імітація Firestore — getAdminDb() повертає імітацію Firestore (ніколи не підключається до Firebase). Це контролюється тим, що shouldUseFirebaseForDatabase() повертає false.
    3. Імітація Auth — getAdminAuth() також повертає імітацію. Auth.js v5 обробляє всю автентифікацію.
    4. Клієнтський FCM — Service worker (public/firebase-messaging-sw.js) працює в браузері та завантажує Firebase compat SDK з CDN. На нього не впливає режим бекенду — він завжди підключається до Firebase для push-підписки.
    5. FCM-токени — зберігаються в таблиці fcm_tokens PostgreSQL через Server Action upsertFcmToken.
    6. Без змінних середовища Firebase = без push — Якщо пропустити всі змінні AUTH_FIREBASE_* та NEXT_PUBLIC_FIREBASE_*, ініціалізація Firebase Admin повністю пропускається. PostgreSQL продовжує працювати.

    Порівняння: k8s-postgres-fcm vs supabase-fcm

    Аспектk8s-postgres-fcmsupabase-fcm
    Хост PostgreSQLВаш K8s або локальнийХмара Supabase
    SSLНеобов'язково (DB_SSL=false за замовчуванням)Обов'язково (DB_SSL=true)
    Пул з'єднаньDB_POOL_SIZE=20 за замовчуваннямDB_POOL_SIZE=10 за замовчуванням
    Облікові даніDB_USER / DB_PASSWORDSUPABASE_URL / SUPABASE_SERVICE_KEY
    Ціль розгортанняK8s, Docker, bare metalПлатформа Supabase
    Маніфести K8sПовний набір у k8s/Не застосовно
    Тунельний хабk8s-postgres або memorymemory
    PostGISDB_ENABLE_POSTGIS=trueПотребує додатку Supabase PostGIS
    Варіант використанняПовний контроль інфраструктуриКерований хмарний PostgreSQL

    Обидва режими використовують той самий клас PostgreSQLAdapter. Єдина відмінність — хто хостить екземпляр PostgreSQL та як надаються параметри підключення.

    Пов'язана документація

    Backend modes and databases

    Database selection guide

    Environment variables

    Firebase integration

    Deployment guide

    Local setup

    bash
    
    # Вибір режиму (ОБОВ'ЯЗКОВО — платформа не запуститься без нього)
    DB_BACKEND_MODE=k8s-postgres-fcm
    
    # Підключення до PostgreSQL
    DB_HOST=localhost               # K8s: postgres.<namespace>.svc.cluster.local
    DB_PORT=5432
    DB_NAME=ring_platform
    DB_USER=ring_user
    DB_PASSWORD=ring_password_2024
    
    # Налаштування пулу з'єднань (необов'язково, показано зі значеннями за замовчуванням)
    DB_POOL_SIZE=20                 # Максимум з'єднань у пулі
    DB_TIMEOUT=30000                # Час очікування з'єднання в мс
    DB_RETRIES=3                    # Спроби повтору при збої
    DB_SSL=false                    # Встановіть true для продакшну та Supabase
    
    # PostGIS (необов'язково)
    DB_ENABLE_POSTGIS=false         # Увімкнути просторові розширення
    text
    
    ┌─────────────────────────────────────────────────┐
    │                Next.js 16 App                     │
    │                                                   │
    │  ┌──────────────────────┐  ┌──────────────────┐  │
    │  │  PostgreSQLAdapter   │  │  Firebase Admin   │  │
    │  │  (all CRUD / query)  │  │  (FCM + Apple     │  │
    │  │                      │  │   Push only)      │  │
    │  │  • Auth.js tables    │  │                   │  │
    │  │  • Entities          │  │  • getAdminDb()   │  │
    │  │  • Store products    │  │    → mock (never  │  │
    │  │  • Conversations     │  │      connects)    │  │
    │  │  • FCM tokens        │  │  • getAdminAuth() │  │
    │  │  • All business data │  │    → mock         │  │
    │  └────────┬─────────────┘  └────────┬─────────┘  │
    │           │                         │            │
    └───────────┼─────────────────────────┼────────────┘
                │                         │
                ▼                         ▼
       ┌─────────────────┐     ┌──────────────────┐
       │  PostgreSQL 16   │     │  Firebase FCM    │
       │  + PostGIS       │     │  (push only)     │
       │  StatefulSet     │     └──────────────────┘
       │  (k8s or local)  │
       └─────────────────┘
    bash
    
    # Firebase Admin SDK (серверний) — потрібен для FCM
    AUTH_FIREBASE_PROJECT_ID=your_firebase_project_id
    AUTH_FIREBASE_CLIENT_EMAIL=your_firebase_client_email
    AUTH_FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
    
    # Firebase client SDK (браузерний) — для реєстрації push через service worker
    NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_auth_domain
    NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_firebase_project_id
    NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_storage_bucket
    NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_messaging_sender_id
    NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
    NEXT_PUBLIC_FIREBASE_VAPID_KEY=your_vapid_key
    typescript
    
    const poolConfig = {
      host: config.connection.host || 'localhost',
      port: config.connection.port || 5432,
      database: config.connection.database || 'ring_platform',
      user: config.connection.username || 'ring_user',
      password: config.connection.password || 'ring_dev_password',
      max: config.options.poolSize || 20,
      idleTimeoutMillis: config.options.timeout || 30000,
      connectionTimeoutMillis: config.options.timeout || 2000,
    }
    typescript
    
    // Операції з окремими документами
    await db.findById('users', userId)
    await db.create('users', { name: 'Аліса', email: 'alice@example.com' })
    await db.update('users', userId, { name: 'Боб' })
    await db.delete('users', userId)
    
    // Запити з фільтрами, сортуванням, пагінацією
    await db.query({
      collection: 'entities',
      filters: [{ field: 'status', operator: 'eq', value: 'active' }],
      orderBy: [{ field: 'createdAt', direction: 'desc' }],
      pagination: { limit: 20, offset: 0 },
    })
    
    // Транзакції
    await db.transaction(async (txn) => {
      const order = await txn.create('orders', { total: 100 })
      await txn.update('stock', productId, { quantity: 5 })
    })
    bash
    
    TUNNEL_HUB_MODE=k8s-postgres
    yaml
    
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ring-platform-org
      labels:
        app.kubernetes.io/name: ring-platform-org
        app.kubernetes.io/part-of: ringdom
    yaml
    
    apiVersion: v1
    kind: Secret
    metadata:
      name: ring-platform-org-secrets
    type: Opaque
    stringData:
      DB_PASSWORD: <value>
      AUTH_FIREBASE_PROJECT_ID: <value>
      AUTH_FIREBASE_CLIENT_EMAIL: <value>
      AUTH_FIREBASE_PRIVATE_KEY: |
        -----BEGIN PRIVATE KEY-----
        ...
        -----END PRIVATE KEY-----
    yaml
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ring-platform-org-config
    data:
      DB_BACKEND_MODE: k8s-postgres-fcm
      DB_HOST: postgres.ring-platform-org.svc.cluster.local
      DB_PORT: "5432"
      DB_NAME: ring_platform
      DB_USER: ring_user
      DB_POOL_SIZE: "20"
      DB_TIMEOUT: "30000"
      DB_RETRIES: "3"
      DB_SSL: "false"
      NEXT_PUBLIC_FIREBASE_PROJECT_ID: <value>
    bash
    
    kubectl apply -f k8s/namespace.yaml
    kubectl apply -f k8s/postgres.yaml
    kubectl apply -f k8s/secrets.yaml
    kubectl apply -f k8s/deployment.yaml
    kubectl apply -f k8s/service.yaml
    kubectl apply -f k8s/ingress.yaml
    kubectl apply -f k8s/pvc-local-file-storage.yaml
    bash
    
    docker compose up -d
    DB_NAMEТакring_platformНазва бази даних
    DB_USERТакring_userКористувач бази даних
    DB_PASSWORDТакring_dev_passwordПароль бази даних
    DB_POOL_SIZEНі20Максимальний розмір пулу з'єднань
    DB_TIMEOUTНі30000Час очікування з'єднання (мс)
    DB_RETRIESНі3Кількість повторних спроб
    DB_SSLНіfalseУвімкнути TLS для PostgreSQL
    DB_ENABLE_POSTGISНіfalseУвімкнути розширення PostGIS

    Необов'язкові змінні середовища FCM / Firebase

    Потрібні лише якщо вам потрібні push-сповіщення. Без них платформа працює виключно з PostgreSQL.

    Конфігурація підключення PostgreSQL

    PostgreSQLAdapter будує конфігурацію пулу зі змінних середовища. Джерело: lib/database/adapters/PostgreSQLAdapter.ts:

    Адаптер використовує гібридну JSONB-схему: більшість таблиць зберігають бізнес-дані в стовпці data типу JSONB разом із загальними стовпцями id, created_at, updated_at. Таблиці з повністю нормалізованими схемами (наприклад, vendor_applications, vendor_profiles») перераховують усі стовпці в мапі fieldMappings, тому конструктор запитів використовує прямі посилання на стовпці замість data->>'field'`.

    Адаптер підтримує повний контракт DatabaseService:

    Локальне налаштування

    1. Запустіть PostgreSQL (два варіанти):

      bash
      
      # Варіант A: Docker (рекомендовано)
      docker run -d --name ring-postgres-dev \
        -e POSTGRES_USER=ring_user \
        -e POSTGRES_PASSWORD=ring_password_2024 \
        -e POSTGRES_DB=ring_platform \
        -p 5432:5432 \
        postgres:16-alpine
      
      # Варіант B: Homebrew (macOS)
      brew install postgresql@16
      brew services start postgresql@16
      createdb ring_platform
    2. Створіть .env.local з шаблону та встановіть:

      bash
      
      DB_BACKEND_MODE=k8s-postgres-fcm
      DB_HOST=localhost
      DB_PORT=5432
      DB_NAME=ring_platform
      DB_USER=ring_user
      DB_PASSWORD=ring_password_2024
    3. Застосуйте схему:

      bash
      
      psql -h localhost -U ring_user -d ring_platform -f data/schema.sql
    4. Запустіть сервер розробки:

      bash
      
      npm run dev

      Платформа перевіряє DB_BACKEND_MODE під час запуску та логує конфігурацію бекенду. Ви маєте побачити Database: PostgreSQL у логах запуску.

    Тунельний хаб для функцій реального часу:

    У локальній розробці тунель за замовчуванням використовує in-memory хаб. Для поведінки, наближеної до продакшну, встановіть:

    Це зберігає стан тунелю в PostgreSQL замість пам'яті процесу.

    Налаштування продакшну на K8s

    1. Ізоляція просторів імен

    Кожен клон ring отримує власний простір імен: k8s/namespace.yaml

    2. StatefulSet PostgreSQL

    Маніфест k8s/postgres.yaml розгортає PostgreSQL 16 (образ: postgres:15) як Deployment з одним реплікою та сервісом ClusterIP:

    • ConfigMap (postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
    • Init SQL — створює користувача застосунку (platform_org_user) та надає привілеї
    • Розширення — uuid-ossp та btree_gin увімкнено за замовчуванням
    • Сховище — том hostPath за шляхом /data/postgres-<clone-name>
    • Сервіс — розпізнається як postgres.<namespace>.svc.cluster.local

    3. Секрети та ConfigMap

    Секрети (k8s/secrets.yaml — Opaque, stringData):

    ConfigMap (k8s/secrets.yaml — секція ConfigMap):

    Важливо: DB_PASSWORD має бути в Secret, а не в ConfigMap. Розгортання посилається на нього через secretKeyRef.

    4. Розгортання застосунку

    k8s/deployment.yaml — застосунок Next.js 16 з:

    • Образ: ghcr.io/connectplatform/ring:v<version>-<clone>-amd64
    • 256Mi запит / 1Gi ліміт пам'яті
    • 200m / 1000m CPU
    • Liveness + readiness + startup проби (/api/health)
    • Змінні середовища з ConfigMap (нечутливі) та Secret (чутливі)
    • Постійний том для завантажених файлів (pvc-local-file-storage.yaml — 20Gi)
    • Pod anti-affinity для високої доступності

    5. Ingress

    k8s/ingress.yaml — контролер ingress nginx з:

    • Let's Encrypt TLS (cert-manager letsencrypt-prod)
    • Підтримка WebSocket (тайм-аут проксі 3600с, анотація websocket-services)
    • Великий буфер проксі (32k — Next.js надсилає великі Link-заголовки для hreflang)
    • Обмеження швидкості (100 RPS, 50 з'єднань)
    • Ліміт розміру тіла 50MB

    6. Застосування стеку

    Налаштування Docker

    Для локальних або продакшн-розгортань на основі Docker docker-compose.yml підтримує режим k8s-postgres-fcm. Переконайтеся, що ваш .env містить DB_BACKEND_MODE=k8s-postgres-fcm та змінні для підключення PostgreSQL:

    Примітка: Стандартний docker-compose.yml не включає сервіс PostgreSQL. Ви повинні або:

    • Запустити PostgreSQL окремо (власне встановлення або docker run postgres:16-alpine)
    • Додати сервіс postgres до вашого перевизначення (docker/docker-compose.dev.yml)

    Нотатки щодо підключення FCM

    Цей режим використовує Firebase Admin виключно для push:

    1. Ініціалізація Admin SDK — застосунок Firebase Admin створюється, якщо присутні змінні середовища AUTH_FIREBASE_*. SDK потрібен для генерації FCM-токенів та надсилання push-повідомлень.
    2. Імітація Firestore — getAdminDb() повертає імітацію Firestore (ніколи не підключається до Firebase). Це контролюється тим, що shouldUseFirebaseForDatabase() повертає false.
    3. Імітація Auth — getAdminAuth() також повертає імітацію. Auth.js v5 обробляє всю автентифікацію.
    4. Клієнтський FCM — Service worker (public/firebase-messaging-sw.js) працює в браузері та завантажує Firebase compat SDK з CDN. На нього не впливає режим бекенду — він завжди підключається до Firebase для push-підписки.
    5. FCM-токени — зберігаються в таблиці fcm_tokens PostgreSQL через Server Action upsertFcmToken.
    6. Без змінних середовища Firebase = без push — Якщо пропустити всі змінні AUTH_FIREBASE_* та NEXT_PUBLIC_FIREBASE_*, ініціалізація Firebase Admin повністю пропускається. PostgreSQL продовжує працювати.

    Порівняння: k8s-postgres-fcm vs supabase-fcm

    Аспектk8s-postgres-fcmsupabase-fcm
    Хост PostgreSQLВаш K8s або локальнийХмара Supabase
    SSLНеобов'язково (DB_SSL=false за замовчуванням)Обов'язково (DB_SSL=true)
    Пул з'єднаньDB_POOL_SIZE=20 за замовчуваннямDB_POOL_SIZE=10 за замовчуванням
    Облікові даніDB_USER / DB_PASSWORDSUPABASE_URL / SUPABASE_SERVICE_KEY
    Ціль розгортанняK8s, Docker, bare metalПлатформа Supabase
    Маніфести K8sПовний набір у k8s/Не застосовно
    Тунельний хабk8s-postgres або memorymemory
    PostGISDB_ENABLE_POSTGIS=trueПотребує додатку Supabase PostGIS
    Варіант використанняПовний контроль інфраструктуриКерований хмарний PostgreSQL

    Обидва режими використовують той самий клас PostgreSQLAdapter. Єдина відмінність — хто хостить екземпляр PostgreSQL та як надаються параметри підключення.

    Пов'язана документація

    Backend modes and databases

    Database selection guide

    Environment variables

    Firebase integration

    Deployment guide

    Local setup

    bash
    
    # Вибір режиму (ОБОВ'ЯЗКОВО — платформа не запуститься без нього)
    DB_BACKEND_MODE=k8s-postgres-fcm
    
    # Підключення до PostgreSQL
    DB_HOST=localhost               # K8s: postgres.<namespace>.svc.cluster.local
    DB_PORT=5432
    DB_NAME=ring_platform
    DB_USER=ring_user
    DB_PASSWORD=ring_password_2024
    
    # Налаштування пулу з'єднань (необов'язково, показано зі значеннями за замовчуванням)
    DB_POOL_SIZE=20                 # Максимум з'єднань у пулі
    DB_TIMEOUT=30000                # Час очікування з'єднання в мс
    DB_RETRIES=3                    # Спроби повтору при збої
    DB_SSL=false                    # Встановіть true для продакшну та Supabase
    
    # PostGIS (необов'язково)
    DB_ENABLE_POSTGIS=false         # Увімкнути просторові розширення
    text
    
    ┌─────────────────────────────────────────────────┐
    │                Next.js 16 App                     │
    │                                                   │
    │  ┌──────────────────────┐  ┌──────────────────┐  │
    │  │  PostgreSQLAdapter   │  │  Firebase Admin   │  │
    │  │  (all CRUD / query)  │  │  (FCM + Apple     │  │
    │  │                      │  │   Push only)      │  │
    │  │  • Auth.js tables    │  │                   │  │
    │  │  • Entities          │  │  • getAdminDb()   │  │
    │  │  • Store products    │  │    → mock (never  │  │
    │  │  • Conversations     │  │      connects)    │  │
    │  │  • FCM tokens        │  │  • getAdminAuth() │  │
    │  │  • All business data │  │    → mock         │  │
    │  └────────┬─────────────┘  └────────┬─────────┘  │
    │           │                         │            │
    └───────────┼─────────────────────────┼────────────┘
                │                         │
                ▼                         ▼
       ┌─────────────────┐     ┌──────────────────┐
       │  PostgreSQL 16   │     │  Firebase FCM    │
       │  + PostGIS       │     │  (push only)     │
       │  StatefulSet     │     └──────────────────┘
       │  (k8s or local)  │
       └─────────────────┘
    bash
    
    # Firebase Admin SDK (серверний) — потрібен для FCM
    AUTH_FIREBASE_PROJECT_ID=your_firebase_project_id
    AUTH_FIREBASE_CLIENT_EMAIL=your_firebase_client_email
    AUTH_FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
    
    # Firebase client SDK (браузерний) — для реєстрації push через service worker
    NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_auth_domain
    NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_firebase_project_id
    NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_storage_bucket
    NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_messaging_sender_id
    NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
    NEXT_PUBLIC_FIREBASE_VAPID_KEY=your_vapid_key
    typescript
    
    const poolConfig = {
      host: config.connection.host || 'localhost',
      port: config.connection.port || 5432,
      database: config.connection.database || 'ring_platform',
      user: config.connection.username || 'ring_user',
      password: config.connection.password || 'ring_dev_password',
      max: config.options.poolSize || 20,
      idleTimeoutMillis: config.options.timeout || 30000,
      connectionTimeoutMillis: config.options.timeout || 2000,
    }
    typescript
    
    // Операції з окремими документами
    await db.findById('users', userId)
    await db.create('users', { name: 'Аліса', email: 'alice@example.com' })
    await db.update('users', userId, { name: 'Боб' })
    await db.delete('users', userId)
    
    // Запити з фільтрами, сортуванням, пагінацією
    await db.query({
      collection: 'entities',
      filters: [{ field: 'status', operator: 'eq', value: 'active' }],
      orderBy: [{ field: 'createdAt', direction: 'desc' }],
      pagination: { limit: 20, offset: 0 },
    })
    
    // Транзакції
    await db.transaction(async (txn) => {
      const order = await txn.create('orders', { total: 100 })
      await txn.update('stock', productId, { quantity: 5 })
    })
    bash
    
    TUNNEL_HUB_MODE=k8s-postgres
    yaml
    
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ring-platform-org
      labels:
        app.kubernetes.io/name: ring-platform-org
        app.kubernetes.io/part-of: ringdom
    yaml
    
    apiVersion: v1
    kind: Secret
    metadata:
      name: ring-platform-org-secrets
    type: Opaque
    stringData:
      DB_PASSWORD: <value>
      AUTH_FIREBASE_PROJECT_ID: <value>
      AUTH_FIREBASE_CLIENT_EMAIL: <value>
      AUTH_FIREBASE_PRIVATE_KEY: |
        -----BEGIN PRIVATE KEY-----
        ...
        -----END PRIVATE KEY-----
    yaml
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ring-platform-org-config
    data:
      DB_BACKEND_MODE: k8s-postgres-fcm
      DB_HOST: postgres.ring-platform-org.svc.cluster.local
      DB_PORT: "5432"
      DB_NAME: ring_platform
      DB_USER: ring_user
      DB_POOL_SIZE: "20"
      DB_TIMEOUT: "30000"
      DB_RETRIES: "3"
      DB_SSL: "false"
      NEXT_PUBLIC_FIREBASE_PROJECT_ID: <value>
    bash
    
    kubectl apply -f k8s/namespace.yaml
    kubectl apply -f k8s/postgres.yaml
    kubectl apply -f k8s/secrets.yaml
    kubectl apply -f k8s/deployment.yaml
    kubectl apply -f k8s/service.yaml
    kubectl apply -f k8s/ingress.yaml
    kubectl apply -f k8s/pvc-local-file-storage.yaml
    bash
    
    docker compose up -d
    DB_NAMEТакring_platformНазва бази даних
    DB_USERТакring_userКористувач бази даних
    DB_PASSWORDТакring_dev_passwordПароль бази даних
    DB_POOL_SIZEНі20Максимальний розмір пулу з'єднань
    DB_TIMEOUTНі30000Час очікування з'єднання (мс)
    DB_RETRIESНі3Кількість повторних спроб
    DB_SSLНіfalseУвімкнути TLS для PostgreSQL
    DB_ENABLE_POSTGISНіfalseУвімкнути розширення PostGIS

    Необов'язкові змінні середовища FCM / Firebase

    Потрібні лише якщо вам потрібні push-сповіщення. Без них платформа працює виключно з PostgreSQL.

    Конфігурація підключення PostgreSQL

    PostgreSQLAdapter будує конфігурацію пулу зі змінних середовища. Джерело: lib/database/adapters/PostgreSQLAdapter.ts:

    Адаптер використовує гібридну JSONB-схему: більшість таблиць зберігають бізнес-дані в стовпці data типу JSONB разом із загальними стовпцями id, created_at, updated_at. Таблиці з повністю нормалізованими схемами (наприклад, vendor_applications, vendor_profiles») перераховують усі стовпці в мапі fieldMappings, тому конструктор запитів використовує прямі посилання на стовпці замість data->>'field'`.

    Адаптер підтримує повний контракт DatabaseService:

    Локальне налаштування

    1. Запустіть PostgreSQL (два варіанти):

      bash
      
      # Варіант A: Docker (рекомендовано)
      docker run -d --name ring-postgres-dev \
        -e POSTGRES_USER=ring_user \
        -e POSTGRES_PASSWORD=ring_password_2024 \
        -e POSTGRES_DB=ring_platform \
        -p 5432:5432 \
        postgres:16-alpine
      
      # Варіант B: Homebrew (macOS)
      brew install postgresql@16
      brew services start postgresql@16
      createdb ring_platform
    2. Створіть .env.local з шаблону та встановіть:

      bash
      
      DB_BACKEND_MODE=k8s-postgres-fcm
      DB_HOST=localhost
      DB_PORT=5432
      DB_NAME=ring_platform
      DB_USER=ring_user
      DB_PASSWORD=ring_password_2024
    3. Застосуйте схему:

      bash
      
      psql -h localhost -U ring_user -d ring_platform -f data/schema.sql
    4. Запустіть сервер розробки:

      bash
      
      npm run dev

      Платформа перевіряє DB_BACKEND_MODE під час запуску та логує конфігурацію бекенду. Ви маєте побачити Database: PostgreSQL у логах запуску.

    Тунельний хаб для функцій реального часу:

    У локальній розробці тунель за замовчуванням використовує in-memory хаб. Для поведінки, наближеної до продакшну, встановіть:

    Це зберігає стан тунелю в PostgreSQL замість пам'яті процесу.

    Налаштування продакшну на K8s

    1. Ізоляція просторів імен

    Кожен клон ring отримує власний простір імен: k8s/namespace.yaml

    2. StatefulSet PostgreSQL

    Маніфест k8s/postgres.yaml розгортає PostgreSQL 16 (образ: postgres:15) як Deployment з одним реплікою та сервісом ClusterIP:

    • ConfigMap (postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
    • Init SQL — створює користувача застосунку (platform_org_user) та надає привілеї
    • Розширення — uuid-ossp та btree_gin увімкнено за замовчуванням
    • Сховище — том hostPath за шляхом /data/postgres-<clone-name>
    • Сервіс — розпізнається як postgres.<namespace>.svc.cluster.local

    3. Секрети та ConfigMap

    Секрети (k8s/secrets.yaml — Opaque, stringData):

    ConfigMap (k8s/secrets.yaml — секція ConfigMap):

    Важливо: DB_PASSWORD має бути в Secret, а не в ConfigMap. Розгортання посилається на нього через secretKeyRef.

    4. Розгортання застосунку

    k8s/deployment.yaml — застосунок Next.js 16 з:

    • Образ: ghcr.io/connectplatform/ring:v<version>-<clone>-amd64
    • 256Mi запит / 1Gi ліміт пам'яті
    • 200m / 1000m CPU
    • Liveness + readiness + startup проби (/api/health)
    • Змінні середовища з ConfigMap (нечутливі) та Secret (чутливі)
    • Постійний том для завантажених файлів (pvc-local-file-storage.yaml — 20Gi)
    • Pod anti-affinity для високої доступності

    5. Ingress

    k8s/ingress.yaml — контролер ingress nginx з:

    • Let's Encrypt TLS (cert-manager letsencrypt-prod)
    • Підтримка WebSocket (тайм-аут проксі 3600с, анотація websocket-services)
    • Великий буфер проксі (32k — Next.js надсилає великі Link-заголовки для hreflang)
    • Обмеження швидкості (100 RPS, 50 з'єднань)
    • Ліміт розміру тіла 50MB

    6. Застосування стеку

    Налаштування Docker

    Для локальних або продакшн-розгортань на основі Docker docker-compose.yml підтримує режим k8s-postgres-fcm. Переконайтеся, що ваш .env містить DB_BACKEND_MODE=k8s-postgres-fcm та змінні для підключення PostgreSQL:

    Примітка: Стандартний docker-compose.yml не включає сервіс PostgreSQL. Ви повинні або:

    • Запустити PostgreSQL окремо (власне встановлення або docker run postgres:16-alpine)
    • Додати сервіс postgres до вашого перевизначення (docker/docker-compose.dev.yml)

    Нотатки щодо підключення FCM

    Цей режим використовує Firebase Admin виключно для push:

    1. Ініціалізація Admin SDK — застосунок Firebase Admin створюється, якщо присутні змінні середовища AUTH_FIREBASE_*. SDK потрібен для генерації FCM-токенів та надсилання push-повідомлень.
    2. Імітація Firestore — getAdminDb() повертає імітацію Firestore (ніколи не підключається до Firebase). Це контролюється тим, що shouldUseFirebaseForDatabase() повертає false.
    3. Імітація Auth — getAdminAuth() також повертає імітацію. Auth.js v5 обробляє всю автентифікацію.
    4. Клієнтський FCM — Service worker (public/firebase-messaging-sw.js) працює в браузері та завантажує Firebase compat SDK з CDN. На нього не впливає режим бекенду — він завжди підключається до Firebase для push-підписки.
    5. FCM-токени — зберігаються в таблиці fcm_tokens PostgreSQL через Server Action upsertFcmToken.
    6. Без змінних середовища Firebase = без push — Якщо пропустити всі змінні AUTH_FIREBASE_* та NEXT_PUBLIC_FIREBASE_*, ініціалізація Firebase Admin повністю пропускається. PostgreSQL продовжує працювати.

    Порівняння: k8s-postgres-fcm vs supabase-fcm

    Аспектk8s-postgres-fcmsupabase-fcm
    Хост PostgreSQLВаш K8s або локальнийХмара Supabase
    SSLНеобов'язково (DB_SSL=false за замовчуванням)Обов'язково (DB_SSL=true)
    Пул з'єднаньDB_POOL_SIZE=20 за замовчуваннямDB_POOL_SIZE=10 за замовчуванням
    Облікові даніDB_USER / DB_PASSWORDSUPABASE_URL / SUPABASE_SERVICE_KEY
    Ціль розгортанняK8s, Docker, bare metalПлатформа Supabase
    Маніфести K8sПовний набір у k8s/Не застосовно
    Тунельний хабk8s-postgres або memorymemory
    PostGISDB_ENABLE_POSTGIS=trueПотребує додатку Supabase PostGIS
    Варіант використанняПовний контроль інфраструктуриКерований хмарний PostgreSQL

    Обидва режими використовують той самий клас PostgreSQLAdapter. Єдина відмінність — хто хостить екземпляр PostgreSQL та як надаються параметри підключення.

    Пов'язана документація

    Backend modes and databases

    Database selection guide

    Environment variables

    Firebase integration

    Deployment guide

    Local setup

    bash
    
    # Вибір режиму (ОБОВ'ЯЗКОВО — платформа не запуститься без нього)
    DB_BACKEND_MODE=k8s-postgres-fcm
    
    # Підключення до PostgreSQL
    DB_HOST=localhost               # K8s: postgres.<namespace>.svc.cluster.local
    DB_PORT=5432
    DB_NAME=ring_platform
    DB_USER=ring_user
    DB_PASSWORD=ring_password_2024
    
    # Налаштування пулу з'єднань (необов'язково, показано зі значеннями за замовчуванням)
    DB_POOL_SIZE=20                 # Максимум з'єднань у пулі
    DB_TIMEOUT=30000                # Час очікування з'єднання в мс
    DB_RETRIES=3                    # Спроби повтору при збої
    DB_SSL=false                    # Встановіть true для продакшну та Supabase
    
    # PostGIS (необов'язково)
    DB_ENABLE_POSTGIS=false         # Увімкнути просторові розширення
    text
    
    ┌─────────────────────────────────────────────────┐
    │                Next.js 16 App                     │
    │                                                   │
    │  ┌──────────────────────┐  ┌──────────────────┐  │
    │  │  PostgreSQLAdapter   │  │  Firebase Admin   │  │
    │  │  (all CRUD / query)  │  │  (FCM + Apple     │  │
    │  │                      │  │   Push only)      │  │
    │  │  • Auth.js tables    │  │                   │  │
    │  │  • Entities          │  │  • getAdminDb()   │  │
    │  │  • Store products    │  │    → mock (never  │  │
    │  │  • Conversations     │  │      connects)    │  │
    │  │  • FCM tokens        │  │  • getAdminAuth() │  │
    │  │  • All business data │  │    → mock         │  │
    │  └────────┬─────────────┘  └────────┬─────────┘  │
    │           │                         │            │
    └───────────┼─────────────────────────┼────────────┘
                │                         │
                ▼                         ▼
       ┌─────────────────┐     ┌──────────────────┐
       │  PostgreSQL 16   │     │  Firebase FCM    │
       │  + PostGIS       │     │  (push only)     │
       │  StatefulSet     │     └──────────────────┘
       │  (k8s or local)  │
       └─────────────────┘
    bash
    
    # Firebase Admin SDK (серверний) — потрібен для FCM
    AUTH_FIREBASE_PROJECT_ID=your_firebase_project_id
    AUTH_FIREBASE_CLIENT_EMAIL=your_firebase_client_email
    AUTH_FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
    
    # Firebase client SDK (браузерний) — для реєстрації push через service worker
    NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_auth_domain
    NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_firebase_project_id
    NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_storage_bucket
    NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_messaging_sender_id
    NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
    NEXT_PUBLIC_FIREBASE_VAPID_KEY=your_vapid_key
    typescript
    
    const poolConfig = {
      host: config.connection.host || 'localhost',
      port: config.connection.port || 5432,
      database: config.connection.database || 'ring_platform',
      user: config.connection.username || 'ring_user',
      password: config.connection.password || 'ring_dev_password',
      max: config.options.poolSize || 20,
      idleTimeoutMillis: config.options.timeout || 30000,
      connectionTimeoutMillis: config.options.timeout || 2000,
    }
    typescript
    
    // Операції з окремими документами
    await db.findById('users', userId)
    await db.create('users', { name: 'Аліса', email: 'alice@example.com' })
    await db.update('users', userId, { name: 'Боб' })
    await db.delete('users', userId)
    
    // Запити з фільтрами, сортуванням, пагінацією
    await db.query({
      collection: 'entities',
      filters: [{ field: 'status', operator: 'eq', value: 'active' }],
      orderBy: [{ field: 'createdAt', direction: 'desc' }],
      pagination: { limit: 20, offset: 0 },
    })
    
    // Транзакції
    await db.transaction(async (txn) => {
      const order = await txn.create('orders', { total: 100 })
      await txn.update('stock', productId, { quantity: 5 })
    })
    bash
    
    TUNNEL_HUB_MODE=k8s-postgres
    yaml
    
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ring-platform-org
      labels:
        app.kubernetes.io/name: ring-platform-org
        app.kubernetes.io/part-of: ringdom
    yaml
    
    apiVersion: v1
    kind: Secret
    metadata:
      name: ring-platform-org-secrets
    type: Opaque
    stringData:
      DB_PASSWORD: <value>
      AUTH_FIREBASE_PROJECT_ID: <value>
      AUTH_FIREBASE_CLIENT_EMAIL: <value>
      AUTH_FIREBASE_PRIVATE_KEY: |
        -----BEGIN PRIVATE KEY-----
        ...
        -----END PRIVATE KEY-----
    yaml
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ring-platform-org-config
    data:
      DB_BACKEND_MODE: k8s-postgres-fcm
      DB_HOST: postgres.ring-platform-org.svc.cluster.local
      DB_PORT: "5432"
      DB_NAME: ring_platform
      DB_USER: ring_user
      DB_POOL_SIZE: "20"
      DB_TIMEOUT: "30000"
      DB_RETRIES: "3"
      DB_SSL: "false"
      NEXT_PUBLIC_FIREBASE_PROJECT_ID: <value>
    bash
    
    kubectl apply -f k8s/namespace.yaml
    kubectl apply -f k8s/postgres.yaml
    kubectl apply -f k8s/secrets.yaml
    kubectl apply -f k8s/deployment.yaml
    kubectl apply -f k8s/service.yaml
    kubectl apply -f k8s/ingress.yaml
    kubectl apply -f k8s/pvc-local-file-storage.yaml
    bash
    
    docker compose up -d