Ошибки авторизации в CRUD-приложениях: аудит ролей, тенантов и маршрутов
Узнайте, как находить и исправлять ошибки авторизации в CRUD‑приложениях: аудит проверок ролей, scoping по тенанту и API‑маршрутов до того, как пользователи начнут видеть чужие данные.

Почему пользователи начинают видеть данные друг друга
Ошибка авторизации — это когда приложение даёт доступ не тому человеку, даже если он залогинен. Это отличается от аутентификации, которая лишь доказывает, кто вы (вход, пароль, magic link). Авторизация отвечает на другой вопрос: раз вы вошли — что вам разрешено делать и какие записи ваши?
Когда авторизация даже немного неверна, последствия редко бывают незначительными. Пользователь может просмотреть счета другого клиента, изменить чужой профиль или удалить записи, о которых не должен знать. В CRUD-приложениях это особенно опасно: интерфейс может выглядеть нормально, пока кто-то не поменяет URL, не подправит запрос в браузере или не вызовет незащищённый API-маршрут.
Это часто проявляется в дашбордах, админ-панелях и клиентских порталах. Такие приложения быстро растут: новые экраны, новые эндпоинты, новые фильтры. Один пропущенный фильтр по тенанту в запросе таблицы — и записи из другой учётной записи появляются.
За такими ошибками часто стоит постепенное расширение привилегий. Права незаметно растут со временем. Сначала «пользователи видят своё», потом добавляются инструменты поддержки, потом вид админа, потом endpoint для экспорта. На каждом шаге появляется новое место, где проверки могут Drift.
Реалистичный пример: в клиентском портале есть кнопка «Скачать квитанцию». Эндпоинт принимает ID квитанции. Если сервер проверяет только, что "пользователь залогинен", но не проверяет "относится ли квитанция к этому тенанту", пользователь может угадать или повторно использовать ID и скачать чужую квитанцию.
Такие ошибки выживают потому, что отсутствует одна из базовых вещей:
- ясное правило владения (пользователь, команда или тенант)
- последовательные проверки при каждом чтении и записи
- тесты, которые намеренно пытаются получить доступ между аккаунтами
Команды часто сталкиваются с этим у прототипов, сгенерированных ИИ. Аутентификация работает, но правила авторизации не применяются последовательно по маршрутам и запросам. Тогда «в демонстрации работало» превращается в утечку данных в продакшене.
Роли, права и тенанты — простая модель
Большинство утечек происходит потому, что приложение не даёт однозначного ответа на простой вопрос: кто этот пользователь и что ему разрешено делать прямо сейчас?
Начните с явной нумерации идентификационных данных, которые приложение должно нести в каждом запросе:
- User ID: человек, выполняющий запрос.
- Role: тип доступа (viewer, editor, admin).
- Tenant ID: организация/рабочая область/проект, к которому они принадлежат.
Проверка роли отвечает на вопрос «можете ли вы выполнить это действие?». Ограничение по тенанту отвечает на вопрос «с какими записями вам разрешено работать?». Обычно нужны оба.
Например, role = editor может разрешать «редактировать счета». Но без scoping по тенанту запрос вроде «update invoice by id» может обновить счёт в другой рабочей области. У пользователя было право, просто не для этого тенанта.
Проверки ролей vs ограничение по тенанту
Проверки ролей обычно простые: может ли пользователь удалить, может ли он приглашать коллег, может ли он видеть страницу биллинга. Ограничение по тенанту — это ограждение, которое держит каждое чтение и запись в пределах нужной организации/рабочей области.
Проще запомнить так:
- Роль решает, что вы можете делать.
- Тенант решает, где вы можете это делать.
Ловушка «админ»
Место, где многие приложения становятся небрежными, — это «админ». Есть большая разница между:
- Тенант-админом: управляет пользователями и настройками внутри своей рабочей области.
- Глобальным админом: имеет доступ ко всему во всех тенантах (редко, обычно внутренний персонал).
Если код трактует любой admin как глобальный, обычный клиентский админ может получить доступ к данным других клиентов. Это особенно распространено, когда «admin» реализован как один флаг без уточнения области действия.
Ещё одно предупреждение: ограничения только в UI — это не безопасность. Скрытие кнопок улучшает удобство, но не защищает данные. Если API-маршрут принимает запрос, пользователь всё равно может вызвать его напрямую, даже если UI никогда не показывает эту опцию.
Где должна применяться авторизация
Авторизация — это не одна проверка, которую добавляют «где-то в бэкенде». В большинстве утечек команда действительно делала проверку, но она находилась не в том месте или покрывала только один уровень.
Думайте про применение как про стек слоёв. Каждый слой блокирует разный тип ошибки, особенно в коде, который быстро развивается и когда обработчики копируются и изменяются.
Думайте слоями (а не одной защитой)
Начните с края, откуда запросы входят в систему. Если endpoint не должен быть вызываемым для роли, заблокируйте его до выполнения какой‑либо работы. Это предотвращает проблему «я могу просто попасть по URL напрямую».
Далее — принудительно проверяйте доступ к конкретной записи. Знание того, что кто‑то залогинен, недостаточно. Вы должны доказать, что запись принадлежит их тенанту (или что у них есть допустимая межтенантная причина, например внутренняя роль поддержки).
Наконец, контролируйте, что они могут видеть или менять внутри этой записи. Многие приложения ограничивают возвращаемые строки, но всё ещё выдают чувствительные поля (внутренние заметки) или принимают изменения в полях, которыми управляет сервер (role, plan, tenantId).
Практический способ расположить проверки:
- Доступ к маршруту: кто вообще может вызывать этот endpoint
- Доступ к записи: какой конкретный(е) объект(ы) можно читать или изменять
- Доступ к действию: что можно сделать (читать vs редактировать vs удалять vs экспорт)
- Доступ к полям: какие свойства возвращаются или принимаются
Правило, которое ловит большинство утечек
Считайте клиентов недоверенными, даже ваш фронтенд. Если в запросе есть id, tenantId или роль, воспринимайте это как подсказку, а не как факт. Сервер должен выводить identity и tenant из сессии или токена, затем применять это ко всем запросам и записям.
При ревью кода смотрите места, где есть только один слой. Если любой маршрут возвращает данные, спросите: применяли ли мы проверки на уровне маршрута, записи, действия и полей, или сделали только одну и надеялись, что этого хватит?
Начните с карты прав, которой реально можно следовать
Большинство ошибок авторизации начинается как проблема документации. Никто не может ответить в одном месте: «Кто чему и какие записи может?» Поэтому проверки добавляются по ходу, маршруты дрейфуют, и привилегии медленно нарастают.
Карта прав — это справочник простым языком, который вы можете держать открытым при аудите маршрутов и запросов. Делайте её достаточно короткой, чтобы нетехнический коллега мог её прочесть и заметить странное правило.
1) Напишите таблицу ролей и действий (без кодовых сокращений)
Начните с ролей, которые у вас есть в продакшене, а не из тех, которые вы планируете иметь. Затем соотнесите их с действиями простыми глаголами: просматривать, создать, редактировать, удалить, приглашать, экспортировать, менять биллинг.
| Role | Can view | Can create | Can edit | Can delete | Can manage users |
|---|---|---|---|---|---|
| Member | Own items | Yes | Own items | No | No |
| Manager | Org items | Yes | Org items | Limited | Invite members |
| Admin | Org items | Yes | Org items | Yes | Full |
Если правило нельзя описать без уточнений — это признак того, что нужна ещё одна роль или понятие вроде «owner».
2) Отметьте каждую границу тенанта и ключ, который её даёт
Во многих приложениях больше одной границы: account, org, workspace, project. Запишите каждую и выберите ключ скоупа для неё (например, org_id или workspace_id). Затем перечислите ресурсы и ключ, который всегда должен присутствовать.
При этом концентрируйтесь на трёх вопросах:
- Что определяет скоуп ресурса (org_id, workspace_id, project_id)?
- Откуда приходит этот скоуп (сессия, токен, URL, тело запроса)?
- Какие границы никогда нельзя пересекать?
Наконец, определите «владельца» для каждого ресурса. «Владелец» не универсален. Коммент может принадлежать создателю, задача — назначенному исполнителю, счёт — аккаунту.
Конкретный пример: если «владелец» документа — это «создатель», то менеджер не должен автоматически редактировать любой документ, если ваша таблица явно не говорит, что менеджеры могут править все документы организации. Эта деталь предотвращает распространённую ошибку: использование проверок роли вместо скопинга по тенанту.
Пошаговый аудит: API-маршруты и серверные обработчики
Ошибки авторизации часто прячутся в скучных местах: маршруты, о которых забыли, обработчик «просто обновляет запись», или админ‑эндпоинт, которому так и не добавили настоящие проверки. Аудит — это в основном инвентаризация плюс дисциплина.
1) Перечислите все маршруты (да, все)
Перечислите каждый API-маршрут, который открытое ваше приложение, включая внутренние, админские и «временные» эндпоинты, добавленные во время прототипирования. Эти эксперименты часто остаются и остаются доступными.
Выберите один источник правды (файл маршрутизатора, папку с маршрутами фреймворка или конфигурацию API-шлюза) и составьте простую таблицу. Если найдете маршруты, которые больше не используются — пометьте их для удаления, но сначала проверьте.
2) Для каждого маршрута пропишите: актор, действие, ресурс, граница тенанта
Для каждого маршрута напишите одно предложение простым языком:
- Актор: кто вызывает (залогиненный пользователь, админ организации, системная задача)?
- Действие: что делает (читать, создать, обновить, удалить)?
- Ресурс: какой объект затрагивается (invoice, project, user, file)?
- Граница тенанта: какой контейнер должен совпадать (org_id, workspace_id, account_id)?
Если вы не можете описать правило в одном предложении — код, как правило, непоследователен.
3) Проверяйте scope тенанта на сервере, не на клиенте
Убедитесь, что обработчик получает tenant из аутентифицированной сессии (или серверных claims токена), а не из полей тела запроса или query params.
Красный флаг: запрос содержит orgId, а сервер ему доверяет. Более безопасный паттерн: читать org_id из сессии пользователя и затем применять его ко всем запросам и мутациям.
4) Убедитесь, что записи при записи тоже ограничены (не только при чтении)
Команды часто ограничивают страницы списка, но забывают обновления и удаления. Ищите эндпоинты вроде:
PATCH /projects/:idDELETE /invoices/:idPOST /members/:id/role
Если обработчик обновляет только по id, это мгновенный риск межтенантного доступа. Проверка должна выглядеть как: «запись с этим id И этим tenant принадлежит этому актору.»
5) Следите за маршрутами, которые принимают ID и делают «голый» фетч
Любой маршрут, который принимает id, — это точка повышенного риска. Опасная схема:
- получить по
id - проверить что-то расплывчато (или не проверять)
- вернуть или изменить
Вместо этого применяйте авторизацию как часть lookup. Если запись не находится в тенанте актёра (или актёр не имеет прав), lookup должен завершиться неудачей.
Пошаговый аудит: запросы в БД и фильтры ORM
Авторизация может выглядеть правильно в контроллере, но тихо сломаться на уровне базы данных. Если запрос может вернуть записи из другого тенанта, приложение в конце концов их покажет, возможно в поиске, экспортах или пограничных кейсах, которые вы не тестировали.
Начните с поиска всех мест, где приложение читает «много строк» (страницы списка, поиск, админ-таблицы, фоновые задания). Для каждого запроса задайте один вопрос: где применяется фильтр по тенанту и можно ли его пропустить?
1) Аудит запросов списка (many rows)
Откройте каждый endpoint списка и проследите до вызова ORM. Ограничения по тенанту должны быть частью запроса к базе данных каждый раз, а не добавляться позже в памяти.
Чеклист, который ловит большинство утечек:
- Скоуп по тенанту в самом SQL/ORM-запросе (не фильтруется после получения).
- Пагинация использует тот же scoped query (запрос на count и данные совпадают по скоупу).
- Условия поиска комбинируются с скоупом тенанта через AND, а не OR.
- Логика сортировки и курсоров не откатывается к неограниченному базовому запросу.
includeсвязанных данных не подтягивает дочерние записи из других тенантов.
2) Аудит detail-запросов (single row)
Эндпоинты деталей никогда не должны искать только по id. Lookup должен включать tenantId и id (или другой уникальный ключ, ограниченный тенантом). Если у ORM есть helpers вроде findUnique(id), считайте их подозрительными, если уникальный ключ не включает tenantId.
Предпочитайте findFirst where tenantId = X and id = Y вместо find by id then check tenant later. Второй паттерн легко забыть в одном обработчике.
3) Joins, экспорты и «специальные» запросы
Join’ы — частое место, где scoping по тенанту исчезает. Запрос может начинаться со скоупом, затем джойнить другую таблицу и фильтровать по неверному полю тенанта (или вовсе не фильтровать).
Проверьте также отчёты, экспорты и фоновые задачи. Они часто обходят обычный API‑код, поэтому им нужны те же правила scoping на уровне запроса.
Частые ловушки, приводящие к постепенному расширению прав
Privilege creep редко происходит потому, что кто-то явно написал «всё разрешено». Это накапливающиеся мелкие сокращения: один маршрут доверяет UI, другой считает, что «admin» — глобальный, третий забывает про фоновую задачу.
Ошибка 1: доверять клиенту (флаги UI, скрытые кнопки)
Если пользователь может отредактировать запрос, он может отправить любой запрос, который поддерживает браузер. Скрытая кнопка «Delete» или client-side поле role: "admin" — это не защита. Сервер должен решать, исходя из залогиненной личности.
Распространённый пример: UI скрывает «Edit invoice», если вы не менеджер, но API‑маршрут проверяет только, что вы вошли. Любой может вызвать маршрут напрямую и обновить чужой счёт.
Ошибка 2: использование isAdmin без скоупа тенанта
«Admin» бессмыслен без уточнения: admin чего? В мульти‑тенантных приложениях почти все роли должны быть ограничены тенантом. Ловушка — писать логику «if isAdmin, allow» и нечаянно давать доступ по всем тенантам.
Более безопасная мысль: каждое решение по авторизации должно отвечать на два вопроса: «кто этот пользователь?» и «к какому тенанту относятся эти данные?» Если любой ответ расплывчат — вы в одном рефакторе от межтенантного доступа.
Ошибка 3: проверять после загрузки записи
Многие утечки происходят, потому что код сначала получает запись, а потом проверяет, может ли пользователь её видеть. Даже если вы блокируете ответ, информация может просочиться через разные коды ошибок (404 vs 403), различия в таймингах или связанные данные, загруженные параллельно.
Лучше включать правила владения и тенанта прямо в запрос к БД, чтобы запись вообще не извлекалась для неавторизованных.
Ошибка 4: забытые «боковые двери» (jobs, webhooks, загрузки)
Фоновые задания, cron‑таски, обработчики webhook и эндпоинты скачивания файлов часто пропускают обычноe middleware и получают более слабые проверки. Если задача обрабатывает «все счета» без фильтра по тенанту, она может отправить или экспортировать чужие данные.
Для таких путей убедитесь, что можно ответить на вопросы: аутентифицирует ли это вызывающего (или валидирует вебхук), применяется ли scoping по тенанту в каждом запросе и логируется ли, что было затронуто (tenant id, record id, actor)?
Ошибка 5: общие хелперы с непонятными дефолтами
Хелпер вроде getUserProjects(userId) кажется безопасным, пока кто‑то не переиспользует его в админском экране и не предполагает, что он возвращает «все проекты». Или ещё хуже — хелпер по умолчанию не ставит фильтр по тенанту, если tenantId отсутствует.
Хорошие хелперы «проваливаются громко». Если tenantId обязателен для безопасности, сделайте его обязательным в сигнатуре функции и бросайте ошибку, если он отсутствует.
Реалистичный пример: один плохой маршрут — одна большая утечка
Представьте роль Support Agent. Ему можно просматривать тикеты, но только их собственной организации (своего тенанта). Звучит просто, но один неаккуратный эндпоинт ломает правило.
Ошибка: API имеет маршрут GET /api/tickets/:ticketId. Обработчик проверяет, что пользователь залогинен, затем получает тикет по ID. Он никогда не проверяет тенант.
// Unsafe: fetches by ID only
const ticket = await db.ticket.findUnique({
where: { id: ticketId }
});
return ticket;
Почему это даёт утечку: ID тикетов часто попадают туда, где их может увидеть пользователь — в URL браузера, уведомлениях по почте, логах инструментов поддержки или экспортированных CSV. Даже без этого многие приложения используют предсказуемые ID (инкрементные числа, короткие UUID, показанные в UI). Любопытный или злоумышленник может подменить ID и увидеть тикет другой организации.
Это одна из самых распространённых ошибок: код принимает, что знание ID — доказательство права видеть запись.
Более безопасный обработчик делает два отличия:
- ограничивает запрос по тенанту (org) из сессии.
- проверяет роль на действие (просмотр тикета).
// Safer: enforce role + tenant scoping
if (user.role !== "support_agent") throw new Error("Forbidden");
const ticket = await db.ticket.findFirst({
where: { id: ticketId, orgId: user.orgId }
});
if (!ticket) throw new Error("Not found");
return ticket;
Обратите внимание на поведение «Not found». Оно не подтверждает, существует ли тикет в другом орге.
Чтобы проверить исправление, держите тест простой:
- Создайте две организации, Org A и Org B.
- Создайте тикет в Org B.
- Войдите как Support Agent в Org A.
- Вызовите endpoint с
ticketIdиз Org B. - Убедитесь, что вернулся «Not found» (или 404), и никаких данных тикета не возвращено.
Быстрые проверки, которые можно выполнить перед релизом
Большинство ошибок авторизации проявляется на последнем этапе: новый маршрут, «полезный» админ‑шорткат или запрос, который забыл scoping по тенанту. Эти проверки простые и повторяемые.
Тест «двух аккаунтов» (10 минут)
Создайте два тестовых аккаунта в разных тенантах (Company A и Company B) с реалистичными данными, чтобы было видно, что где принадлежит.
Затем умышленно смешайте идентификаторы:
- Скопируйте ID записи из Tenant A и попробуйте прочитать её из Tenant B.
- Попробуйте обновление, передав ID Tenant A, будучи залогиненым как Tenant B.
- Попробуйте удаление с ID Tenant A под учёткой Tenant B.
- Если в приложении есть soft delete, протестируйте восстановление.
- Повторите для дочерних объектов (комментарии, счета, файлы), которые могут иметь иной скоуп.
Если что‑то из этого проходит или возвращает реальные данные — скорее всего, у вас отсутствуют фильтры по тенанту или проверка роли выполняется только в UI.
Не забудьте про bulk и «задние двери»
Утечки часто происходят вне основных CRUD‑экранов. Страница списка может быть ограничена, а экспорт — нет. Загрузка файла может пропускать проверки, потому что это «всего лишь URL».
Быстрый проход по следующим вещам:
- Страницы списка с фильтрами, поиском, сортировкой и пагинацией (попробуйте поискать известное значение из другого тенанта).
- Экспортные endpoints (CSV, PDF, отчёты) и фоновые задачи, которые их генерируют.
- Загрузки файлов и превью (signed URLs, attachment IDs, image endpoints).
- Логи активности, админ‑дашборды и виджеты «недавние элементы».
- Любой маршрут, который принимает ID в пути, даже если UI его никогда не показывает.
Также подтвердите, что ваши админ‑роли соответствуют желаемому скоупу. «Тенант-админ» не должен работать как «глобальный админ» только потому, что это удобно.
Следующие шаги: сделайте авторизацию трудно сломать
Сбой авторизации редко случается из‑за безразличия. Он происходит потому, что проверки разбросаны, фильтры по тенанту легко забыть, а новые функции выпускают быстрее, чем правила обновляются. Цель — сделать безопасный путь самым простым.
Поставьте один ограждающий слой перед всем
Используйте единый слой авторизации везде: middleware, policy helper или сервисную функцию, которую вызывает каждый обработчик до выполнения работы. Если вам нужно помнить, какие маршруты «нужно проверять», вы что‑то пропустите.
Практическое правило: обработчики маршрутов не должны содержать кастомную логику прав. Они должны задать полис‑слою четкий вопрос (например, «может ли этот пользователь обновить этот счёт?») и затем продолжить.
Быстрые изменения, которые сокращают ошибки:
- Сделайте один policy helper (или middleware) на ресурс: read, create, update, delete.
- Сделайте scoping по тенанту значением по умолчанию (например, scoped query helper, который всегда применяет tenantId).
- Отказывайте по умолчанию, когда данных недостаточно или есть неоднозначность (нет тенанта, нет роли, нет владельца).
- Логируйте отказы в авторизации с достаточным контекстом для дебага (пользователь, тенант, ресурс, действие).
Вплетите scoping по тенанту в доступ к данным
Централизуйте scoping по тенанту, чтобы его было трудно забыть. Лучшее место — там, где формируются запросы, а не там, где возвращаются ответы.
Например, вместо where: { id } по всему коду, экспортируйте хелпер, который уже включает tenantId. Если разработчик попытается обойти его, это должно сразу бросаться в глаза при ревью кода.
Высокоценные тесты ловят регрессии, которые действительно важны:
- Кросс‑тенантное чтение не должно проходить (Пользователь A не может получить запись Пользователя B по ID).
- Кросс‑тенантная запись не должна проходить (Пользователь A не может обновить/удалить запись Пользователя B).
- Понижение роли безопасно (пользователь, лишённый прав админа, не должен сохранять админский доступ).
- Создание записей проставляет правильный tenant (новые записи маркируются текущим тенантом).
Если вы унаследовали код, сгенерированный ИИ, и не уверены, что scoping по тенанту и проверки ролей применяются последовательно, сфокусированный аудит может сэкономить дни догадок. FixMyMess (fixmymess.ai) специализируется на диагностике и починке таких пробелов в авторизации, особенно обработчиков «только по id» и неограниченных запросов, которые выглядят нормально, пока реальные пользователи не попадут в продакшен.
Часто задаваемые вопросы
Why can users see someone else’s data even though login works?
Это проблема авторизации, а не аутентификации. Пользователь может быть полностью залогинен, но сервер не всегда последовательно проверяет, принадлежит ли запрашиваемая запись этому пользователю/команде/тенанту, прежде чем вернуть её.
What’s the difference between authentication and authorization?
Аутентификация отвечает на вопрос «кто вы?», а авторизация — «что вам разрешено делать, и какие записи ваши?». Большинство утечек между аккаунтами происходит, когда приложение лишь проверяет, что пользователь вошёл, а затем возвращает данные по id без проверки владельца или границ тенанта.
Do I need role checks, tenant scoping, or both?
Проверки ролей определяют, какие действия разрешены (например, «может редактировать счета»). Ограничение по тенанту определяет, где эти действия разрешены (например, «только в этой рабочей области»). Обычно нужны оба механизма: роль — что, тенант — где.
Which endpoints are most likely to leak cross-tenant data?
Любой endpoint, который принимает id, — это горячая точка, особенно загрузки, экспорты и маршруты «деталей». Если обработчик получает запись только по id, пользователь может подменить идентификатор и получить доступ к данным другого тенанта.
If the UI hides admin features, is that enough security?
Нет. Скрытие кнопок улучшает удобство, но не защищает API. Предположите, что любой может напрямую вызвать ваши маршруты, поэтому сервер должен проверять права и принадлежность по тенанту при каждом чтении и записи.
What’s the “admin trap” and how do I avoid it?
«Admin» должен иметь область действия. Тенант-админ управляет внутри своей рабочей области, глобальный админ видит всё и должен быть редким и строго контролируемым. Если код трактует любой admin как глобальный, вы можете случайно дать доступ к данным других клиентов.
Why is it risky to load a record first and check access afterward?
Потому что легко забыть один обработчик, и через побочные эффекты всё ещё могут раскрыться данные (различия 404 vs 403, тайминги, связанные подгруженные данные). Надёжнее включать правила владения и тенанта прямо в запрос к базе, чтобы неподходящие записи вообще не извлекались.
Should the server trust tenantId or role sent from the client?
Получайте личность и тенант из сессии на сервере или из claims токена, затем применяйте их ко всем запросам и мутациям. Любые tenantId, role или userId, приходящие от клиента, воспринимайте как подсказку, но не как факт.
What’s the fastest way to smoke test for authorization leaks?
Создайте два аккаунта в разных тенантах с разными данными. Подойдёт простая проверка: под учёткой Tenant B попробуйте прочитать/обновить/удалить записи Tenant A, используя их id. Если что-то возвращает реальные данные — есть пробел в ограничениях по тенанту.
Why do AI-generated CRUD apps have so many authorization bugs, and what can I do?
Прототипы, созданные ИИ, быстро решают аутентификацию, но правила авторизации часто применяются несогласованно по маршрутам и запросам, особенно в скопированных хендлерах и «временных» эндпоинтах. Если вы унаследовали такой код и хотите быстро сделать его безопасным для продакшена, FixMyMess может провести фокусированный аудит и починить обработчики «только по id», незащищённые запросы и ошибки ролей/тенантов, обычно за 48–72 часа после бесплатной проверки кода.