@dieugene/users-controller
Version:
Модуль для управления глобальным реестром пользователей сервиса и их данными через различные каналы коммуникации
294 lines (198 loc) • 14.2 kB
Markdown
# Users Controller
Модуль для управления глобальным реестром пользователей сервиса и их данными через различные каналы коммуникации.
## Принципы работы с пользователями
Модуль предусматривает ведение глобального реестра пользователей сервиса, безотносительно к тому, через какой канал происходит взаимодействие с сервисом. В то же время, на текущий момент настроена работа только через один канал - телеграм-боты.
Пользователи могут взаимодействовать с системой через разные каналы, в которых у них свои идентификаторы и метаданные. Каждому пользователю присваивается глобальный UUID, и разные каналы коммуникаций связываются с этим ID.
Особенность задачи в том, что при подключении каждого нового канала коммуникаций пользователь считается "новым", пока не будет выполнена связь с другими каналами. Когда пользователь выполняет привязку (через предоставление своего глобального ID), идентификатор "нового" канала переписывается.
## Типы хранилища
Модуль предусматривает три типа хранилища:
### 1. Общий реестр пользователей
- **Таблица**: `users_global`
- **Модуль**: `UsersGlobal`
- **Назначение**: Связывает идентификаторы каналов с глобальными UUID пользователей
- **Структура**: тип канала, идентификатор в канале, глобальный идентификатор, дата регистрации
### 2. Пользовательские данные
- **Хранилище**: Key-value база данных
- **Модуль**: `UserData`
- **Назначение**: Хранение объектов с различной пользовательской информацией
- **Особенности**: Использует кэширование для оптимизации производительности
### 3. Пакетная обработка пользовательских данных
- **Таблица**: `users_processing_{domain}`
- **Модуль**: `UserProcessing`
- **Назначение**: Временное хранение данных для пакетной обработки
- **Оптимизация**: Создано для снижения затрат на операции чтения/записи
## Конфигурация базы данных
### Рекомендуемая структура
С точки зрения структуры хранения данных рекомендуется иметь глобальную базу данных, в которой будут храниться данные по всем пользователям. Адрес к этой базе прописывается в переменной `GLOBAL_DB_ADDRESS`, либо указывается при инициализации.
### Альтернативная структура
Также допускается, но не рекомендуется ситуация, что данные (таблицы) распределены по разным базам данных. В этом случае требуется выполнять раздельную инициализацию для каждого из используемых хранилищ.
## Правила именования для пакетной обработки
При инициализации данных для пакетной обработки нужно соблюдать правила именования для параметра `domain`, поскольку его значение становится частью названия таблицы, в которой будет вестись работа. В частности, допустимы:
- прописные латинские буквы (A-Z)
- строчные латинские буквы (a-z)
- цифры (0-9)
- специальные символы: `.`, `-` и `_`
## Установка
```bash
npm install @dieugene/users-controller
```
## Зависимости
- `@dieugene/key-value-db` - для работы с key-value хранилищем
- `@dieugene/utils` - утилиты
- `@dieugene/ydb-serverless` - для работы с YDB
- `uuid` - генерация уникальных идентификаторов
## Дополнительная документация
📋 **[Руководство по работе с таблицами YDB](./YDB_TABLE_OPERATIONS_GUIDE.md)** - подробное руководство по CRUD операциям с использованием @dieugene/ydb-serverless, включая:
- Оптимизацию стоимости операций (UPSERT vs INSERT vs UPDATE)
- Рекомендации по индексации полей
- Лучшие практики работы с YDB
- Примеры кода для всех типов операций
## Быстрый старт
```javascript
const users = require('@dieugene/users-controller');
// Инициализация с использованием переменной окружения GLOBAL_DB_ADDRESS
users.init();
// Или с указанием адреса базы данных
users.init('/region/folder-id/database-id');
```
## API
### Основная инициализация
#### `init(users_database?)`
Инициализирует все модули с указанной базой данных.
**Параметры:**
- `users_database` (string, optional) - адрес базы данных. По умолчанию используется `process.env.GLOBAL_DB_ADDRESS`
### Модуль UsersGlobal (`users.globals`)
#### `init(users_database?)`
Инициализирует модуль работы с глобальным реестром пользователей.
#### `getUserUuid(channelType, inChannelId)`
Получает глобальный UUID пользователя по данным канала.
**Параметры:**
- `channelType` (string) - тип канала коммуникации
- `inChannelId` (string) - идентификатор пользователя в канале
**Возвращает:** Promise<string|undefined> - глобальный UUID пользователя
#### `setUser(channelType, inChannelId)`
Создает нового пользователя в глобальном реестре.
**Параметры:**
- `channelType` (string) - тип канала коммуникации
- `inChannelId` (string) - идентификатор пользователя в канале
**Возвращает:** Promise<string> - новый глобальный UUID пользователя
#### `getChannelUsers(channelType)`
Получает список всех пользователей определенного канала.
**Параметры:**
- `channelType` (string) - тип канала коммуникации
### Модуль UserData (`users.data`)
#### `init(database?)`
Инициализирует модуль работы с пользовательскими данными.
#### `set_user_data(user_uuid, data)`
Сохраняет данные пользователя.
**Параметры:**
- `user_uuid` (string) - глобальный UUID пользователя
- `data` (object) - данные для сохранения
#### `get_user_data(user_uuid, forced?)`
Получает данные пользователя.
**Параметры:**
- `user_uuid` (string) - глобальный UUID пользователя
- `forced` (boolean, optional) - принудительное обновление кэша
**Возвращает:** Promise<object> - данные пользователя
### Модуль UserProcessing (`users.processing`)
#### `init(domain, users_database?)`
Инициализирует модуль пакетной обработки.
**Параметры:**
- `domain` (string) - домен для именования таблицы (должен соответствовать правилам именования)
- `users_database` (string, optional) - адрес базы данных
#### `set(uuid_list)`
Добавляет список UUID пользователей для обработки.
**Параметры:**
- `uuid_list` (string[]) - массив UUID пользователей
#### `set_channel_users(channel)`
Добавляет всех пользователей канала для обработки.
**Параметры:**
- `channel` (string) - тип канала
#### `get(limit?)`
Получает пакет пользователей для обработки.
**Параметры:**
- `limit` (number, optional) - количество пользователей (по умолчанию 50)
**Возвращает:** Promise<string[]> - массив UUID пользователей
#### `del(id_list)`
Удаляет обработанных пользователей из очереди.
**Параметры:**
- `id_list` (string[]) - массив UUID пользователей для удаления
### Модуль TelegramUsers (`users.tg`)
#### `get_user_uuid(ctx, tgId?)`
Получает глобальный UUID пользователя Telegram.
**Параметры:**
- `ctx` - контекст Telegram бота
- `tgId` (number, optional) - ID пользователя Telegram
**Возвращает:** Promise<string> - глобальный UUID пользователя
#### `stringify_user_data(userData)`
Форматирует данные пользователя Telegram в строку.
**Параметры:**
- `userData` (object) - данные пользователя с полями `first_name`, `last_name`, `username`
**Возвращает:** string - отформатированная строка
#### `get_bot_users(botId)`
Получает список пользователей конкретного Telegram бота.
**Параметры:**
- `botId` (string) - ID Telegram бота
#### `set_telegram_data(user_data, ctx)`
Обновляет пользовательские данные информацией из Telegram контекста.
**Параметры:**
- `user_data` (object) - объект данных пользователя
- `ctx` - контекст Telegram бота
**Возвращает:** object - обновленный объект данных пользователя
**Заполняемые поля:**
- `telegram_data.telegram_id` - ID пользователя в Telegram
- `telegram_data.first_name` - имя пользователя
- `telegram_data.last_name` - фамилия пользователя
- `telegram_data.username` - никнейм пользователя
- `telegram_data.language_code` - код языка пользователя
- `telegram_data.is_bot` - флаг бота
- `telegram_data.is_premium` - флаг Telegram Premium
- `telegram_data.updated_at` - Unix timestamp последнего обновления
### Вспомогательные методы
#### `set_user_data(user_uuid, data)`
Прямой доступ к сохранению пользовательских данных.
#### `get_user_data(user_uuid, forced?)`
Прямой доступ к получению пользовательских данных.
## Примеры использования
### Работа с пользователями Telegram
```javascript
const users = require('@dieugene/users-controller');
// Инициализация
users.init();
// Получение UUID пользователя Telegram
async function handleTelegramUser(ctx) {
const userUuid = await users.tg.get_user_uuid(ctx);
// Получение данных пользователя
let userData = await users.get_user_data(userUuid);
// Обновление данных из Telegram (имя, фамилия, username и т.д.)
userData = users.tg.set_telegram_data(userData, ctx);
// Добавление дополнительных данных
userData.last_interaction = new Date();
userData.preferences = { language: 'ru' };
// Сохранение обновленных данных
await users.set_user_data(userUuid, userData);
}
```
### Пакетная обработка пользователей
```javascript
// Инициализация модуля пакетной обработки
await users.processing.init('newsletter');
// Добавление всех пользователей Telegram для обработки
await users.processing.set_channel_users('telegram_bot_id');
// Обработка пользователей пакетами
async function processUsers() {
const usersList = await users.processing.get(100);
for (const userUuid of usersList) {
// Обработка пользователя
await processUser(userUuid);
}
// Удаление обработанных пользователей
await users.processing.del(usersList);
}
```
## Переменные окружения
- `GLOBAL_DB_ADDRESS` - адрес глобальной базы данных (формат: `/region/folder-id/database-id`)
## Лицензия
ISC
## Автор
Eugene Ditkovsky