Auth Service — Data Model

База данных: auth_db

erDiagram
    refresh_tokens {
        uuid id PK
        uuid user_id
        string token_hash UK
        string device_info
        string ip_address
        boolean revoked
        timestamp expires_at
        timestamp created_at
    }

    login_attempts {
        uuid id PK
        string email
        integer attempt_count
        timestamp locked_until "nullable"
        timestamp last_attempt_at
    }

    password_reset_tokens {
        uuid id PK
        uuid user_id
        string token_hash UK
        boolean used
        timestamp expires_at
        timestamp created_at
    }

Таблицы

refresh_tokens

Refresh tokens для rotation. При обновлении старый token помечается revoked = true, создаётся новый.

login_attempts

Счётчик неудачных попыток входа. После 5 попыток — блокировка на 15 минут (locked_until). Сбрасывается при успешном входе.

ПолеТипDescription
iduuid PK
emailvarchar(255) UKEmail сотрудника
attempt_countintegerКол-во неудачных попыток (default 0)
locked_untiltimestamp NULLВремя окончания блокировки
last_attempt_attimestampВремя последней попытки

password_reset_tokens

Токены для сброса пароля. TTL = 1 час. Одноразовые (used = true после использования).

ПолеТипDescription
iduuid PK
user_iduuidID сотрудника
token_hashvarchar(255) UKХэш токена
usedbooleanИспользован (default false)
expires_attimestampСрок действия (created_at + 1 hour)
created_attimestamp

Auth Service не хранит пароли

Пароли хранятся в User Service (таблица employees.password_hash). Auth Service запрашивает валидацию через internal API.

Redis-структуры

Key patternValueTTL
session:{user_id}:{token_hash}{ user_id, role_ids, franchise_id } (упрощено в BR 1.4.4 — поля role, store_ids удалены)= access TTL
user_permissions:{user_id}JSON: { role_ids: [...], permissions: [...] } (BR 1.4.3)60 сек
user_scope:{user_id}JSON: { type: "all_franchise" | "legal_entity_ids" | "store_ids", legal_entity_ids?: [...], store_ids?: [...] } (BR 1.4.4)60 сек

Кэш permissions (BR 1.4.3)

user_permissions:{user_id} — агрегированный список permission-ключей сотрудника, полученный из User Service (GET /internal/users/{id}/permissions). Используется POST /internal/auth/validate для отдачи permissions без обращения к User Service на каждый запрос.

Стратегия инвалидации: TTL 60 секунд. Изменения прав роли отражаются на сотруднике через ≤ 60 секунд — компромисс между нагрузкой на User Service и скоростью применения.

Opt-in мгновенная инвалидация (deferred): при необходимости можно добавить эндпоинт DELETE /internal/auth/cache/{user_id}, вызываемый User Service после изменения ролей/прав.

Кэш scope (BR 1.4.4)

(Введено в BR 1.4.4)

user_scope:{user_id} — вычисленный scope сотрудника: либо «вся франшиза», либо список ЮЛ, либо список ТТ. Получается из User Service (GET /internal/users/{id}/scope) при cache-miss. Аналогичная стратегия, что и для permissions: TTL 60 сек. Используется в POST /internal/auth/validate чтобы отдавать scope другим сервисам без отдельного запроса в User Service на каждый вызов.

Scope заменяет ранее использовавшиеся поля JWT store_ids и legal_entity_id — они удалены из payload в BR 1.4.4. Все downstream-сервисы (Store, Catalog, Warehouse, Order) получают scope из ответа validate и используют его для фильтрации данных.