sequenceDiagram
autonumber
actor User as Пользователь (Настройки -> Выход)
participant APP as Мобильное приложение (Flutter)
participant AS as Сервис Авторизации (FastAPI)
participant DB as Реляционная СУБД (PostgreSQL)
User->>APP: Нажимает кнопку "Выйти из аккаунта"
APP->>AS: HTTP POST /api/v1/auth/logout (JSON с refresh_token и JWT в Header)
activate AS
note over AS: Шаг 3: Декодирование JWT (Выделение user_id и home_group_id)
Note over AS, DB: Старт атомарной SQL-транзакции
AS->>DB: UPDATE user_sessions SET is_revoked = true WHERE token = refresh_token
activate DB
DB-->>AS: Успешное обновление (Сессия заблокирована)
deactivate DB
Note over AS, DB: Коммит атомарной транзакции (COMMIT)
note over AS: Шаг 6: Принудительное закрытие WSS дескриптора этого устройства
AS->>APP: Системный фрейм WebSocket.close(1000, "LOGOUT_CONFIRMED")
AS-->>APP: HTTP 200 OK (status: "success", data: "SESSION_TERMINATED")
deactivate AS
note over APP: Flutter стирает Secure Storage и переключается на экран ввода логина
Метод POST /api/v1/auth/logout
Документация API: Деактивация сессии пользователя (Logout) с каскадной инвалидацией WebSocket-дескрипторов
- INVENTORY-2XX Backlog — Краткое Описание задачи 1.
- INVENTORY-1XX Refinement (Уточнение) — Краткое Описание задачи 2.
1 Функциональное назначение
Метод предназначен для корректного и безопасного завершения текущей пользовательской сессии в экосистеме .
В рамках новой распределенной архитектуры метод POST /logout решает три ключевые задачи:
- Аннулирование долгоживущей сессии (Revocation): Переводит флаг
is_revokedцелевогоrefresh_tokenв состояниеtrueв таблицеuser_sessions, полностью блокируя возможность фонового продления сессии черезDio Interceptor. - Очистка ресурсов WebSocket-менеджера: Отправляет внутренний асинхронный сигнал в оперативную память шлюза
FastAPI, чтобы принудительно закрыть текущий активный WSS-стрим (/ws/push-stream/{id}) именно для этого девайса, предотвращая утечки памяти и отправку системных пушей на отключенное устройство. - Безопасный сброс стейта UI: Служит триггером для мобильного приложения Flutter для полной очистки локальных хранилищ
Flutter Secure Storageи переключения интерфейса на стартовый экран авторизации.
2 Протокол взаимодействия (HTTP Контракт)
- Метод:
POST - Маршрут:
/api/v1/auth/logout - Формат данных:
application/json
2.1 Спецификация заголовков (HTTP Headers)
| Заголовок | Обязательный | Описание | Пример значения |
|---|---|---|---|
Content-Type |
Да | Указывает на передачу JSON-пакета | application/json |
Authorization |
Да | Токен доступа (Access Token). Шлюз вычитывает user_id и home_group_id. |
Bearer eyJhbGciOiJIUzI1Ni... |
X-Request-ID |
Да | Сквозной ID запроса для трассировки сессии выхода из системы | req-auth-out-77aa |
2.2 Спецификация тела запроса (Request Body)
В теле запроса клиент явно передает текущий валидный refresh_token, который подлежит уничтожению в базе данных.
| Поле | Тип | Обязательный | Описание | Пример значения |
|---|---|---|---|---|
refresh_token |
String | Да | Токен обновления, который необходимо аннулировать в СУБД | ref-token-xyz789... |
2.2.1 Пример сырого JSON-запроса (Payload):
{
"refresh_token": "ref-token-xyz789_v1_signature..."
}3 Схема обработки запроса пользователя (Mermaid)
На диаграмме представлена логика безопасного выхода из системы (POST /logout). Сервис Auth блокирует refresh_token в PostgreSQL, после чего шлюз FastAPI обращается к своему пулу активных соединений и принудительно гасит WebSocket-стрим этого смартфона, освобождая оперативную память сервера.
4 Расшифровка шагов
- Шаг 1 (
User -> APP): Пользователь переходит в настройки профиля в мобильном приложении Flutter, нажимает кнопку «Выйти из аккаунта» и подтверждает действие. - Шаг 2 (
APP -> AS): Сетевой слой приложения отправляет запросHTTP POST /api/v1/auth/logout. В теле JSON передается уничтожаемыйrefresh_token, а в заголовкеAuthorizationпрокидывается живойAccess Tokenсессии для прохождения контекстных фильтров шлюза. - Шаг 3 (
AS -> AS): Микросервис Авторизации (FastAPI) принимает пакет, декодируетAccess Tokenи извлекает из негоuser_idиhome_group_idдля проверки матрицы прав. - Шаг 4 (
AS -> DB): Сервис открывает атомарную SQL-транзакцию вPostgreSQLи выполняет команду принудительной блокировки токена:UPDATE user_sessions SET is_revoked = true WHERE token = $1 AND user_id = $2. Параметрuser_idберется строго из JWT, что исключает коллизию, когда один пользователь пытается аннулировать сессию другого. - Шаг 5 (
DB -> AS): База данных фиксирует изменения и возвращает шлюзу подтверждение успешного апдейта строки. Транзакция закрывается командойCOMMIT. С этого момента фоновое продление сессии черезDio Interceptor(Метод 3) для данного токена полностью заблокировано. - Шаг 6 (
AS -> AS): Каскадное тушение сокетов: Шлюз FastAPI обращается к своему резидентному пулу соединенийactive_connections[home_group_id]и находит дескриптор WebSocket-канала, открытый с текущего смартфона пользователя. - Шаг 7 (
AS -> APP): Сервер отправляет в сокет системный фрейм закрытия с кодом1000 (Normal Closure)и текстовой директивой"LOGOUT_CONFIRMED", после чего корректно разрывает TCP-соединение, полностью вычищая дескриптор из оперативной памяти шлюза. Это освобождает системные ресурсы сервера от «мертвых» удерживаемых линков. - Шаг 8 (
AS -> APP): HTTP-поток шлюза возвращает мобильному приложению успешный статусHTTP 200 OK. Приемник Flutter ловит ответ, полностью очищает локальный кэш и хранилищаFlutter Secure Storage, сбрасывает стейты Bloc-менеджеров и переключает интерфейс смартфона на стартовое окно авторизации.
5 Спецификация ответов сервера (Response Body) и ошибок
5.1 1. Успешный ответ (Success Response)
5.1.1 HTTP 200 OK (Ответ на Шаге 8)
Возвращается мобильному приложению после успешного коммита транзакции деактивации. В теле ответа фиксируется успешное уничтожение сессии.
- Заголовки ответа (Response Headers):
Content-Type: application/json
- Тело ответа (Response Body):
{
"status": "success",
"data": {
"message": "SESSION_TERMINATED",
"details": "Refresh token successfully revoked. Active WebSocket connection terminated clean.",
"timestamp": "2026-07-02T02:20:00Z"
}
}5.2 2. Вилки исключений и обработка ошибок
5.2.1 Ошибка: Токен не найден или уже аннулирован (HTTP 404 Not Found)
Выбрасывается, если переданный в JSON-теле refresh_token отсутствует в таблице user_sessions, либо если его флаг is_revoked уже равен true (например, метод logout был вызван повторно).
- Заголовки ответа (Response Headers):
Content-Type: application/json
- Тело ответа (Response Body):
{
"error_code": "ERR-LOGOUT-TARGET-NOT-FOUND",
"message": "Указанная сессия обновления не найдена или была аннулирована ранее.",
"details": {
"action": "Proceed with local state clearance in Flutter securely as session is already dead on server."
}
}5.2.2 Ошибка валидации структуры (HTTP 422 Unprocessable Entity)
Выбрасывается бэкенд-шлюзом FastAPI при передаче пустого поля токена.
{
"error_code": "ERR-VALIDATION-FAILED",
"message": "Передан некорректный или пустой токен для аннулирования сессии.",
"details": [
{
"loc": ["body", "refresh_token"],
"msg": "Field constraints violation: string cannot be empty",
"type": "value_error.str.min_length"
}
]
}