Files
IdP/apps/docs/lib/docs-pages.ts
2026-06-24 15:06:01 +03:00

800 lines
33 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export type DocBlock =
| { type: 'paragraph'; text: string }
| { type: 'list'; items: string[] }
| { type: 'code'; language: string; code: string; title?: string }
| { type: 'callout'; variant: 'info' | 'warning' | 'tip'; title: string; text: string }
| { type: 'table'; headers: string[]; rows: string[][] }
| { type: 'oauth-examples' }
| { type: 'auth-login-examples' }
| { type: 'auth-ldap-examples' }
| { type: 'api-reference' };
export interface DocSection {
id: string;
title: string;
blocks: DocBlock[];
}
export interface DocPage {
slug: string;
title: string;
description: string;
sections: DocSection[];
}
export const docPages: DocPage[] = [
{
slug: 'getting-started',
title: 'Начало работы',
description: 'Обзор экосистемы Identity Provider, порты сервисов и быстрый локальный запуск.',
sections: [
{
id: 'overview',
title: 'Обзор',
blocks: [
{
type: 'paragraph',
text: 'Lendry ID — enterprise Identity Provider в стиле Yandex ID: единый аккаунт, OAuth 2.0, LDAP/LDAPS, семейные группы, чат, PIN-блокировка сессий и админ-панель. Монорепозиторий состоит из NestJS-микросервисов, Go-сервисов и Next.js-приложений.'
},
{
type: 'callout',
variant: 'info',
title: 'Домен',
text: 'Production-домен: id.lendry.ru. Локально API доступен на порту 3000, frontend — 3002, документация — 3003.'
}
]
},
{
id: 'requirements',
title: 'Требования',
blocks: [
{
type: 'list',
items: [
'Node.js 20.19+ и npm 10+',
'Docker и Docker Compose',
'PostgreSQL 16, Redis 7, RabbitMQ 3.13, MinIO',
'Go 1.23+ (для локальной сборки media-ws и ldap-auth)'
]
}
]
},
{
id: 'quick-start',
title: 'Быстрый запуск',
blocks: [
{
type: 'callout',
variant: 'tip',
title: 'Production на сервере',
text: 'Для развёртывания на Linux с Docker, Nginx и SSL используйте скрипт install.sh — подробности в разделе «Развёртывание на сервере».'
},
{
type: 'code',
language: 'bash',
title: 'Сервер (рекомендуется)',
code: `git clone https://git.lendry.ru/lendry/IdP.git
cd IdP
chmod +x install.sh
./install.sh`
},
{
type: 'code',
language: 'bash',
title: 'Локально через Docker',
code: `git clone <repository-url> lendry-id
cd lendry-id
docker compose up -d --build
# Проверка
curl http://localhost:3000/health
curl http://localhost:3003/docs/getting-started`
},
{
type: 'table',
headers: ['Сервис', 'Порт', 'Назначение'],
rows: [
['api-gateway', '3000', 'REST API, Swagger'],
['sso-core', '3001 / 50051', 'Бизнес-логика, gRPC'],
['frontend', '3002', 'UI входа и профиля'],
['docs', '3003', 'Документация'],
['media-ws', '8085', 'WebSocket уведомлений и чата'],
['ldap-auth', '8086', 'LDAP/LDAPS аутентификация'],
['MinIO', '9000 / 9001', 'Хранилище медиа'],
['RabbitMQ', '5672 / 15672', 'Очереди событий']
]
}
]
},
{
id: 'first-user',
title: 'Первый пользователь',
blocks: [
{
type: 'paragraph',
text: 'Первый зарегистрированный пользователь автоматически получает права супер-администратора (isSuperAdmin). Race condition защищена Redis-lock и Serializable-транзакцией PostgreSQL.'
},
{
type: 'code',
language: 'bash',
title: 'Регистрация через API',
code: `curl -X POST http://localhost:3000/auth/register \\
-H "Content-Type: application/json" \\
-d '{"displayName":"Администратор","email":"admin@example.com","password":"SecurePass123"}'`
}
]
}
]
},
{
slug: 'architecture',
title: 'Архитектура',
description: 'Схема микросервисов, потоки данных и технологический стек.',
sections: [
{
id: 'stack',
title: 'Технологический стек',
blocks: [
{
type: 'table',
headers: ['Компонент', 'Технологии'],
rows: [
['sso-core', 'NestJS, Prisma 7+, PostgreSQL, gRPC'],
['api-gateway', 'NestJS, REST, Swagger'],
['frontend / docs', 'Next.js App Router, React, Tailwind, shadcn/ui'],
['media-ws', 'Go, Gorilla WebSocket, Redis, RabbitMQ'],
['ldap-auth', 'Go, go-ldap'],
['Инфраструктура', 'Docker, Redis, RabbitMQ, MinIO']
]
}
]
},
{
id: 'flow',
title: 'Поток запросов',
blocks: [
{
type: 'paragraph',
text: 'Клиент (браузер или стороннее приложение) обращается к api-gateway по REST. Gateway проксирует вызовы в sso-core через gRPC. Медиафайлы загружаются в MinIO через presigned URL. Realtime-события (уведомления, чат) доставляются через media-ws по WebSocket с JWT-авторизацией.'
},
{
type: 'list',
items: [
'JWT access + refresh tokens для сессий',
'PIN-код: при включении сессия создаётся с pinVerified=false',
'SystemSetting — динамические бизнес-правила без хардкода во frontend',
'LinkedAccount — привязка LDAP, Google, Yandex и других провайдеров'
]
}
]
}
]
},
{
slug: 'deployment',
title: 'Развёртывание на сервере',
description: 'Автоматическая установка через install.sh: Docker, Nginx, SSL и отдельные домены для каждого сервиса.',
sections: [
{
id: 'install-script',
title: '1. Автоматическая установка (install.sh)',
blocks: [
{
type: 'paragraph',
text: 'Скрипт install.sh разворачивает весь стек одной командой: Docker, Nginx, генерация .env, reverse proxy. Поддерживает локальную сеть без интернета (--intranet), самоподписанный HTTPS и Let\'s Encrypt для публичных серверов. На Windows Server Nginx запускается в Docker-контейнере.'
},
{
type: 'callout',
variant: 'tip',
title: 'Локальная сеть (AD, .lpr, .local)',
text: 'Если домены только внутри LAN и Let\'s Encrypt недоступен — используйте ./install.sh --intranet --ssl none. Доступ: http://api.idpmvk.lpr без выхода в интернет.'
},
{
type: 'code',
language: 'bash',
title: 'Быстрый старт',
code: `git clone https://git.lendry.ru/lendry/IdP.git
cd IdP
chmod +x install.sh
./install.sh`
},
{
type: 'code',
language: 'bash',
title: 'Production без вопросов',
code: `./install.sh --install --yes \\
--api-domain api.id.example.ru \\
--frontend-domain id.example.ru \\
--docs-domain docs.example.ru \\
--email admin@example.ru`
},
{
type: 'code',
language: 'bash',
title: 'Установка без клонирования',
code: `curl -fsSL https://git.lendry.ru/lendry/IdP/raw/branch/main/install.sh | bash`
}
]
},
{
id: 'intranet-network',
title: '2. Локальная сеть (без интернета)',
blocks: [
{
type: 'paragraph',
text: 'Для корпоративной LAN, Windows Server и внутренних доменов (например idpmvk.lpr) не нужен доступ из интернета и Let\'s Encrypt. Скрипт настраивает Nginx на HTTP или HTTPS с самоподписанным сертификатом (openssl). На Windows Server Nginx работает в Docker (профиль proxy).'
},
{
type: 'code',
language: 'bash',
title: 'Рекомендуемая команда (HTTP)',
code: `./install.sh --intranet --install --yes --offline \\
--api-domain api.idpmvk.lpr \\
--frontend-domain id.idpmvk.lpr \\
--docs-domain docs.idpmvk.lpr \\
--ssl none`
},
{
type: 'code',
language: 'bash',
title: 'HTTPS самоподписанный (опционально)',
code: `./install.sh --intranet --install --yes --offline \\
--api-domain api.idpmvk.lpr \\
--frontend-domain id.idpmvk.lpr \\
--docs-domain docs.idpmvk.lpr \\
--ssl selfsigned`
},
{
type: 'table',
headers: ['SSL_TYPE', 'Описание', 'Интернет'],
rows: [
['none', 'http://api.idpmvk.lpr — без сертификатов', 'Не нужен'],
['selfsigned', 'https://... — openssl, предупреждение браузера', 'Не нужен'],
['letsencrypt', 'Публичный HTTPS', 'Нужен']
]
},
{
type: 'callout',
variant: 'warning',
title: 'DNS на клиентах',
text: 'Пропишите A-записи во внутреннем DNS Active Directory или файл hosts на каждом ПК: IP-сервера → api.idpmvk.lpr, id.idpmvk.lpr, docs.idpmvk.lpr. Windows: C:\\Windows\\System32\\drivers\\etc\\hosts'
},
{
type: 'code',
language: 'text',
title: 'Пример hosts (Windows / Linux)',
code: `192.168.1.10 api.idpmvk.lpr
192.168.1.10 id.idpmvk.lpr
192.168.1.10 docs.idpmvk.lpr`
},
{
type: 'callout',
variant: 'info',
title: 'Windows Server',
text: 'Запускайте install.sh из Git Bash или WSL. Docker Desktop / Docker Engine должен быть установлен заранее (--offline). Nginx поднимается контейнером на портах 80 и 443.'
}
]
},
{
id: 'server-requirements',
title: '3. Требования к серверу',
blocks: [
{
type: 'list',
items: [
'Ubuntu 22.04+ / Debian 12+ / Fedora / RHEL (Linux)',
'Минимум 4 GB RAM, 2 vCPU, 40 GB SSD',
'Отдельные домены или поддомены для API, Frontend и Docs (A-запись → IP сервера)',
'Открытые порты 80 и 443 (остальные сервисы доступны только через Nginx на localhost)',
'Права sudo/root для установки Docker и Nginx'
]
}
]
},
{
id: 'domains',
title: '4. Отдельные домены для сервисов',
blocks: [
{
type: 'paragraph',
text: 'При установке и при повторной настройке (--configure-domains) можно указать свой домен для каждого компонента. Текущие значения подставляются по умолчанию — достаточно изменить только нужные.'
},
{
type: 'table',
headers: ['Сервис', 'Параметр', 'Пример', 'Nginx → порт'],
rows: [
['API / Swagger', '--api-domain', 'api.id.example.ru', '127.0.0.1:3000'],
['Frontend (UI)', '--frontend-domain', 'id.example.ru', '127.0.0.1:3002'],
['Документация', '--docs-domain', 'docs.example.ru', '127.0.0.1:3003'],
['WebSocket', '--ws-domain', 'пусто = API + /ws', '127.0.0.1:8085'],
['MinIO S3', '--minio-domain', 'опционально', '127.0.0.1:9000'],
['MinIO Console', '--minio-console-domain', 'опционально', '127.0.0.1:9001']
]
},
{
type: 'callout',
variant: 'info',
title: 'WebSocket',
text: 'Если --ws-domain не указан, WebSocket проксируется на том же домене, что и API, по пути /ws (wss://api.example.ru/ws). Для отдельного домена укажите --ws-domain ws.example.ru.'
}
]
},
{
id: 'install-menu',
title: '5. Меню управления (повторный запуск)',
blocks: [
{
type: 'paragraph',
text: 'Если файл .env уже существует, повторный вызов ./install.sh открывает интерактивное меню — как у панелей с автоматическим reverse proxy.'
},
{
type: 'table',
headers: ['Пункт', 'Действие'],
rows: [
['1', 'Полная установка / переустановка стека'],
['2', 'Настроить или изменить домены, Nginx и SSL'],
['3', 'Обновить SSL-сертификаты (Let\'s Encrypt)'],
['4', 'Перезапуск / пересборка контейнеров'],
['5', 'Статус сервисов и проверка Nginx'],
['6', 'Удалить конфиги Nginx IdP'],
['0', 'Выход']
]
},
{
type: 'code',
language: 'bash',
title: 'Смена доменов после установки',
code: `# Интерактивно
./install.sh --configure-domains
# Или через меню
./install.sh
# → пункт 2
# Пример: вынести Swagger на отдельный домен
./install.sh --configure-domains \\
--api-domain swagger.id.example.ru \\
--frontend-domain id.example.ru \\
--docs-domain docs.example.ru`
}
]
},
{
id: 'install-commands',
title: '6. Команды и флаги',
blocks: [
{
type: 'table',
headers: ['Команда / флаг', 'Описание'],
rows: [
['./install.sh', 'Интерактивное меню (если .env есть) или первая установка'],
['./install.sh --install', 'Полная установка'],
['./install.sh --configure-domains', 'Изменить домены и пересобрать frontend/docs'],
['./install.sh --renew-ssl', 'Обновить сертификаты Let\'s Encrypt'],
['./install.sh --restart', 'docker compose up -d --build'],
['./install.sh --status', 'Статус контейнеров и доменов'],
['./install.sh --intranet', 'Локальная сеть, HTTP по умолчанию'],
['./install.sh --ssl none', 'Только HTTP через Nginx'],
['./install.sh --ssl selfsigned', 'HTTPS самоподписанный'],
['./install.sh --offline', 'Не скачивать Docker из интернета'],
['./install.sh --nginx-mode docker', 'Nginx в контейнере (Windows)'],
['./install.sh --local', 'localhost:3000/3002/3003 без Nginx'],
['./install.sh --yes', 'Без интерактивных вопросов'],
['FORCE_ENV=1 ./install.sh', 'Пересоздать .env с новыми секретами']
]
},
{
type: 'code',
language: 'bash',
title: 'Локальная разработка без доменов',
code: `./install.sh --local
# или
./install.sh --install --local --yes`
}
]
},
{
id: 'install-automation',
title: '7. Что делает скрипт автоматически',
blocks: [
{
type: 'list',
items: [
'Устанавливает curl, git, openssl, jq (apt/dnf)',
'Устанавливает Docker и Docker Compose v2 (get.docker.com)',
'Добавляет пользователя в группу docker',
'Генерирует .env: пароли PostgreSQL, RabbitMQ, MinIO, JWT-секреты, DATA_ENCRYPTION_KEY',
'Создаёт docker-compose.override.yml — привязка портов к 127.0.0.1',
'Устанавливает Nginx и Certbot, настраивает UFW (80, 443)',
'Генерирует конфиги /etc/nginx/sites-available/lendry-id-*.conf',
'Получает SSL через certbot (webroot), включает certbot.timer',
'Запускает docker compose up -d --build и ждёт health сервисов',
'При смене доменов пересобирает frontend и docs с новыми NEXT_PUBLIC_* URL'
]
},
{
type: 'callout',
variant: 'warning',
title: 'Секреты',
text: 'Файл .env не коммитьте в git. Сохраните его в надёжном месте после первой установки. FORCE_ENV=1 генерирует новые секреты и сбрасывает старые.'
}
]
},
{
id: 'clone-config',
title: '8. Переменные .env (генерируются автоматически)',
blocks: [
{
type: 'paragraph',
text: 'install.sh создаёт и обновляет .env на основе .env.example. При ручном редактировании не меняйте секреты без необходимости — для смены доменов используйте ./install.sh --configure-domains.'
},
{
type: 'code',
language: 'bash',
title: 'Ключевые переменные .env',
code: `# Домены (без протокола)
DOMAIN_API=api.id.example.ru
DOMAIN_FRONTEND=id.example.ru
DOMAIN_DOCS=docs.example.ru
DOMAIN_WS=
# Публичные URL (скрипт подставляет https://)
PUBLIC_API_URL=https://api.id.example.ru
PUBLIC_FRONTEND_URL=https://id.example.ru
PUBLIC_DOCS_URL=https://docs.example.ru
PUBLIC_WS_URL=wss://api.id.example.ru/ws
USE_NGINX_SSL=true
CERTBOT_EMAIL=admin@example.ru
INSTALL_MODE=production
# Секреты — генерируются install.sh
JWT_ACCESS_SECRET=...
JWT_REFRESH_SECRET=...
DATA_ENCRYPTION_KEY=...
POSTGRES_PASSWORD=...
RABBITMQ_DEFAULT_PASS=...
MINIO_ROOT_PASSWORD=...`
}
]
},
{
id: 'env-services',
title: '9. Переменные окружения сервисов',
blocks: [
{
type: 'table',
headers: ['Сервис', 'Ключевые переменные'],
rows: [
['sso-core', 'DATABASE_URL, JWT_*_SECRET, DATA_ENCRYPTION_KEY, REDIS_URL, RABBITMQ_URL, MINIO_*, LDAP_AUTH_URL, PUBLIC_API_URL'],
['api-gateway', 'SSO_CORE_GRPC_URL, JWT_ACCESS_SECRET, PUBLIC_API_URL, MINIO_*'],
['frontend', 'NEXT_PUBLIC_API_URL, NEXT_PUBLIC_WS_URL (build args + runtime)'],
['docs', 'NEXT_PUBLIC_API_URL, INTERNAL_API_URL'],
['media-ws', 'REDIS_ADDR, RABBITMQ_URL, JWT_ACCESS_SECRET'],
['ldap-auth', 'PORT=8086']
]
}
]
},
{
id: 'after-install',
title: '10. После установки',
blocks: [
{
type: 'table',
headers: ['Ресурс', 'URL (production)'],
rows: [
['API / Swagger', 'https://<DOMAIN_API>/api'],
['Frontend', 'https://<DOMAIN_FRONTEND>'],
['Документация', 'https://<DOMAIN_DOCS>/docs'],
['WebSocket', 'wss://<DOMAIN_API>/ws или wss://<DOMAIN_WS>/ws'],
['MinIO Console', 'только localhost:9001 (если не задан домен)'],
['RabbitMQ UI', 'только localhost:15672']
]
},
{
type: 'callout',
variant: 'tip',
title: 'Первый пользователь',
text: 'Первый зарегистрированный пользователь автоматически становится супер-администратором. Название проекта (PROJECT_NAME) и LDAP настраиваются в админке: /admin/settings.'
},
{
type: 'code',
language: 'bash',
title: 'Полезные команды',
code: `docker compose ps
docker compose logs -f api-gateway sso-core
./install.sh --status
./install.sh --renew-ssl`
}
]
},
{
id: 'migrations',
title: '11. Миграции и seed',
blocks: [
{
type: 'code',
language: 'bash',
code: `# Prisma migrate внутри контейнера sso-core
docker compose exec sso-core npx prisma migrate deploy
# Seed системных настроек (PROJECT_NAME, LDAP_*, PIN_*)
docker compose restart sso-core`
},
{
type: 'callout',
variant: 'info',
title: 'SystemSetting',
text: 'Название проекта (PROJECT_NAME), tagline и LDAP-параметры настраиваются в админке. Frontend и docs подтягивают PROJECT_NAME через GET /settings/public.'
}
]
},
{
id: 'backup',
title: '12. Резервное копирование',
blocks: [
{
type: 'list',
items: [
'PostgreSQL: pg_dump lendry_id ежедневно',
'MinIO: mc mirror или snapshot volume minio_data',
'Redis: RDB/AOF snapshots при необходимости сохранения сессий',
'Секреты .env — хранить в vault, не в репозитории'
]
},
{
type: 'code',
language: 'bash',
code: `docker compose exec postgres pg_dump -U lendry lendry_id > backup-$(date +%F).sql`
}
]
},
{
id: 'monitoring',
title: '13. Мониторинг и обновления',
blocks: [
{
type: 'list',
items: [
'Health: GET /health на api-gateway и sso-core',
'Логи: docker compose logs -f --tail=200',
'Обновление кода: git pull && ./install.sh --restart',
'Смена доменов: ./install.sh --configure-domains',
'SSL: ./install.sh --renew-ssl или автоматически через certbot.timer'
]
}
]
}
]
},
{
slug: 'authentication',
title: 'Аутентификация',
description: 'Способы входа: пароль, OTP, LDAP, PIN и refresh-сессии.',
sections: [
{
id: 'flows',
title: 'Сценарии входа',
blocks: [
{
type: 'table',
headers: ['Сценарий', 'Endpoint', 'Описание'],
rows: [
['Identifier-first', 'POST /auth/identify', 'Проверка существования пользователя и способа входа'],
['Passwordless OTP', 'POST /auth/otp/send + verify', '6-значный код на почту/телефон'],
['Пароль', 'POST /auth/login/password', 'Логин + пароль или tempAuthToken после OTP'],
['LDAP/LDAPS', 'POST /auth/ldap/login', 'Корпоративный вход (требует LDAP_ENABLED)'],
['PIN', 'POST /auth/pin/verify', 'Разблокировка сессии после входа с PIN']
]
}
]
},
{
id: 'login-example',
title: 'Примеры входа по паролю',
blocks: [
{
type: 'paragraph',
text: 'Endpoint POST /auth/login/password принимает login (почта, телефон или username), password и метаданные устройства. Ниже — готовые примеры на разных языках.'
},
{ type: 'auth-login-examples' },
{
type: 'callout',
variant: 'info',
title: 'PIN-блокировка',
text: 'Если у пользователя включён PIN, ответ содержит requiresPin=true и ограниченную сессию. Полный JWT выдаётся после POST /auth/pin/verify.'
}
]
}
]
},
{
slug: 'oauth',
title: 'OAuth 2.0',
description: 'Регистрация приложения, Authorization Code Flow, scopes и примеры на разных языках.',
sections: [
{
id: 'register-app',
title: 'Регистрация OAuth-приложения',
blocks: [
{
type: 'list',
items: [
'Войдите как супер-администратор в админ-панель',
'Перейдите в RBAC → OAuth приложения',
'Создайте клиент: name, redirectUris, scopes (openid, profile, email)',
'Confidential-клиент получит client_secret один раз — сохраните его'
]
}
]
},
{
id: 'flow',
title: 'Authorization Code Flow',
blocks: [
{
type: 'paragraph',
text: '1) Пользователь авторизуется в Lendry ID. 2) Ваше приложение перенаправляет на GET /oauth/authorize с clientId, redirectUri, scope, userId. 3) IdP возвращает redirectUrl с authorization code. 4) Backend обменивает code на токены через POST /oauth/token. 5) GET /oauth/userinfo возвращает профиль.'
},
{
type: 'callout',
variant: 'warning',
title: 'Безопасность',
text: 'client_secret никогда не храните во frontend. Обмен code → token выполняйте только на сервере.'
}
]
},
{
id: 'examples',
title: 'Примеры интеграции',
blocks: [{ type: 'oauth-examples' }]
},
{
id: 'scopes',
title: 'Scopes',
blocks: [
{
type: 'table',
headers: ['Scope', 'Доступ'],
rows: [
['openid', 'Идентификатор пользователя (sub)'],
['profile', 'displayName, avatar, bio'],
['email', 'Основная и резервная почта'],
['phone', 'Телефоны пользователя']
]
}
]
}
]
},
{
slug: 'ldap',
title: 'LDAP / LDAPS',
description: 'Корпоративный вход через Active Directory.',
sections: [
{
id: 'setup',
title: 'Настройка в админке',
blocks: [
{
type: 'table',
headers: ['Ключ SystemSetting', 'Описание'],
rows: [
['LDAP_ENABLED', 'Включить кнопку «Войти через LDAP»'],
['LDAP_USE_LDAPS', 'LDAPS на порту 636'],
['LDAP_HOST', 'DC-1.domain.local,DC-2.domain.local'],
['LDAP_BIND_USERNAME', 'Логин сервисной УЗ (mvkadmin)'],
['LDAP_BASE_DN', 'OU=Users,DC=domain,DC=local'],
['LDAP_BIND_PASSWORD', 'Пароль сервисной УЗ']
]
}
]
},
{
id: 'login',
title: 'Примеры LDAP-входа',
blocks: [
{
type: 'paragraph',
text: 'Endpoint POST /auth/ldap/login доступен при включённой настройке LDAP_ENABLED.'
},
{ type: 'auth-ldap-examples' }
]
}
]
},
{
slug: 'sessions',
title: 'Сессии и PIN',
description: 'Управление устройствами, PIN-блокировка и отзыв сессий.',
sections: [
{
id: 'pin',
title: 'PIN-код',
blocks: [
{
type: 'paragraph',
text: 'PIN хранится как bcrypt hash. Таймаут блокировки читается из SystemSetting PIN_LOCK_TIMEOUT_MINUTES — значение не захардкожено во frontend.'
}
]
},
{
id: 'devices',
title: 'Устройства и сессии',
blocks: [
{
type: 'list',
items: [
'GET /security/users/{userId}/devices — список устройств',
'POST /security/users/{userId}/sessions/{sessionId}/revoke — выход с устройства',
'POST /security/users/{userId}/revoke-all-sessions — выход везде'
]
}
]
}
]
},
{
slug: 'family-chat',
title: 'Семья и чат',
description: 'Семейные группы, приглашения, чат и realtime через WebSocket.',
sections: [
{
id: 'family',
title: 'Семейные группы',
blocks: [
{
type: 'paragraph',
text: 'Пользователь создаёт семью, приглашает участников по email/телефону/логину. Лимиты (max family members) берутся из SystemSetting.'
}
]
},
{
id: 'chat',
title: 'Чат и WebSocket',
blocks: [
{
type: 'list',
items: [
'REST: /chat/groups/{groupId}/rooms, /chat/rooms/{roomId}/messages',
'WebSocket: ws://localhost:8085/ws с JWT в query или заголовке',
'Медиа чата: presigned upload + защищённый stream с Authorization'
]
}
]
}
]
},
{
slug: 'api-reference',
title: 'Справочник API',
description: 'Полный список REST endpoints Lendry ID API. Swagger: /api на api-gateway.',
sections: [
{
id: 'endpoints',
title: 'Endpoints',
blocks: [{ type: 'api-reference' }]
},
{
id: 'swagger',
title: 'OpenAPI / Swagger',
blocks: [
{
type: 'paragraph',
text: 'Интерактивная документация доступна по адресу http://localhost:3000/api (Swagger UI). Все DTO и схемы генерируются автоматически из NestJS decorators.'
}
]
}
]
}
];
export function getDocPage(slug: string): DocPage | undefined {
return docPages.find((page) => page.slug === slug);
}
export function getAllDocSlugs() {
return docPages.map((page) => page.slug);
}