6.0 KiB
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.
