sequenceDiagram
autonumber
actor User as Пользователь (Главный экран)
participant APP as Мобильное приложение (Flutter)
participant API as Бэкенд-шлюз (FastAPI)
participant DB as Реляционная СУБД (PostgreSQL)
User->>APP: Открывает приложение / обновляет склад
APP->>API: HTTP GET /api/v1/fridge/virtual-shortages (JWT в заголовке)
activate API
note over API: Шаг 3: Проверка account_type (Если OFFICE -> мгновенный пустой ответ)
API->>DB: SELECT FROM fridge_inventory WHERE home_group_id = \$1 AND quantity < 0
activate DB
DB-->>API: Набор строк с отрицательным балансом (quantity, unit, product_name)
deactivate DB
note over API: Шаг 6: Конвертация отрицательных весов в абсолютные значения float
API-->>APP: HTTP 200 OK (JSON с массивом shortages и флагом has_shortages: true)
deactivate API
note over APP: На главном экране всплывает информер: "Вы забыли внести 0.5 кг яблок!"
Метод GET /api/v1/fridge/virtual-shortages
Документация API: Извлечение реестра отрицательных балансов (виртуальных минусов) для превентивного информирования пользователя
1 Функциональное назначение
Метод предназначен для обслуживания и агрегации технических отрицательных состояний склада, которые возникли в семейном контуре (HOME) на этапах фиксации приготовленных блюд (Методы 1 и 4). Поскольку система разрешает пользователям уводить баланс продуктов в минус, чтобы не блокировать бытовые процессы, нам необходим специализированный эндпоинт для контроля этих задолженностей.
Метод решает следующие задачи:
- Аудит задолженностей: Сканирует таблицу инвентаря холодильника по
home_group_idи вытягивает строки, у которых фактическое количество строго меньше нуля (quantity < 0). - Формирование контекстных алертов: Готовит упорядоченный список продуктов, которые физически были съедены или потрачены, но технически еще не были внесены в систему (например, пользователь забыл отсканировать чек при покупке яблок).
- Триггер для UI: На основе ответа этого метода мобильное приложение Flutter выводит на главном экране предупреждающий информер: «Вы приготовили пирог, но мы виртуально списали 0.5 кг яблок. Пожалуйста, отсканируйте чек или подтвердите остатки».
2 Протокол взаимодействия (HTTP Контракт)
- Метод:
GET - Маршрут:
/api/v1/fridge/virtual-shortages - Формат данных:
application/json(только ответ)
2.1 Спецификация заголовков (HTTP Headers)
| Заголовок | Обязательный | Описание | Пример значения |
|---|---|---|---|
Authorization |
Да | Токен авторизации (Access Token). Бэкенд извлекает из него home_group_id и проверяет контекст HOME. |
Bearer eyJhbGciOiJIUzI1Ni... |
X-Request-ID |
Да | Сквозной ID запроса для связывания логов мониторинга долгов | req-shortage-55dd |
2.2 Спецификация структуры ответа (Response Body)
Метод возвращает массив объектов задолженностей. Значение deficit_quantity приводится к абсолютному положительному числу для удобства отображения в UI-баннерах на клиенте.
| Поле | Тип | Описание | Пример значения |
|---|---|---|---|
fridge_item_id |
Integer | ID конкретной записи поставки, ушедшей в минус | 1042 |
product_name |
String | Каноническое или пользовательское имя дефицитного продукта | "Яблоки" |
deficit_quantity |
Float | Абсолютный объем задолженности, требующий покрытия | 0.5000 (из исходного значения -0.5000) |
unit |
String | Единица измерения продукта | "кг" |
2.2.1 Пример JSON-ответа (Payload):
{
"home_group_id": "group-772-alpha",
"has_shortages": true,
"total_shortages_count": 2,
"shortages": [
{
"fridge_item_id": 1042,
"product_name": "Яблоки",
"deficit_quantity": 0.5,
"unit": "кг",
"created_at": "2026-07-01T21:50:00Z"
},
{
"fridge_item_id": 1089,
"product_name": "Мука",
"deficit_quantity": 0.25,
"unit": "кг",
"created_at": "2026-07-01T21:55:00Z"
}
]
}3 Схема обработки запроса пользователя (Mermaid)
На диаграмме представлена логика сканирования балансов СУБД. Бэкенд изолирует отрицательные остатки конкретной семьи и передает их во Flutter для вывода интерфейсных предупреждений.
4 Расшифровка шагов
- Шаг 1 (
User -> APP): Пользователь запускает мобильное приложение или переходит на главный экран управления запасами. В этот момент Flutter-приложение инициирует фоновый опрос для проверки наличия задолженностей по продуктам. - Шаг 2 (
APP -> API): Приложение отправляет запросHTTP GET /api/v1/fridge/virtual-shortages. В заголовках передается стандартный токен авторизации иX-Request-ID. Пользователь не видит лоадеров, запрос выполняется незаметно для интерфейса. - Шаг 3 (
API -> API): БэкендFastAPIрасшифровывает JWT-токен и проверяет клеймaccount_type. Так как в корпоративном контуреOFFICEуход в минус технически заблокирован на уровне транзакций коммита, для офисных аккаунтов метод прерывает выполнение и мгновенно возвращает структуруhas_shortages: falseс пустым массивом, не нагружая базу данных лишними операциями. - Шаг 4 (
API -> DB): Если тип аккаунта —HOME(семья), бэкенд обращается к СУБДPostgreSQLс целевым запросом фильтрации по индексу группы:SELECT item_id, product_name, quantity, unit, created_at FROM fridge_inventory WHERE home_group_id = $1 AND quantity < 0 ORDER BY created_at DESC. - Шаг 5 (
DB -> API): База данных сканирует таблицу инвентаря и возвращает набор строк, баланс которых ушел в минус в процессе ручной или рецептурной готовки. - Шаг 6 (
API -> API): Бэкенд принимает данные и выполняет математическое преобразование. Чтобы не путать пользователя знаками «минус» в интерфейсе, бэкенд пропускает значениеquantityчерез функциюabs(), превращая, например,-0.5000в чистый float-объем дефицита0.5. - Шаг 7 (
API -> APP):FastAPIрассчитывает общее количество дефицитных позиций, выставляет маркерhas_shortages: trueи возвращает статусHTTP 200 OK. Мобильное приложение Flutter принимает JSON-пакет. Если задолженности найдены, стейт-менеджер (Bloc/Provider) активирует на главном экране желтый информационный информер-алерт с перечнем продуктов, которые семья съела виртуально, призывая закрыть долг путем сканирования чека новой покупки.
5 Спецификация ответов сервера (Response Body) и ошибок
5.1 1. Контекстные ответы сервера (Success Responses)
Метод всегда возвращает статус 200 OK для авторизованных сессий, но структура данных меняется в зависимости от наличия задолженностей или типа аккаунта.
5.1.1 Пример JSON-ответа при отсутствии задолженностей (Идеальное состояние)
Возвращается, если все остатки в холодильнике строго >= 0, либо если запрос выполнен под учетной записью OFFICE. Флаг has_shortages: false сигнализирует Flutter, что выводить алерты и информеры на экран не нужно.
{
"home_group_id": "group-772-alpha",
"has_shortages": false,
"total_shortages_count": 0,
"shortages": []
}5.2 2. Спецификация серверной логики фильтрации (SQL)
Запрос производит выборку строк инвентаря с отрицательным объемом для конкретного семейного контура.
SELECT
item_id AS fridge_item_id,
product_name,
-- Конвертируем отрицательное значение в абсолютное число на уровне СУБД
ABS(quantity)::FLOAT AS deficit_quantity,
unit,
created_at
FROM fridge_inventory
WHERE home_group_id = \$1
AND quantity < 0 -- Критерий отбора: только технические минусы
ORDER BY created_at DESC;5.3 3. Вилки исключений и обработка ошибок
5.3.1 Ошибка: Нарушение прав доступа к группе (HTTP 403 Forbidden)
Выбрасывается на Шаге 3, если home_group_id, извлеченный из токена, заблокирован, деактивирован или не совпадает с запрашиваемым контекстом безопасности базы данных.
{
"error_code": "ERR-GROUP-ACCESS-DENIED",
"message": "Доступ к инвентарю данной группы заблокирован или отсутствует в матрице прав.",
"details": {
"reason": "JWT home_group_id token claim signature mismatch or group is suspended."
}
}