Экономика SaaS: Почему мы переплатили в 10 раз за аутентификацию и как защитили облако от спама

 · 4 min read

Разработав защищенную архитектуру облачных воркеров, о которой мы рассказывали в прошлой статье, мы решили главную инженерную задачу — ядро нашего парсера было в безопасности. Но теперь перед нами встала продуктовая проблема.

Saas Economics Abuse Protection

Как позволить разработчикам бесплатно тестировать Flude, не позволив им обанкротить нас на счетах за GCP Cloud Run? Каждая секунда парсинга стоит реальных денег. Нам нужен был Free-Tier, но с железобетонной защитой от Abuse-нагрузки. И фундаментом для этой защиты стала система аутентификации.

Фундамент: Выбор Auth-провайдера

Нам нужно было управлять пользователями, квотами и B2B-организациями. Мы рассматривали три варианта: Auth0, Supabase Auth и Clerk.

Auth0 отпал первым: у него не оказалось нативной интеграции с GitLab, а для нашего CI-инструмента GitHub, GitLab и Bitbucket должны были быть абсолютно равноправными платформами “из коробки”.

Остались Supabase Auth и Clerk. По предварительным расчетам на масштаб в 100 000 активных пользователей (MAU), Supabase обошелся бы нам в копейки, в то время как чек от Clerk был бы примерно раз в десять больше.

И тем не менее, мы выбрали более дорогой Clerk. Почему?

Во-первых, решала экономия разработки. Наш будущий тарифный план Team подразумевал мультиаккаунтность: сущность организации, роли (админ и участник) и общий биллинг. Clerk предоставлял фичу Organizations и готовые UI-компоненты “из коробки” — это идеально ложилось на нашу модель. На Supabase нам пришлось бы строить ролевую B2B-модель с нуля.

Во-вторых — архитектурная чистота. Supabase — это полноценный BaaS со своей базой PostgreSQL. Наш проект уже был прочно завязан на стек Google Cloud (в частности, Firestore). Тащить в проект вторую СУБД только ради дешевой аутентификации было бы ошибкой.

В контексте предполагаемой выручки переплата за Clerk составила бы всего пару процентов. Мы осознанно поменяли деньги на месяцы сэкономленного инженерного времени.

Эшелонированная защита (Free-Gate)

Saas Economics Abuse Protection Part 2

Получив мощный инструмент идентификации, мы приступили к настройке лимитов. Наша философия на этапе беты была простой: мы хотим поддержать инди-разработчиков и их небольшие Open Source проекты, отсекая при этом гигантские энтерпрайз-монорепозитории.

Для этого мы построили трехуровневые «ворота», отсекающие лишнюю нагрузку еще до того, как запустится тяжелый процесс парсинга в облаке:

  1. Ограничение по сущности: API-токен проверяется сервером. Если запрос приходит от аккаунта, привязанного к организации — он отклоняется. Бесплатный доступ открыт только для личных проектов, а поддержка корпоративных команд закладывается в будущие платные тарифы.
  2. Ограничение по приватности: Мы делаем дешевый предварительный запрос к публичному API (например, GitHub) до начала тяжелого клонирования репозитория. Если код приватный — отказ (rejected_private).
  3. Метрика жадности (Лимит в 5MB): Самая важная проверка происходит внутри воркера после неглубокого клонирования (git clone --depth 1). Мы не верим размеру репозитория из API (там могут лежать гигабайты мусора). Мы взвешиваем только те файлы, которые реально попали под маски включения (include_patterns). Если чистый объем кода превышает 5 МБ, воркер тут же обрывает работу.

Динамический Rate-Limit и Окно лояльности

Saas Economics Abuse Protection Part 3

Даже маленькие Open Source проекты могут запускать CI на каждый мелкий коммит по 100 раз в день. Чтобы не парсить это всё за свой счет, мы внедрили динамический rate-limit на базе Firestore.

Для новых аккаунтов мы открываем “окно лояльности”: в первые 7 дней мы разрешаем до 5 сборок в день, чтобы разработчик мог спокойно настроить CI и поиграться с конфигурацией Flude. Но спустя неделю наступает суровая реальность — лимит жестко падает до 1 бесплатной сборки в день. Хочешь парсить документацию на каждый PR — придется ждать запуска платных тарифов, которые мы пока только проектируем.

В качестве финального аккорда мы заложили в Firestore глобальный “рубильник” (system_status/global.enabled), который позволяет нам при любой инфраструктурной атаке отключить все бесплатные сборки одной кнопкой.

Что дальше?

Мы спроектировали классную бизнес-логику, защищающую наши серверы от спама, и интегрировали мощный провайдер авторизации. Но, как это часто бывает в JS-экосистеме, сторонние зависимости имеют свойство внезапно ломаться.

Интеграция Clerk и переход на новые стандарты Next.js 16 превратили разработку нашего фронтенда в настоящий квест с устаревшими функциями и сломанными роутами. Об этом (а также о том, как одна переименованная строчка сломала контракты по всей распределенной системе) — в следующем эпизоде.