Документация Accelera

Various models

Обзор

Various Models — это динамические пользовательские таблицы в платформе Accelera Loyalty. Позволяют создавать произвольные модели данных без изменения кода, управлять их схемой, записями, а также выполнять массовые операции через API.

Юзкейсы

Хранение справочных данных

Каталоги товаров, справочники городов, тарифные планы — любые данные, по которым нужен быстрый поиск и фильтрация из игрового клиента.

Хранение результатов рассылок

Статусы доставки push-уведомлений, SMS, email — с возможностью фильтрации по client_id, каналу, статусу.

Промо-механики

Списки участников акций, промо-коды, купоны — с поддержкой batch-загрузки и upsert по уникальному ключу.

Аналитические витрины

Агрегированные данные для отображения в клиентском приложении — лидерборды, статистика, рейтинги.

Интеграционные буферы

Промежуточное хранение данных из внешних систем перед обработкой бизнес-логикой платформы.

Поддерживаемые типы данных

ТипPostgreSQLОписаниеПример
stringvarcharСтрока до 2^31-1 байт"Hello"
integerintegerЦелое число (32-бит)42
floatrealЧисло с плавающей точкой3.14
booleanbooleanЛогическое значениеtrue / false
jsonjsonJSON-документ{"key": "value"}
texttextБольшой текстдлинные строки
datedateТолько дата"2026-01-15"
timetimeТолько время"14:30:00"
datetimetimestampДата и время"2026-01-15T14:30:00"

Системные колонки (создаются автоматически)

КолонкаТипОписание
uidBIGINT (PK, auto-increment)Уникальный идентификатор записи
createdAttimestampВремя создания, заполняется автоматически
updatedAttimestampВремя последнего обновления

Системные колонки нельзя переименовать или удалить.

Валидаторы полей

При описании атрибутов модели можно указать ограничения:

ПараметрТипОписание
allowNullbooleanРазрешить NULL-значения (по умолчанию true)
uniquebooleanУникальное значение (по умолчанию false)
defaultValueanyЗначение по умолчанию (должно соответствовать типу)
minnumberМинимальное числовое значение
maxnumberМаксимальное числовое значение
minLengthnumberМинимальная длина строки
maxLengthnumberМаксимальная длина строки
patternstringРегулярное выражение для валидации
enumarrayСписок допустимых значений

Пример описания атрибута

{
  "name": "email",
  "type": "string",
  "allowNull": false,
  "unique": true,
  "maxLength": 255,
  "minLength": 3,
  "pattern": "^[^@]+@[^@]+\\.[^@]+$"
}

Индексы

  • Индексы ускоряют поиск по указанным колонкам
  • Задаются как массив имён колонок при создании или обновлении модели
  • Автоматически именуются {modelName}_{columnName}_idx
  • Ограничение: JSON-колонки не поддерживают индексирование
{
  "indexes": ["email", "status", "createdAt"]
}

API: Управление моделями (Management)

Аутентификация: сессионная (cookie) Базовый путь: /v1/management/various

Получить список моделей

GET /v1/management/various/

Ответ: массив определений моделей.

Получить модель по ID

GET /v1/management/various/{id}

Создать модель

POST /v1/management/various/
Content-Type: application/json

Тело запроса:

{
  "modelName": "products",
  "title": "Каталог товаров",
  "description": "Справочник товаров для программы лояльности",
  "attributes": [
    {
      "name": "product_id",
      "type": "string",
      "allowNull": false,
      "unique": true
    },
    {
      "name": "name",
      "type": "string",
      "allowNull": false,
      "maxLength": 200
    },
    {
      "name": "price",
      "type": "float",
      "allowNull": false,
      "min": 0
    },
    {
      "name": "category",
      "type": "string",
      "allowNull": true
    },
    {
      "name": "active",
      "type": "boolean",
      "defaultValue": true
    }
  ],
  "indexes": ["product_id", "category"]
}

Ограничения:

  • modelName: 2-50 символов, уникальное
  • attributes: непустой массив
  • Имя не должно совпадать с существующей таблицей

Обновить метаданные модели

PUT /v1/management/various/{id}
Content-Type: application/json

Тело запроса (только метаданные, не структура):

{
  "title": "Новое название",
  "description": "Новое описание"
}

Изменить схему модели

POST /v1/management/various/update-schema
Content-Type: application/json

Тело запроса:

{
  "modelName": "products",
  "attributes": [
    {"name": "product_id", "type": "string", "allowNull": false, "unique": true},
    {"name": "name", "type": "string", "allowNull": false},
    {"name": "price", "type": "float", "allowNull": false},
    {"name": "category", "type": "string"},
    {"name": "brand", "type": "string", "allowNull": true}
  ],
  "removedColumns": ["old_column"],
  "renamedColumns": [
    {"old": "category", "new": "product_category"}
  ],
  "indexes": ["product_id", "product_category"]
}

Возможности:

  • Добавление новых колонок
  • Удаление существующих колонок
  • Переименование колонок
  • Изменение типа данных (с проверкой совместимости)
  • Изменение constraints (allowNull, unique, defaultValue)
  • Управление индексами

Ограничения:

  • Нельзя переименовать/удалить uid, createdAt, updatedAt
  • Нельзя добавить NOT NULL если в колонке есть NULL-значения
  • Нельзя добавить UNIQUE если есть дубликаты
  • Нельзя индексировать JSON-колонки

Валидация изменений схемы (dry run)

POST /v1/management/various/validate-schema
Content-Type: application/json

Тело запроса аналогично update-schema. Возвращает результат валидации без применения изменений:

{"valid": true}

или

{
  "valid": false,
  "errors": [
    {
      "column": "status",
      "constraint": "NOT NULL",
      "message": "Column has 42 null values",
      "nullCount": 42
    }
  ]
}

Удалить модель

DELETE /v1/management/various/{model}

Таблица не удаляется физически, а переименовывается с добавлением timestamp (soft delete).

API: Управление записями (Management)

Базовый путь: /v1/management/various/records

Получить записи

GET /v1/management/various/records/{model}

Query-параметры (формат Sequelize):

?where[status]=1&where[name][like]=%test%

Получить запись по ID

GET /v1/management/various/records/{model}/{id}

Создать/обновить запись

POST /v1/management/various/records/{model}
Content-Type: application/json
{
  "product_id": "SKU-001",
  "name": "Товар 1",
  "price": 999.90,
  "category": "electronics",
  "active": true
}

Обновить конкретную запись

POST /v1/management/various/records/{model}/{id}
Content-Type: application/json

Удалить запись

DELETE /v1/management/various/records/{model}/{id}

DataTables (серверная пагинация)

POST /v1/management/various/datatables/{model}
Content-Type: application/json
{
  "draw": 1,
  "start": 0,
  "length": 25,
  "search": {"value": "поисковый запрос"},
  "columns": [
    {"data": "name", "searchable": true},
    {"data": "status", "searchable": false}
  ]
}

Ответ:

{
  "draw": 1,
  "recordsTotal": 15000,
  "recordsFiltered": 342,
  "data": [...]
}

API: Работа с записями (Internal)

Аутентификация: Basic Auth Базовый путь: /v1/internal/various

Получить список моделей

GET /v1/internal/various/
Authorization: Basic <credentials>

Получить записи с фильтрацией

GET /v1/internal/various/records/{model}
Authorization: Basic <credentials>

Query-параметры:

ПараметрОписаниеПример
queryJSON-фильтр{"status": 1}
fieldsВыбор колонокname,price,status
limitКол-во записей (макс. 200)50
offsetСтраница0
sort_byСортировкаprice.asc,name.desc
group_byГруппировкаcategory
countАгрегацияuid,total

Специальные заголовки:

ЗаголовокОписаниеЗначение
loyalty-use-cacheВключить кешированиеtrue / false
loyalty-cache-lifetimeВремя жизни кеша (минуты)60 (по умолчанию)

Операторы фильтрации

Сравнение

{"age": {"gt": 18}}          // age > 18
{"age": {"gte": 18}}         // age >= 18
{"age": {"lt": 65}}          // age < 65
{"age": {"lte": 65}}         // age <= 65
{"status": {"ne": 0}}        // status != 0
{"status": {"eq": 1}}        // status = 1

Строковые

{"email": {"like": "%@company.com"}}       // LIKE
{"name": {"notLike": "%test%"}}            // NOT LIKE
{"code": {"regexp": "^[A-Z]{3}\\d+"}}      // regex ~

Диапазоны

{"price": {"between": [100, 1000]}}        // BETWEEN 100 AND 1000
{"age": {"notBetween": [0, 17]}}           // NOT BETWEEN 0 AND 17

Списки

{"status": {"in": [1, 2, 3]}}             // IN (1, 2, 3)
{"category": {"notIn": ["test", "demo"]}}  // NOT IN

Логические

{"and": [{"status": 1}, {"active": true}]}
{"or": [{"role": "admin"}, {"role": "moderator"}]}

Комбинированный пример

GET /v1/internal/various/records/products?query={"and":[{"price":{"gte":100,"lte":5000}},{"active":true},{"category":{"in":["electronics","gaming"]}}]}&sort_by=price.asc&fields=product_id,name,price&limit=50

Создать или обновить запись

POST /v1/internal/various/records/{model}
Authorization: Basic <credentials>
Content-Type: application/json

Без query — создание новой записи:

{
  "product_id": "SKU-001",
  "name": "Товар 1",
  "price": 999.90
}

С query — обновление существующей записи:

POST /v1/internal/various/records/{model}?query={"product_id":"SKU-001"}
{
  "price": 899.90,
  "active": false
}

Если запись по фильтру не найдена — будет создана новая.

Удалить записи

DELETE /v1/internal/various/records/{model}
Authorization: Basic <credentials>

С query — удаление по фильтру:

DELETE /v1/internal/various/records/{model}?query={"status":0}

Без query — TRUNCATE всей таблицы.

Batch-загрузка

Массовая вставка/обновление записей с буферизацией через Redis.

POST /v1/internal/various/records/{model}/batch?key={conflict_column}
Authorization: Basic <credentials>
Content-Type: application/json

Параметры:

  • key (обязательный) — имя колонки с уникальным индексом для разрешения конфликтов (upsert)

Тело запроса — одна запись:

{
  "product_id": "SKU-001",
  "name": "Товар 1",
  "price": 999.90,
  "active": true
}

Ответ: {"status": "received"}

Как работает batch

  1. Запись проходит валидацию (типы, обязательные поля, наличие conflict key)
  2. Добавляется в Redis-очередь
  3. При достижении порога (по умолчанию 20 записей) или по крону (каждые 20 секунд) — записи сбрасываются в БД
  4. Используется upsert: если запись с таким key существует — обновляется, иначе — создаётся
  5. При ошибке записи попадают в очередь ошибок для ручного разбора

Валидация перед постановкой в очередь

  • Наличие conflict key в каждой записи
  • Соответствие типов данных описанию модели
  • Наличие обязательных полей (allowNull: false без defaultValue)

Кеширование

Кеширование доступно только для Internal API и управляется заголовками запроса.

Включение

GET /v1/internal/various/records/{model}?query={...}
loyalty-use-cache: true
loyalty-cache-lifetime: 30

Поведение

  • Ключ кеша: полный URL запроса включая query-параметры
  • Хранилище: Redis
  • TTL: значение loyalty-cache-lifetime в минутах (по умолчанию 60)
  • Cache miss: запрос к БД, результат сохраняется в кеш
  • Cache hit: возврат из Redis без обращения к БД

Когда использовать

  • Справочные данные, которые редко меняются
  • Высоконагруженные эндпоинты с одинаковыми запросами
  • Данные, для которых допустима задержка обновления

Когда не использовать

  • Часто обновляемые данные
  • Запросы, требующие актуальных значений в реальном времени

Формат ошибок

{
  "error": {
    "message": "Описание ошибки",
    "details": "Детали из БД (если применимо)"
  }
}

HTTP-коды ответов

КодОписание
200Успешная операция
400Ошибка валидации
401Не авторизован
404Модель или запись не найдена
409Конфликт (запись уже существует)
500Внутренняя ошибка сервера

Примеры: типичные сценарии

Сценарий 1: Каталог товаров

Создание модели:

POST /v1/management/various/
{
  "modelName": "product_catalog",
  "title": "Каталог товаров",
  "attributes": [
    {"name": "sku", "type": "string", "allowNull": false, "unique": true},
    {"name": "name", "type": "string", "allowNull": false, "maxLength": 200},
    {"name": "price", "type": "float", "min": 0},
    {"name": "category", "type": "string"},
    {"name": "in_stock", "type": "boolean", "defaultValue": true}
  ],
  "indexes": ["sku", "category"]
}

Массовая загрузка товаров:

POST /v1/internal/various/records/product_catalog/batch?key=sku
{"sku": "A001", "name": "Наушники", "price": 2990, "category": "audio"}

Поиск товаров:

GET /v1/internal/various/records/product_catalog?query={"category":"audio","price":{"lte":5000},"in_stock":true}&sort_by=price.asc
loyalty-use-cache: true

Сценарий 2: Результаты рассылки

Создание модели:

POST /v1/management/various/
{
  "modelName": "push_results",
  "title": "Результаты push-рассылок",
  "attributes": [
    {"name": "client_id", "type": "string", "allowNull": false},
    {"name": "message_id", "type": "string", "allowNull": false, "unique": true},
    {"name": "channel", "type": "string"},
    {"name": "delivery_status", "type": "string"},
    {"name": "delivery_details", "type": "string"},
    {"name": "sent_at", "type": "datetime"}
  ],
  "indexes": ["client_id", "message_id", "delivery_status"]
}

Запрос статусов по клиенту:

GET /v1/internal/various/records/push_results?query={"client_id":"ABC-123","delivery_status":"DELIVERED"}&sort_by=sent_at.desc&limit=20

Сценарий 3: Участники промо-акции

Создание модели:

POST /v1/management/various/
{
  "modelName": "promo_summer_2026",
  "title": "Летняя акция 2026",
  "attributes": [
    {"name": "phone", "type": "string", "allowNull": false, "unique": true},
    {"name": "bonus_amount", "type": "integer", "defaultValue": 0, "min": 0},
    {"name": "registered_at", "type": "datetime"},
    {"name": "status", "type": "string", "enum": ["new", "active", "completed", "cancelled"]}
  ],
  "indexes": ["phone", "status"]
}

Upsert участника:

POST /v1/internal/various/records/promo_summer_2026?query={"phone":"+79991234567"}
{"phone": "+79991234567", "bonus_amount": 500, "status": "active"}

Особенности и ограничения

ОграничениеЗначение
Длина modelName2-50 символов
Максимум записей в ответе (limit)200
Batch: размер буфера до flush20 записей (настраивается)
Batch: интервал flush20 секунд (настраивается)
JSON-колонкинельзя индексировать
Удаление моделиsoft delete (переименование таблицы)
Системные колонкиuid, createdAt, updatedAt — неизменяемы
Кешированиетолько Internal API, управляется заголовками

На этой странице

ОбзорЮзкейсыХранение справочных данныхХранение результатов рассылокПромо-механикиАналитические витриныИнтеграционные буферыПоддерживаемые типы данныхСистемные колонки (создаются автоматически)Валидаторы полейПример описания атрибутаИндексыAPI: Управление моделями (Management)Получить список моделейПолучить модель по IDСоздать модельОбновить метаданные моделиИзменить схему моделиВалидация изменений схемы (dry run)Удалить модельAPI: Управление записями (Management)Получить записиПолучить запись по IDСоздать/обновить записьОбновить конкретную записьУдалить записьDataTables (серверная пагинация)API: Работа с записями (Internal)Получить список моделейПолучить записи с фильтрациейОператоры фильтрацииСравнениеСтроковыеДиапазоныСпискиЛогическиеКомбинированный примерСоздать или обновить записьУдалить записиBatch-загрузкаКак работает batchВалидация перед постановкой в очередьКешированиеВключениеПоведениеКогда использоватьКогда не использоватьФормат ошибокHTTP-коды ответовПримеры: типичные сценарииСценарий 1: Каталог товаровСценарий 2: Результаты рассылкиСценарий 3: Участники промо-акцииОсобенности и ограничения