Files
BitrixDealsBot/docs/adr/008-data-storage-and-access.md

6.0 KiB
Raw Permalink Blame History

ADR-008: хранение интеграционных данных и разграничение доступа

Статус: Принято
Дата: 2026-07-23

Контекст

Основное назначение базы данных — хранение авторизационных данных, токенов привязки, OAuth-токенов и связей между пользователями Битрикс24 и Telegram. Сделки, контакты, компании, стадии и история остаются в Битрикс24 и в локальной базе не дублируются.

Решение

Модель хранения нормализована вокруг портала Битрикс24.

Схема базы данных

Рисунок ADR-008/1. Схема базы данных

Таблица Ключевые данные Назначение и ограничения
binding.portals member_id, domain Справочник порталов; member_id уникален
binding.tokens token_hash, expires_at, consumed_at, revoked_at Одноразовые ссылки; токен хранится только как хеш
binding.user_bindings portal_id, bitrix_user_id, telegram_user_id Однозначная привязка пользователей в пределах портала
oauth.user_credentials access_token, refresh_token, version, lock Зашифрованные OAuth-данные и координация обновления

Таблица ADR-008/1. Назначение таблиц базы данных

Поле member_id является устойчивым внешним идентификатором портала, а числовой bitrix_user_id имеет смысл только вместе с portal_id. Связи с portals используют ON DELETE CASCADE: удаление портала автоматически удаляет его ссылки, привязки и OAuth-данные. Составной первичный ключ oauth.user_credentials(portal_id, bitrix_user_id) исключает две конкурирующие записи учётных данных одного пользователя. Поля consumed_at и revoked_at разделяют два независимых основания недействительности одноразовой ссылки.

Для работы с данными в PostgreSQL созданы две роли: site_role и bot_role. Они имеют разные права доступа к хранимым функциям и не могут редактировать таблицы напрямую.

Функция Вызывающая роль Назначение
binding.issue_v1 site_role Сохранить OAuth-данные, отозвать старые ссылки и выпустить новую в одной транзакции
binding.consume_v1 bot_role Однократно погасить ссылку и создать привязку
binding.find_by_telegram_v1 bot_role Получить актуальную привязку Telegram
oauth.get_credentials_v1 bot_role Получить учётные данные связанного пользователя
oauth.claim_refresh_v1 bot_role Получить короткую аренду на обновление токена
oauth.finish_refresh_v1 bot_role Атомарно записать новую пару при совпадении версии
oauth.release_refresh_v1 bot_role Освободить аренду после ошибки

Таблица ADR-008/2. Контракт хранимых функций PostgreSQL

Сайт использует роль site_role и может вызывать только функцию привязки. Telegram-бот использует bot_role и может вызывать функции погашения токенов, получения привязки и работы с OAuth. Роль site_role не имеет доступа к схеме oauth и не может читать сохранённые токены; роль bot_role не может выпускать новые ссылки от имени сайта.

Все функции объявлены SECURITY DEFINER и фиксируют search_path в pg_catalog, что уменьшает риск подмены объектов. Права PUBLIC на таблицы и функции отозваны.

Последствия

Конкурирующие вызовы binding.consume_v1 для одного хеша не смогут одновременно пройти условие consumed_at IS NULL: UPDATE блокирует строку, а после завершения первой транзакции второй вызов видит уже установленное время погашения. Проверка и изменение не разделены между приложением и базой, поэтому отсутствует окно гонки между SELECT и UPDATE.