Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
navigation.docs_sidebar.audience.founderHint
navigation.docs_sidebar.audience.founderHint
navigation.docs_sidebar.audience.founderHint
k8s-postgres-fcm — это рекомендованный бэкенд-режим для продакшна и локальной разработки. PostgreSQL на Kubernetes (или локально) обрабатывает все данные приложения, тогда как Firebase Admin SDK инициализируется исключительно для FCM push-сообщений и Apple Push. Никакой привязки к Firebase для данных приложения.
TUNNEL_HUB_MODE=k8s-postgres (или in-memory хаб для локальной разработки).| Сценарий | Рекомендуемый режим |
|---|---|
| Собственный продакшн на k3s | k8s-postgres-fcm |
| Локальная разработка с PostgreSQL | k8s-postgres-fcm |
| Облачный PostgreSQL (без K8s) | supabase-fcm |
| Быстрое прототипирование / Vercel Edge | firebase-full |
| Push-уведомления нужны | любой режим — FCM опционален во всех трёх |
getAdminDb() возвращает имитацию Firestore, которая никогда не подключается.k8s-postgres-fcm — это рекомендованный бэкенд-режим для продакшна и локальной разработки. PostgreSQL на Kubernetes (или локально) обрабатывает все данные приложения, тогда как Firebase Admin SDK инициализируется исключительно для FCM push-сообщений и Apple Push. Никакой привязки к Firebase для данных приложения.
TUNNEL_HUB_MODE=k8s-postgres (или in-memory хаб для локальной разработки).| Сценарий | Рекомендуемый режим |
|---|---|
| Собственный продакшн на k3s | k8s-postgres-fcm |
| Локальная разработка с PostgreSQL | k8s-postgres-fcm |
| Облачный PostgreSQL (без K8s) | supabase-fcm |
| Быстрое прототипирование / Vercel Edge | firebase-full |
| Push-уведомления нужны | любой режим — FCM опционален во всех трёх |
getAdminDb() возвращает имитацию Firestore, которая никогда не подключается.k8s-postgres-fcm — это рекомендованный бэкенд-режим для продакшна и локальной разработки. PostgreSQL на Kubernetes (или локально) обрабатывает все данные приложения, тогда как Firebase Admin SDK инициализируется исключительно для FCM push-сообщений и Apple Push. Никакой привязки к Firebase для данных приложения.
TUNNEL_HUB_MODE=k8s-postgres (или in-memory хаб для локальной разработки).| Сценарий | Рекомендуемый режим |
|---|---|
| Собственный продакшн на k3s | k8s-postgres-fcm |
| Локальная разработка с PostgreSQL | k8s-postgres-fcm |
| Облачный PostgreSQL (без K8s) | supabase-fcm |
| Быстрое прототипирование / Vercel Edge | firebase-full |
| Push-уведомления нужны | любой режим — FCM опционален во всех трёх |
getAdminDb() возвращает имитацию Firestore, которая никогда не подключается.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 |
Требуются только если вам нужны push-уведомления. Без них платформа работает исключительно с PostgreSQL.
PostgreSQLAdapter строит конфигурацию пула из переменных окружения. Источник: lib/database/adapters/PostgreSQLAdapter.ts:
Адаптер использует гибридную JSONB-схему: большинство таблиц хранят бизнес-данные в столбце data типа JSONB вместе с общими столбцами id, created_at, updated_at. Таблицы с полностью нормализованными схемами (например, vendor_applications, vendor_profiles) перечисляют все столбцы в карте fieldMappings, поэтому конструктор запросов использует прямые ссылки на столбцы вместо data->>'field'.
Адаптер поддерживает полный контракт DatabaseService:
Запустите PostgreSQL (два варианта):
# Вариант 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Создайте .env.local из шаблона и установите:
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Примените схему:
psql -h localhost -U ring_user -d ring_platform -f data/schema.sqlЗапустите сервер разработки:
npm run devПлатформа проверяет DB_BACKEND_MODE при запуске и логирует конфигурацию бэкенда. Вы должны увидеть Database: PostgreSQL в логах запуска.
Туннельный хаб для функций реального времени:
В локальной разработке туннель по умолчанию использует in-memory хаб. Для поведения, приближенного к продакшну, установите:
Это сохраняет состояние туннеля в PostgreSQL вместо памяти процесса.
Каждый клон ring получает собственное пространство имён: k8s/namespace.yaml
Манифест k8s/postgres.yaml развёртывает PostgreSQL 16 (образ: postgres:15) как Deployment с одной репликой и сервисом ClusterIP:
postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DBplatform_org_user) и предоставляет привилегииuuid-ossp и btree_gin включены по умолчанию/data/postgres-<clone-name>postgres.<namespace>.svc.cluster.localСекреты (k8s/secrets.yaml — Opaque, stringData):
ConfigMap (k8s/secrets.yaml — секция ConfigMap):
Важно: DB_PASSWORD должен быть в Secret, а не в ConfigMap. Развёртывание ссылается на него через secretKeyRef.
k8s/deployment.yaml — приложение Next.js 16 с:
ghcr.io/connectplatform/ring:v<version>-<clone>-amd64/api/health)pvc-local-file-storage.yaml — 20Gi)k8s/ingress.yaml — контроллер ingress nginx с:
letsencrypt-prod)websocket-services)Для локальных или продакшн-развёртываний на основе Docker docker-compose.yml поддерживает режим k8s-postgres-fcm. Убедитесь, что ваш .env содержит DB_BACKEND_MODE=k8s-postgres-fcm и переменные для подключения PostgreSQL:
Примечание: Стандартный docker-compose.yml не включает сервис PostgreSQL. Вы должны либо:
docker run postgres:16-alpine)postgres в ваше переопределение (docker/docker-compose.dev.yml)Этот режим использует Firebase Admin исключительно для push:
AUTH_FIREBASE_*. SDK требуется для генерации FCM-токенов и отправки push-сообщений.getAdminDb() возвращает имитацию Firestore (никогда не подключается к Firebase). Это контролируется тем, что shouldUseFirebaseForDatabase() возвращает false.getAdminAuth() также возвращает имитацию. Auth.js v5 обрабатывает всю аутентификацию.public/firebase-messaging-sw.js) работает в браузере и загружает Firebase compat SDK с CDN. На него не влияет режим бэкенда — он всегда подключается к Firebase для push-подписки.fcm_tokens PostgreSQL через Server Action upsertFcmToken.AUTH_FIREBASE_* и NEXT_PUBLIC_FIREBASE_*, инициализация Firebase Admin полностью пропускается. PostgreSQL продолжает работать.| Аспект | k8s-postgres-fcm | supabase-fcm |
|---|---|---|
| Хост PostgreSQL | Ваш K8s или локальный | Облако Supabase |
| SSL | Опционально (DB_SSL=false по умолчанию) | Обязательно (DB_SSL=true) |
| Пул соединений | DB_POOL_SIZE=20 по умолчанию | DB_POOL_SIZE=10 по умолчанию |
| Учётные данные | DB_USER / DB_PASSWORD | SUPABASE_URL / SUPABASE_SERVICE_KEY |
| Цель развёртывания | K8s, Docker, bare metal | Платформа Supabase |
| Манифесты K8s | Полный набор в k8s/ | Не применимо |
| Туннельный хаб | k8s-postgres или memory | memory |
| PostGIS | DB_ENABLE_POSTGIS=true | Требует аддона Supabase PostGIS |
| Вариант использования | Полный контроль инфраструктуры | Управляемый облачный PostgreSQL |
Оба режима используют один и тот же класс PostgreSQLAdapter. Единственное отличие — кто хостит экземпляр PostgreSQL и как предоставляются параметры подключения.
# Выбор режима (ОБЯЗАТЕЛЬНО — платформа не запустится без него)
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 # Включить пространственные расширения
┌─────────────────────────────────────────────────┐
│ 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) │
└─────────────────┘
# 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
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,
}
// Операции с отдельными документами
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 })
})
TUNNEL_HUB_MODE=k8s-postgres
apiVersion: v1
kind: Namespace
metadata:
name: ring-platform-org
labels:
app.kubernetes.io/name: ring-platform-org
app.kubernetes.io/part-of: ringdom
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-----
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>
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
docker compose up -dDB_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 |
Требуются только если вам нужны push-уведомления. Без них платформа работает исключительно с PostgreSQL.
PostgreSQLAdapter строит конфигурацию пула из переменных окружения. Источник: lib/database/adapters/PostgreSQLAdapter.ts:
Адаптер использует гибридную JSONB-схему: большинство таблиц хранят бизнес-данные в столбце data типа JSONB вместе с общими столбцами id, created_at, updated_at. Таблицы с полностью нормализованными схемами (например, vendor_applications, vendor_profiles) перечисляют все столбцы в карте fieldMappings, поэтому конструктор запросов использует прямые ссылки на столбцы вместо data->>'field'.
Адаптер поддерживает полный контракт DatabaseService:
Запустите PostgreSQL (два варианта):
# Вариант 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Создайте .env.local из шаблона и установите:
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Примените схему:
psql -h localhost -U ring_user -d ring_platform -f data/schema.sqlЗапустите сервер разработки:
npm run devПлатформа проверяет DB_BACKEND_MODE при запуске и логирует конфигурацию бэкенда. Вы должны увидеть Database: PostgreSQL в логах запуска.
Туннельный хаб для функций реального времени:
В локальной разработке туннель по умолчанию использует in-memory хаб. Для поведения, приближенного к продакшну, установите:
Это сохраняет состояние туннеля в PostgreSQL вместо памяти процесса.
Каждый клон ring получает собственное пространство имён: k8s/namespace.yaml
Манифест k8s/postgres.yaml развёртывает PostgreSQL 16 (образ: postgres:15) как Deployment с одной репликой и сервисом ClusterIP:
postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DBplatform_org_user) и предоставляет привилегииuuid-ossp и btree_gin включены по умолчанию/data/postgres-<clone-name>postgres.<namespace>.svc.cluster.localСекреты (k8s/secrets.yaml — Opaque, stringData):
ConfigMap (k8s/secrets.yaml — секция ConfigMap):
Важно: DB_PASSWORD должен быть в Secret, а не в ConfigMap. Развёртывание ссылается на него через secretKeyRef.
k8s/deployment.yaml — приложение Next.js 16 с:
ghcr.io/connectplatform/ring:v<version>-<clone>-amd64/api/health)pvc-local-file-storage.yaml — 20Gi)k8s/ingress.yaml — контроллер ingress nginx с:
letsencrypt-prod)websocket-services)Для локальных или продакшн-развёртываний на основе Docker docker-compose.yml поддерживает режим k8s-postgres-fcm. Убедитесь, что ваш .env содержит DB_BACKEND_MODE=k8s-postgres-fcm и переменные для подключения PostgreSQL:
Примечание: Стандартный docker-compose.yml не включает сервис PostgreSQL. Вы должны либо:
docker run postgres:16-alpine)postgres в ваше переопределение (docker/docker-compose.dev.yml)Этот режим использует Firebase Admin исключительно для push:
AUTH_FIREBASE_*. SDK требуется для генерации FCM-токенов и отправки push-сообщений.getAdminDb() возвращает имитацию Firestore (никогда не подключается к Firebase). Это контролируется тем, что shouldUseFirebaseForDatabase() возвращает false.getAdminAuth() также возвращает имитацию. Auth.js v5 обрабатывает всю аутентификацию.public/firebase-messaging-sw.js) работает в браузере и загружает Firebase compat SDK с CDN. На него не влияет режим бэкенда — он всегда подключается к Firebase для push-подписки.fcm_tokens PostgreSQL через Server Action upsertFcmToken.AUTH_FIREBASE_* и NEXT_PUBLIC_FIREBASE_*, инициализация Firebase Admin полностью пропускается. PostgreSQL продолжает работать.| Аспект | k8s-postgres-fcm | supabase-fcm |
|---|---|---|
| Хост PostgreSQL | Ваш K8s или локальный | Облако Supabase |
| SSL | Опционально (DB_SSL=false по умолчанию) | Обязательно (DB_SSL=true) |
| Пул соединений | DB_POOL_SIZE=20 по умолчанию | DB_POOL_SIZE=10 по умолчанию |
| Учётные данные | DB_USER / DB_PASSWORD | SUPABASE_URL / SUPABASE_SERVICE_KEY |
| Цель развёртывания | K8s, Docker, bare metal | Платформа Supabase |
| Манифесты K8s | Полный набор в k8s/ | Не применимо |
| Туннельный хаб | k8s-postgres или memory | memory |
| PostGIS | DB_ENABLE_POSTGIS=true | Требует аддона Supabase PostGIS |
| Вариант использования | Полный контроль инфраструктуры | Управляемый облачный PostgreSQL |
Оба режима используют один и тот же класс PostgreSQLAdapter. Единственное отличие — кто хостит экземпляр PostgreSQL и как предоставляются параметры подключения.
# Выбор режима (ОБЯЗАТЕЛЬНО — платформа не запустится без него)
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 # Включить пространственные расширения
┌─────────────────────────────────────────────────┐
│ 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) │
└─────────────────┘
# 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
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,
}
// Операции с отдельными документами
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 })
})
TUNNEL_HUB_MODE=k8s-postgres
apiVersion: v1
kind: Namespace
metadata:
name: ring-platform-org
labels:
app.kubernetes.io/name: ring-platform-org
app.kubernetes.io/part-of: ringdom
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-----
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>
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
docker compose up -dDB_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 |
Требуются только если вам нужны push-уведомления. Без них платформа работает исключительно с PostgreSQL.
PostgreSQLAdapter строит конфигурацию пула из переменных окружения. Источник: lib/database/adapters/PostgreSQLAdapter.ts:
Адаптер использует гибридную JSONB-схему: большинство таблиц хранят бизнес-данные в столбце data типа JSONB вместе с общими столбцами id, created_at, updated_at. Таблицы с полностью нормализованными схемами (например, vendor_applications, vendor_profiles) перечисляют все столбцы в карте fieldMappings, поэтому конструктор запросов использует прямые ссылки на столбцы вместо data->>'field'.
Адаптер поддерживает полный контракт DatabaseService:
Запустите PostgreSQL (два варианта):
# Вариант 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Создайте .env.local из шаблона и установите:
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Примените схему:
psql -h localhost -U ring_user -d ring_platform -f data/schema.sqlЗапустите сервер разработки:
npm run devПлатформа проверяет DB_BACKEND_MODE при запуске и логирует конфигурацию бэкенда. Вы должны увидеть Database: PostgreSQL в логах запуска.
Туннельный хаб для функций реального времени:
В локальной разработке туннель по умолчанию использует in-memory хаб. Для поведения, приближенного к продакшну, установите:
Это сохраняет состояние туннеля в PostgreSQL вместо памяти процесса.
Каждый клон ring получает собственное пространство имён: k8s/namespace.yaml
Манифест k8s/postgres.yaml развёртывает PostgreSQL 16 (образ: postgres:15) как Deployment с одной репликой и сервисом ClusterIP:
postgres-config) — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DBplatform_org_user) и предоставляет привилегииuuid-ossp и btree_gin включены по умолчанию/data/postgres-<clone-name>postgres.<namespace>.svc.cluster.localСекреты (k8s/secrets.yaml — Opaque, stringData):
ConfigMap (k8s/secrets.yaml — секция ConfigMap):
Важно: DB_PASSWORD должен быть в Secret, а не в ConfigMap. Развёртывание ссылается на него через secretKeyRef.
k8s/deployment.yaml — приложение Next.js 16 с:
ghcr.io/connectplatform/ring:v<version>-<clone>-amd64/api/health)pvc-local-file-storage.yaml — 20Gi)k8s/ingress.yaml — контроллер ingress nginx с:
letsencrypt-prod)websocket-services)Для локальных или продакшн-развёртываний на основе Docker docker-compose.yml поддерживает режим k8s-postgres-fcm. Убедитесь, что ваш .env содержит DB_BACKEND_MODE=k8s-postgres-fcm и переменные для подключения PostgreSQL:
Примечание: Стандартный docker-compose.yml не включает сервис PostgreSQL. Вы должны либо:
docker run postgres:16-alpine)postgres в ваше переопределение (docker/docker-compose.dev.yml)Этот режим использует Firebase Admin исключительно для push:
AUTH_FIREBASE_*. SDK требуется для генерации FCM-токенов и отправки push-сообщений.getAdminDb() возвращает имитацию Firestore (никогда не подключается к Firebase). Это контролируется тем, что shouldUseFirebaseForDatabase() возвращает false.getAdminAuth() также возвращает имитацию. Auth.js v5 обрабатывает всю аутентификацию.public/firebase-messaging-sw.js) работает в браузере и загружает Firebase compat SDK с CDN. На него не влияет режим бэкенда — он всегда подключается к Firebase для push-подписки.fcm_tokens PostgreSQL через Server Action upsertFcmToken.AUTH_FIREBASE_* и NEXT_PUBLIC_FIREBASE_*, инициализация Firebase Admin полностью пропускается. PostgreSQL продолжает работать.| Аспект | k8s-postgres-fcm | supabase-fcm |
|---|---|---|
| Хост PostgreSQL | Ваш K8s или локальный | Облако Supabase |
| SSL | Опционально (DB_SSL=false по умолчанию) | Обязательно (DB_SSL=true) |
| Пул соединений | DB_POOL_SIZE=20 по умолчанию | DB_POOL_SIZE=10 по умолчанию |
| Учётные данные | DB_USER / DB_PASSWORD | SUPABASE_URL / SUPABASE_SERVICE_KEY |
| Цель развёртывания | K8s, Docker, bare metal | Платформа Supabase |
| Манифесты K8s | Полный набор в k8s/ | Не применимо |
| Туннельный хаб | k8s-postgres или memory | memory |
| PostGIS | DB_ENABLE_POSTGIS=true | Требует аддона Supabase PostGIS |
| Вариант использования | Полный контроль инфраструктуры | Управляемый облачный PostgreSQL |
Оба режима используют один и тот же класс PostgreSQLAdapter. Единственное отличие — кто хостит экземпляр PostgreSQL и как предоставляются параметры подключения.
# Выбор режима (ОБЯЗАТЕЛЬНО — платформа не запустится без него)
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 # Включить пространственные расширения
┌─────────────────────────────────────────────────┐
│ 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) │
└─────────────────┘
# 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
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,
}
// Операции с отдельными документами
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 })
})
TUNNEL_HUB_MODE=k8s-postgres
apiVersion: v1
kind: Namespace
metadata:
name: ring-platform-org
labels:
app.kubernetes.io/name: ring-platform-org
app.kubernetes.io/part-of: ringdom
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-----
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>
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
docker compose up -d