Кейс OnePercent: как довести кастомный SaaS от прототипа до production
Рабочий прототип умеет показать основную идею продукта. Пользователь нажимает кнопку, система получает данные, выполняет расчёт и выдаёт результат. Для демонстрации инвестору, партнёру или первым клиентам этого достаточно.
Но production начинается там, где приложением пользуются не разработчики, а реальные люди. Они дважды нажимают кнопку, закрывают вкладку посреди операции, загружают файл не того формата, забывают пароль и ожидают, что данные не пропадут после обновления сервера.
Рабочий прототип умеет показать основную идею продукта. Пользователь нажимает кнопку, система получает данные, выполняет расчёт и выдаёт результат. Для демонстрации инвестору, партнёру или первым клиентам этого достаточно.
Но production начинается там, где приложением пользуются не разработчики, а реальные люди. Они дважды нажимают кнопку, закрывают вкладку посреди операции, загружают файл не того формата, забывают пароль и ожидают, что данные не пропадут после обновления сервера.
На примере OnePercent разберём не интерфейс и не отдельные функции, а менее заметную часть разработки: как превратить работающий прототип в кастомный SaaS, который можно выпускать, поддерживать и развивать.
Часть продуктовых и клиентских деталей проекта не раскрывается. Поэтому здесь нет придуманных цифр роста, количества пользователей или экономии. Фокус — на инженерных решениях, без которых прототип нельзя честно назвать production-системой.
> ## Коротко > > Чтобы довести кастомный SaaS до production, недостаточно закончить основной пользовательский сценарий. Нужно определить границы системы, разделить права доступа, защитить операции от повторного запуска, вынести долгие задачи в фон, настроить логи, резервное копирование, мониторинг и управляемый релиз. > > В OnePercent переход к production строился не вокруг идеи «добавить ещё функций», а вокруг другого вопроса: что произойдёт, если пользователь ошибётся, внешний сервис не ответит, задача прервётся или новая версия приложения окажется неудачной? > > Production-ready SaaS — это не приложение без ошибок. Это система, в которой ошибки обнаруживаются, локализуются и исправляются без потери данных и ручного расследования по переписке с клиентом.
Главная проблема: прототип доказывает функцию, но не надёжность
У прототипа и production-продукта разные задачи.
Прототип отвечает на вопрос: «Можно ли реализовать этот сценарий?» Production должен отвечать ещё на несколько:
- кто имеет право запускать операцию;
- что произойдёт при повторном запросе;
- где хранится состояние процесса;
- можно ли восстановить данные;
- как понять, на каком шаге возникла ошибка;
- кто увидит сбой раньше — команда или клиент;
- как откатить неудачный релиз;
- можно ли безопасно изменить логику через месяц.
Типичная ошибка — продолжать наращивать функции, не закрыв эти вопросы. В результате появляется эффектный интерфейс, который работает только при идеальном сценарии.
Например, пользователь запускает формирование отчёта. В демо всё выглядит просто: запрос уходит на сервер, сервер собирает данные и возвращает файл. Но в реальной работе отчёт может строиться несколько минут. Пользователь обновит страницу, нажмёт кнопку ещё раз или закроет ноутбук. Внешний API может вернуть ошибку на 80% операции.
Если система не хранит состояние задачи, не защищена от дублей и не умеет повторять безопасные шаги, каждый такой случай превращается в ручной разбор.
Это актуально не только для сложных SaaS. Та же проблема возникает в автоматизации продаж, поддержки и маркетплейсов:
- лид дважды создаётся в CRM;
- клиент получает два одинаковых сообщения в Telegram;
- остатки WB или Ozon загружаются частично;
- отчёт содержит данные только по одному кабинету;
- AI-агент повторно выполняет подтверждённое действие;
- менеджер меняет статус сделки, но интеграция продолжает работать со старым значением.
Поэтому переход к production начинается не с выбора облака или фреймворка. Сначала нужно описать состояние системы и последствия сбоев.
Шаг 1. Зафиксировать границы первой production-версии
У прототипа границы часто размыты: команда добавляет всё, что помогает показать ценность. Перед релизом такой подход становится опасным. Каждая новая функция увеличивает число сценариев, которые придётся тестировать, наблюдать и поддерживать.
Для OnePercent production-контур определялся через обязательные пользовательские потоки:
- пользователь получает доступ к системе;
- выполняет основную операцию;
- видит её статус и результат;
- может понять причину корректируемой ошибки;
- обращается в поддержку с идентификатором операции;
- администратор находит событие в журнале и восстанавливает ход выполнения.
Если функция не участвовала в этом контуре и не была критична для запуска, её можно было перенести в следующую версию.
Это важная дисциплина для кастомного SaaS. Первая production-версия не обязана закрывать весь будущий продукт. Она обязана целиком закрывать ограниченный набор процессов.
Лучше надёжно провести заявку от формы до CRM и уведомления менеджеру, чем одновременно подключить скоринг, генерацию коммерческого предложения, автообзвон и пять каналов аналитики — но не понимать, где теряются данные.
Шаг 2. Разделить продуктовую логику и интеграции
На стадии прототипа удобно связать всё напрямую. Обработчик кнопки получает данные, обращается к внешнему API, записывает результат и отправляет уведомление.
Такой код быстро создаётся, но плохо переживает изменения. Если CRM недоступна, ломается весь запрос. Если меняется API поставщика, приходится затрагивать продуктовую логику. Если нужно добавить Telegram или другую систему, появляются почти одинаковые ветки кода.
В production-контуре OnePercent внешние системы важно было воспринимать не как часть ядра продукта, а как ненадёжных соседей. У них могут быть:
- ограничения по количеству запросов;
- изменившиеся поля ответа;
- временные ошибки;
- задержки;
- неполные данные;
- разные правила авторизации.
Поэтому между ядром SaaS и интеграцией нужен явный слой. Он отвечает за преобразование данных, повторные попытки, таймауты и обработку ошибок.
Практический принцип простой: сбой внешнего сервиса не должен уничтожать уже принятые системой данные. Если заявка создана, но CRM временно не отвечает, заявка должна остаться в базе со статусом «ожидает отправки», а не исчезнуть вместе с ошибкой HTTP-запроса.
Этот же подход нужен при работе с WB и Ozon. Получение заказов, остатков, цен и рекламной статистики лучше хранить как отдельные синхронизации с понятным временем обновления. Тогда пользователь видит, какие данные актуальны, а какие не удалось обновить. Система не маскирует частичный сбой под корректный отчёт.
Шаг 3. Вынести долгие операции из веб-запроса
Веб-запрос должен завершаться быстро. Если внутри него строится большой отчёт, обрабатывается файл, вызывается AI-модель или последовательно опрашиваются несколько API, соединение может оборваться раньше окончания операции.
Для пользователя это выглядит как зависшая кнопка. Для команды — как задача, о судьбе которой ничего не известно.
В production-архитектуре долгую операцию лучше оформлять как отдельную задачу:
- пользователь отправляет запрос;
- система проверяет данные и права;
- создаёт задачу с уникальным идентификатором;
- фоновый обработчик забирает её в работу;
- статус меняется по мере выполнения;
- результат сохраняется отдельно;
- интерфейс показывает итог или понятную ошибку.
Так появляется наблюдаемое состояние: «создано», «в очереди», «выполняется», «завершено», «ошибка», «отменено».
Для OnePercent это было важнее визуальной анимации загрузки. Индикатор сам по себе не делает процесс надёжным. Надёжность появляется, когда задача существует независимо от вкладки браузера и её состояние можно проверить после перезагрузки страницы.
Так же стоит строить импорт лидов, массовое обновление карточек, генерацию документов, обработку отзывов, синхронизацию CRM и сбор отчётов по маркетплейсам.
Шаг 4. Защититься от повторных действий
Пользователи нажимают кнопки несколько раз. Интеграции повторяют запросы после таймаута. Очередь может вернуть задачу в обработку, если исполнитель не успел подтвердить завершение.
Поэтому критичные операции должны быть идемпотентными: повтор одного и того же запроса не должен создавать новый побочный эффект.
На уровне интерфейса кнопку можно временно заблокировать, но этого недостаточно. Защита должна работать на сервере.
Для операции создаётся устойчивый ключ или проверяется её текущее состояние. Если запрос уже принят, система возвращает существующий результат или статус, а не запускает процесс заново.
Особенно важно проверять:
- создание платежа;
- отправку сообщения клиенту;
- изменение цены;
- формирование заказа;
- списание лимита;
- публикацию контента;
- передачу лида в CRM;
- действие AI-агента во внешней системе.
Если AI предлагает ответ менеджеру, повторная генерация обычно безопасна. Если агент отправляет сообщение, меняет статус сделки или редактирует карточку товара, нужен отдельный контроль выполнения. Подробнее о разнице между демонстрацией и рабочим агентом — в статье «AI-агент для бизнеса: что это и как работает».
Шаг 5. Спроектировать роли и права до появления команды клиентов
На старте часто существует один тип пользователя: владелец аккаунта. Затем появляются сотрудники, подрядчики, операторы поддержки и администраторы. Если права не были заложены заранее, ограничения начинают добавлять отдельными условиями в разных частях кода.
Это приводит к опасным расхождениям: в интерфейсе кнопка скрыта, но API по-прежнему позволяет выполнить действие.
В OnePercent доступ нужно было рассматривать на трёх уровнях:
- к какому аккаунту или организации относится пользователь;
- какие сущности этого аккаунта он может видеть;
- какие действия над ними ему разрешены.
Проверка должна выполняться на сервере при каждом защищённом запросе. Интерфейс лишь отражает права, но не является средством защиты.
Для SMB-систем это особенно важно. Менеджеру по продажам может быть доступна работа с его сделками, но не выгрузка всей клиентской базы. Специалисту по маркетплейсам — аналитика и черновики изменений, но не платёжные реквизиты. AI-агенту — чтение данных и подготовка рекомендаций, но не безусловная публикация или изменение цены.
Принцип минимальных прав снижает не только риск атаки, но и цену обычной ошибки.
Шаг 6. Сделать ошибки полезными
Сообщение «Что-то пошло не так» допустимо для пользователя, если рядом есть следующий шаг. Для команды его недостаточно.
У каждой значимой операции должен быть идентификатор. Он связывает пользовательский экран, серверный лог и фоновую задачу. Тогда поддержка может найти конкретный сбой без просьб «повторите ещё раз и снимите видео».
Хорошая обработка ошибки отвечает на четыре вопроса:
- что выполнялось;
- на каком шаге произошёл сбой;
- можно ли безопасно повторить операцию;
- нужны ли действия пользователя.
Пользователю не следует показывать внутренний стек ошибки, токены или технические детали. Но и скрывать всё нельзя.
Например:
- «Файл не обработан: в колонке “Цена” найден текст. Исправьте строку 48 и загрузите файл повторно»;
- «CRM временно не ответила. Заявка сохранена и будет отправлена автоматически»;
- «Синхронизация Ozon завершена частично: данные по двум кабинетам обновлены, по одному требуется повторный вход»;
- «Отчёт не сформирован. Код операции: OP-1842».
Такие сообщения уменьшают нагрузку на поддержку и помогают пользователю исправлять предсказуемые ошибки самостоятельно.
Шаг 7. Добавить логи, аудит и мониторинг
Логирование — это не сохранение всего текста, который проходит через приложение. Избыточные логи усложняют поиск и могут привести к утечке персональных данных или секретов.
Для OnePercent полезным был структурированный подход: каждое событие содержит тип операции, идентификатор пользователя или аккаунта, идентификатор задачи, статус, время выполнения и безопасное описание ошибки.
Отдельно нужен аудит действий: кто, когда и что изменил. Это особенно важно для настроек, прав доступа, удаления данных и операций, влияющих на клиентов или деньги.
Мониторинг отвечает уже не на вопрос «что произошло с одной задачей», а на вопрос «что происходит с системой в целом». Минимальный production-набор должен отслеживать:
- доступность приложения;
- долю серверных ошибок;
- рост времени ответа;
- длину очереди фоновых задач;
- число неуспешных интеграций;
- заполнение диска и состояние базы;
- срок действия сертификатов и критичных ключей;
- успешность резервного копирования.
Наличие резервной копии тоже нужно проверять. Файл в хранилище ещё не доказывает, что базу можно восстановить. Нужен хотя бы периодический тест восстановления в отдельном контуре.
Шаг 8. Сделать релиз обратимым
Релиз — не момент, когда разработчик загрузил новую версию. Это управляемая последовательность действий:
- проверить сборку и автоматические тесты;
- применить изменения конфигурации;
- выполнить миграции базы;
- запустить новую версию;
- проверить критичные сценарии;
- наблюдать за ошибками после запуска;
- при необходимости откатить изменение.
Самая опасная часть — миграции данных. Код можно вернуть к предыдущей версии, а удалённую колонку или испорченные записи — не всегда.
Поэтому безопаснее вносить изменения совместимо: сначала добавить новое поле, научить приложение работать с обеими версиями структуры, перенести данные и только затем удалять старое.
Перед production-релизом OnePercent критично было проверить не только «открывается ли главная», но и полный короткий маршрут: вход, основная операция, фоновая обработка, сохранение результата и доступ администратора к журналу.
Такой smoke-тест занимает меньше времени, чем разбор ситуации, когда сервер формально отвечает, но ключевой сценарий сломан.
Где появляется экономия времени и денег
У production-подготовки редко есть эффектная цифра на следующий день. Её ценность проявляется в повторяемости операций и снижении стоимости каждого сбоя.
Если фоновые задачи имеют статусы, поддержке не нужно спрашивать разработчика, завершился ли импорт. Если интеграция умеет повторять временные ошибки, сотрудник не переносит данные вручную. Если есть аудит, команда не восстанавливает историю изменений по сообщениям в Telegram.
Экономия складывается из конкретных участков:
- меньше повторной обработки одних и тех же данных;
- меньше ручного контроля интеграций;
- быстрее диагностика обращений;
- безопаснее выпуск небольших обновлений;
- ниже вероятность потери заявки или результата;
- проще подключать новых сотрудников и клиентов;
- меньше зависимость от одного разработчика, который «помнит, как всё устроено».
Для расчёта эффекта полезно измерить не абстрактную производительность, а текущую цену исключений.
Например, если менеджер трижды в неделю вручную разбирает дубли заявок, специалист каждый день проверяет выгрузку Ozon, а разработчик тратит несколько часов на поиск каждой ошибки без идентификатора операции, это уже измеримый резерв.
Сначала стоит определить сам процесс и его слабые места. Для этого можно использовать подход из статьи «Как понять, что процесс пора автоматизировать».
Что нельзя откладывать «на потом»
Не каждый прототип требует сложной инфраструктуры. Но есть вещи, которые дорого добавлять после появления реальных пользователей.
Изоляция данных
Данные одного клиента не должны смешиваться с данными другого ни в интерфейсе, ни в API, ни в фоновых задачах. Проверка принадлежности записи аккаунту должна быть частью серверной логики.
Управление секретами
Ключи API, пароли и токены нельзя хранить в коде, логах или клиентском приложении. Для них нужны отдельное хранилище, ограниченный доступ и понятная процедура замены.
Резервное копирование
Нужно заранее определить, что копируется, как часто, сколько хранятся копии и сколько времени займёт восстановление.
Контроль действий AI
Если в продукте используется AI, модель не должна получать больше данных и полномочий, чем требуется для задачи. Генерация рекомендации и выполнение действия — разные операции.
Черновик ответа клиенту можно показать менеджеру. Возврат денег, изменение цены, удаление записи или массовую рассылку безопаснее проводить через подтверждение, лимиты и журнал действий.
Удаление и экспорт данных
Даже если эти функции не вынесены в интерфейс первой версии, команда должна понимать, как выгрузить данные клиента и как удалить их без повреждения связанных сущностей.
Практический план перехода от прототипа к production
Работу удобнее вести не по слоям «сначала весь backend, потом весь frontend», а по сквозным пользовательским сценариям.
1. Выбрать критичный маршрут
Например: регистрация → создание проекта → запуск обработки → получение результата.
Для CRM-автоматизации это может быть: заявка с сайта → проверка → создание контакта и сделки → уведомление менеджера.
2. Описать состояния и сбои
Для каждого шага определить:
- какие данные приходят;
- где они сохраняются;
- что считается успешным результатом;
- какие ошибки можно повторить;
- где нужен человек;
- что увидит пользователь.
3. Закрыть доступ и дубли
Добавить серверную проверку прав, уникальные ключи операций и защиту критичных действий от повторного выполнения.
4. Вынести долгие задачи в очередь
Не удерживать браузерное соединение ради импорта, отчёта, AI-обработки или синхронизации внешних кабинетов.
5. Настроить наблюдаемость
Связать пользовательскую операцию, задачу и лог одним идентификатором. Добавить уведомления о системных сбоях и отдельный аудит значимых действий.
6. Подготовить данные к изменениям
Проверить резервные копии, миграции и возможность отката. Отдельно протестировать восстановление, а не только создание копии.
7. Провести ограниченный запуск
Первые пользователи должны работать в настоящем production-контуре, но с контролируемым объёмом. Это позволяет найти реальные пограничные сценарии без массового ущерба.
8. Разбирать исключения, а не только запросы на функции
После запуска полезнее сначала изучать не список пожеланий, а случаи, где потребовалось ручное вмешательство. Именно они показывают, чего системе не хватает для устойчивой эксплуатации.
Чек-лист production-ready SaaS
Перед релизом проверьте:
- основной пользовательский сценарий проходит целиком;
- права проверяются на сервере;
- данные клиентов изолированы;
- критичные операции защищены от дублей;
- долгие процессы выполняются в фоне;
- пользователь видит состояние задачи;
- временные ошибки интеграций повторяются безопасно;
- частичный результат не выдаётся за полный;
- секреты не попадают в код, браузер и логи;
- у операций есть идентификаторы;
- значимые изменения записываются в аудит;
- настроены мониторинг и уведомления;
- резервные копии создаются и восстанавливаются;
- миграции данных обратимы или совместимы с предыдущей версией;
- существует короткий smoke-тест после релиза;
- команда знает, как откатить неудачное обновление;
- опасные действия AI требуют подтверждения или ограничены правилами;
- у поддержки есть способ найти проблему без прямого доступа к production-базе.
Если на несколько пунктов ответ «потом», продукт всё ещё ближе к прототипу, чем к production.
FAQ
Чем production-версия отличается от MVP?
MVP — это минимальная версия продукта, достаточная для проверки ценности и спроса. Production — характеристика среды и качества эксплуатации.
MVP может быть production-ready, если он закрывает мало функций, но делает это надёжно. И наоборот: большое приложение с десятками экранов может оставаться прототипом, если в нём нет контроля доступа, мониторинга и восстановления после сбоев.
Нужно ли сразу строить микросервисную архитектуру?
Нет. Для первой версии кастомного SaaS модульный монолит часто проще разрабатывать и поддерживать.
Разделять систему на отдельные сервисы стоит, когда для этого есть конкретная причина: независимое масштабирование, разные требования к надёжности, отдельные команды или изоляция ресурсоёмких процессов. Микросервисы без такой необходимости добавляют сетевые ошибки, сложность развёртывания и больше точек мониторинга.
Сколько времени занимает переход от прототипа к production?
Это зависит не столько от количества экранов, сколько от числа интеграций, ролей, фоновых процессов и требований к данным.
Если прототип уже имеет понятную структуру и тестируемую бизнес-логику, подготовка может быть отдельным ограниченным этапом. Если продукт собран как цепочка прямых вызовов без состояний и границ, часть системы придётся перепроектировать.
Оценивать срок лучше после аудита критичного пользовательского маршрута, а не по общему количеству функций.
Можно ли запустить SaaS без автоматических тестов?
Можно, но цена каждого изменения будет выше. Необязательно сразу добиваться максимального покрытия.
В первую очередь нужны тесты для расчётов, прав доступа, переходов между статусами, платежей и других операций, где ошибка приводит к потере данных или неверному действию. Дополнительно полезен короткий сквозной тест основного сценария после каждого релиза.
Какие логи нужны на старте?
Нужны структурированные события для входа, критичных операций, фоновых задач, интеграций и административных изменений.
В логах должны быть идентификаторы аккаунта, пользователя и операции, но не пароли, токены, полные платёжные данные и лишние персональные сведения. Лог без контекста бесполезен, а лог со всеми входными данными может стать источником утечки.
Когда в SaaS нужен human-in-the-loop?
Когда ошибка может повлиять на деньги, доступы, репутацию или данные клиента.
AI может классифицировать заявку, подготовить ответ или предложить изменение цены. Но отправку спорного сообщения, возврат платежа, удаление данных и массовое изменение карточек лучше подтверждать человеком — по крайней мере до тех пор, пока сценарий не измерен и не ограничен понятными правилами.
Что проверить сразу после релиза?
Нужно пройти критичный маршрут реальным пользовательским способом: войти, создать операцию, дождаться фоновой обработки и открыть результат.
После этого проверить ошибки, очередь задач, внешние интеграции и системные метрики. Ответ сервера 200 OK подтверждает доступность страницы, но не работоспособность продукта.
Вывод
Кейс OnePercent показывает важное различие между разработкой функции и запуском продукта. Прототип доказывает, что сценарий возможен. Production-контур делает его управляемым: с состояниями, правами, защитой от повторов, логами, восстановлением и понятной ответственностью человека.
Самая дорогая ошибка на этом этапе — пытаться компенсировать слабую основу новыми функциями. Если система теряет состояние задачи, смешивает права или не позволяет найти причину сбоя, следующий экран только увеличивает стоимость поддержки.
Правильный переход к production обычно выглядит менее эффектно, чем презентация прототипа. Но именно он превращает кастомную разработку в SaaS, которому можно доверить заявки, клиентские данные, отчёты и ежедневные бизнес-процессы.
Если хочешь понять, что автоматизировать у себя — напиши Дмитрию в Telegram @dmkosik и опиши процесс для диагностики Paramiko.