# Как ломаются приложения Bolt.new в продакшене

> Узнайте, где приложения Bolt.new в продакшене ломаются первыми, как укрепить защиту и эксплуатацию и когда точечный перенос оправдает затраты.

Приложение на Bolt.new вполне может нормально работать в продакшене. Ошибка начинается, когда успешный предпросмотр принимают за доказательство готовности системы к реальным клиентам. Предпросмотр подтверждает, что удачный сценарий отображается как надо. В продакшене возникают другие вопросы: может ли посторонний пользователь прочитать чужую строку, можно ли повторить неудавшийся платеж, дойдет ли письмо до настоящего почтового ящика и сумеет ли кто-то восстановить сервис после того, как сгенерированное изменение сломает базу данных.

Я видел, как команды тратили неделю на переписывание сгенерированного интерфейса, но оставляли открытым правило авторизации, которое и создавало настоящий риск для бизнеса. Происхождение кода редко определяет результат. Все решает способность команды отвечать за эксплуатацию. Сохраняйте стек Bolt, если можете понять его, протестировать, наблюдать за ним и менять его без зависимости от истории чата. Переносите только тот компонент, чьи ограничения или сценарии отказа можете назвать.

## Работающий предпросмотр доказывает меньше, чем кажется

Первой обычно ломается гипотеза, которую скрывала среда предпросмотра, а не React или сгенерированный CSS. Один разработчик, один браузер, почти пустая база, активная сессия и тестовые данные, введенные вручную, создают слишком удобный стенд. Клиенты приходят с истекшими сессиями, двойными нажатиями, медленным мобильным интернетом, менеджерами паролей, корпоративными почтовыми фильтрами, неожиданными символами Unicode и двумя вкладками, которые одновременно меняют одну запись.

Отделяйте успешную сборку от готовности к эксплуатации. Bolt умеет публиковать сайт на Bolt Hosting, а при публикации автоматически проверяет безопасность. Это полезно, но успешный деплой и чистый результат автоматической проверки не доказывают правильность бизнес-правил. Сканер не может догадаться, что менеджеру аккаунта разрешено видеть все заказы одного клиента и ни одного заказа другого. Он не знает, что для бизнеса хуже: двойное списание после тайм-аута или потерянный заказ.

Проведите репетицию продакшена в новом профиле браузера и с аккаунтами как минимум двух организаций. Создайте данные от имени пользователя A, затем попробуйте прочитать, изменить, экспортировать и удалить их от имени пользователя B. Повторите тест с истекшей сессией, отключенным аккаунтом и дважды отправленным запросом. Проверяйте тестовый деплой с отдельной базой, а не предпросмотр в редакторе и не продакшен.

Команды часто смешивают функциональное тестирование с проверкой границ доступа. Функциональный тест выясняет, может ли пользователь с нужными правами выполнить задачу. Проверка границ выясняет, может ли посторонний пользователь, устаревший клиент или повторный запрос пересечь запретную линию. Сгенерированные приложения быстро проходят первый тип проверок, потому что именно успешный сценарий обычно описан в запросе. Для второго типа нужны явные политики и тесты с попытками нарушить правила.

Считайте предпросмотр проверкой дизайна, а тестовую среду - репетицией эксплуатации. Если команда не может сразу сказать, на какую среду смотрит, не добавляйте новые функции, пока различия не станут видны в доменах, учетных данных и проектах баз данных.

Среда редактора и среда опубликованного приложения тоже решают разные задачи. Bolt собирает проект в браузерной среде на технологии StackBlitz, а опубликованное приложение работает в инфраструктуре хостинга. В руководстве StackBlitz о поддержке WebContainers в браузерах описаны междоменная изоляция, service workers и ограничения отдельных браузеров для среды разработки. Эти детали могут объяснить, почему предпросмотр иначе ведет себя в Safari или браузере со строгой защитой приватности, но ничего не говорят о мощности опубликованных серверных функций. Ищите причину в той среде, где случился сбой, а не воспринимайте «Bolt» как единый черный ящик.

Добавьте проверку релиза, которая открывает не только главную страницу. Она должна создать временный аккаунт или взять контролируемый тестовый, прочитать одну защищенную запись, вызвать одну серверную функцию и подтвердить ожидаемую запись в базе. Запускайте ее сразу после деплоя и затем по расписанию. Если сборка прошла, а проверка релиза нет, компиляция завершилась успешно, но конфигурация, учетные данные, перенаправления или зависимый сервис подвели.

## Авторизация ломается раньше интерфейса

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

Bolt Database и Supabase поддерживают аутентификацию, серверные функции, секреты и построчные ограничения доступа. Само наличие этих средств не делает политику правильной. Security Audit в Bolt находит такие проблемы, как отсутствие политик RLS и небезопасные разрешения. Production Checklist от Supabase советует включить row level security для всех доступных извне таблиц и создать разумные политики. Я добавлю более жесткое правило: включенная политика с неверным столбцом владельца опаснее явно отсутствующей, потому что дает ложную уверенность.

Представим, что в каждой строке проекта есть `owner_id`, а позже продукт начинает поддерживать организации. Сгенерированная политика по-прежнему может сравнивать `owner_id` с текущим пользователем. Коллеги перестают видеть общие проекты, и кто-то разрешает доступ всем аутентифицированным пользователям. Приложение снова работает, но незаметно превращает всех клиентов в участников одного глобального пространства. Такой ремонт встречается часто, потому что устраняет видимый симптом.

До просьбы агенту изменить политику составьте матрицу авторизации:

- Публичный профиль: анонимные посетители, участники и администраторы могут читать, служебная задача может читать и записывать.
- Проект клиента: участники и администраторы работают только со своим клиентом, заданная служебная задача может читать и записывать.
- Платежная запись: участники и администраторы читают только свою область, запись доступна лишь задаче событий.
- Событие аудита: участники и администраторы читают только свою область, служебная задача только добавляет записи.

Затем проверяйте базу через тот же публичный клиент, которым пользуется браузер. Короткую проверку политик можно запускать в CI. Конкретная команда зависит от API, но в выводе должны ясно читаться субъект, действие и результат:

```sh
node scripts/check-access.mjs
```

```text
PASS anonymous cannot read tenant_projects
PASS member_a reads tenant_a project
PASS member_a cannot read tenant_b project
PASS tenant_admin cannot update billing_events
PASS webhook_job can append one billing_event
5 passed, 0 failed
```

Никогда не передавайте служебный ключ через переменную с префиксом `VITE_`. Инструменты сборки специально помещают такие переменные в браузерный код. Во вводном руководстве Bolt по базам приведены примеры переменных среды, но имя переменной не отменяет поведение сборщика. Публичный анонимный ключ иногда допустим в браузере, если RLS защищает каждый путь. Административный ключ должен находиться только в хранилище секретов серверной функции.

Проверьте также объектное хранилище, экспорт и серверные функции. Команды защищают таблицы, но забывают, что предсказуемый путь к файлу, неограниченная функция экспорта или доступная извне административная функция обходят нужную границу. Авторизация остается одной системой, даже если платформа показывает ее в нескольких экранах.

## Изменениям базы нужна история вне чата

Вторая линия разлома - управление схемой. Запрос «добавь приглашения в команду» может затронуть таблицы, политики, функции, индексы, начальные данные и сгенерированные типы. Если изменение записано только в текущем состоянии базы и разговоре, вы не сможете надежно воспроизвести тестовую среду, проверить SQL или вернуть предыдущую версию приложения.

Как только приложение хранит важные данные, применяйте последовательные миграции только вперед и храните их в системе контроля версий. Модель зрелости деплоя Supabase сформулирована прямо: после запуска приложения меняйте базу через миграции, а не панель, и разделяйте локальную, тестовую и продуктивную среды. Совет работает одинаково, написал первый SQL инженер или Bolt.

Миграция должна описывать структурное изменение и предотвращаемый сбой. Добавляя новый обязательный столбец, не включайте ограничение до заполнения старых строк:

```sql
alter table projects add column tenant_id uuid;

update projects p
set tenant_id = m.tenant_id
from memberships m
where m.user_id = p.owner_id;

alter table projects alter column tenant_id set not null;
create index projects_tenant_id_idx on projects (tenant_id);
```

Для владельцев без участия в организации все равно нужно принять явное решение. Если после обновления остались строки со значением null, ограничение правильно остановит миграцию. Если заглушить ошибку выдуманным клиентом по умолчанию, принадлежность данных будет испорчена. Работа с миграциями в продакшене в основном состоит в обработке старых неудобных данных, а не в синтаксисе `alter table`.

При каждом изменении продуктивной схемы ответьте на четыре вопроса. Сможет ли старое приложение работать во время миграции? Сможет ли новая версия работать до ее применения? Как вы проверите число строк и ограничения? Что делать для восстановления, если деплой остановится посередине? Откат часто требует новой компенсирующей миграции, а не обратного SQL, способного уничтожить свежие данные.

Резервные копии не заменяют эту дисциплину. Копия восстановит состояние после повреждения, но не объяснит, какой код ожидает какую схему. Восстановление всей базы ради одного плохого столбца может удалить корректные записи клиентов, сделанные после резервного копирования.

## Аутентификация ломается в почте и старых сессиях

Аутентификация обычно подводит за пределами почтового ящика разработчика. Регистрация, подтверждение, сброс пароля, приглашение, вход через провайдера, выход и обновление сессии - разные сценарии. Одна успешная авторизация почти ничего из этого не проверяет.

Стандартная доставка писем годится для ранней разработки, но не для запуска без проверки. Production Checklist от Supabase рекомендует собственный SMTP, чтобы вы контролировали доставку и личность отправителя. Документ также предупреждает: корпоративный почтовый сканер может открыть одноразовую ссылку раньше человека, а отслеживание переходов способно переписать адрес подтверждения. Последствие конкретно: пользователь сразу нажимает на ссылку, но видит сообщение об истечении срока.

Проверяйте несколько почтовых провайдеров и добавьте корпоративный ящик, если продукт продается компаниям. Проверьте домен отправителя, список разрешенных перенаправлений, срок действия и страницу после успеха или ошибки. Запросите два письма для сброса и откройте более старое. Откройте ссылку подтверждения на другом устройстве. Исключите пользователя из организации при открытом приложении и убедитесь, что следующий привилегированный запрос отклоняется сервером.

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

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

## Настоящий трафик обнаруживает гонки и лимиты среды

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

У serverless и edge-сред есть жесткие лимиты. Netlify публикует ограничения размера пакета, памяти, процессорного времени и времени ответа для edge functions. У Bolt Hosting своя эксплуатационная модель. Не переносите цифры одного провайдера в разбор архитектуры другого. Запишите текущие лимиты реального деплоя в короткую инструкцию, затем укладывайте каждую задачу в эти рамки или переносите ее в обработчик с очередью.

Обработчик платежа или webhook должен быть идемпотентным. Провайдеры повторяют запрос после тайм-аута, а пользователи дважды нажимают кнопку. Сохраняйте идентификатор события провайдера под ограничением уникальности, а при дубликате подтверждайте прежний результат и возвращайте успех. Нельзя сначала выполнять необратимое действие, а потом записывать событие.

Пагинация тоже быстро показывает проблему. Сгенерированный экран, который загружает все строки, мгновенно работает с двенадцатью записями и дорого обходится с двенадцатью тысячами. Задайте запросу однозначную сортировку и лимит. Для меняющейся ленты лучше курсорная пагинация: смещение может пропускать или дублировать строки, если между запросами появляются записи.

Для serverless-функций с Supabase выбирайте режим соединения для краткоживущих клиентов. Руководство Supabase по подключениям направляет serverless и edge-трафик в пул транзакций, а прямые соединения оставляет миграциям и долгоживущим серверам. Если каждое выполнение открывает прямое соединение с базой, лимит можно исчерпать даже при скромной загрузке процессора и небольшом числе запросов.

Нагрузочный тест должен проверять поведение, а не красивое число запросов. Смоделируйте всплеск входов, панель с несколькими запросами, повтор webhook и двух авторов одной записи. Собирайте p50, p95, долю ошибок, число соединений с базой и медленные запросы. Тест одной загрузки главной страницы лишь подтверждает, что CDN раздает статические файлы, а это и так ожидаемо.

## Публичный доступ превращает удобство в счет

Контроль стоимости и злоупотреблений становится частью продакшена, как только анонимный человек получает возможность запустить платную операцию. Удобный интерфейс не ограничивает вызывающую сторону этим интерфейсом. Любой может автоматизировать регистрации, сбросы пароля, загрузку файлов, запросы к ИИ, поиск или webhook и израсходовать квоты намного быстрее обычного пользователя.

Ставьте лимит на самой узкой границе, где его можно обеспечить. Отключенная кнопка не ограничивает запросы. Проверяйте размер запроса до разбора файла, квоту пользователя и клиента до платной операции, а частоту обращений до вызова внешнего сервиса. Для дорогих действий резервируйте квоту атомарно, чтобы два одновременных запроса не прошли одну проверку остатка.

Конечные точки аутентификации тоже нужно защищать от злоупотреблений. Supabase описывает настраиваемые лимиты для регистрации, OTP, подтверждения, обновления токена и MFA, а также CAPTCHA для регистрации, входа и сброса пароля. Не переносите опубликованные значения по умолчанию в архитектуру навсегда: провайдеры меняют лимиты, а тарифы различаются. Запишите параметры своего проекта и проверьте сообщение, которое увидит пользователь после достижения предела.

Для загрузок до запуска нужно принять четыре решения: максимальный размер запроса, допустимое содержимое по байтам вместо имени файла, квота хранилища на клиента и порядок удаления. Храните файлы под непредсказуемыми именами и разрешайте скачивание на уровне хранилища. Если продукт обрабатывает документы, отделите обработку от запроса и относитесь к парсерам как к ненадежным входам. Файл с именем `invoice.pdf` может оказаться не PDF.

Расходы на внешние сервисы требуют аварийного выключателя. Настройте бюджеты и оповещения у провайдера, если они доступны, затем добавьте в приложении суточный предел для необязательных операций. Заранее решите, что ухудшится при достижении предела. Поиск может показать сокращенный результат, функция ИИ - остановиться с понятным объяснением, а рекламная рассылка - подождать. Вход, экспорт данных и удаление аккаунта не должны зависеть от бюджета необязательной функции.

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

Хорошая репетиция злоупотребления отправляет скриптом дубликаты запросов, слишком большие данные, истекшие учетные данные и запросы чуть выше квоты. Убедитесь, что отказ происходит до дорогого побочного эффекта, а повтор не создает новую работу. Затем проверьте, сможет ли поддержка отличить клиента, честно достигшего лимита, от атакующего без чтения личных данных.

## Нельзя управлять ошибкой, которую нельзя восстановить по событиям

Наблюдаемость первой ломается в человеческом смысле: приложение отказало, а никто не может объяснить, какое действие пользователя, деплой, функция или запрос к базе стали причиной. Вывод консоли браузера и скриншот клиента не создают историю инцидента.

Как минимум собирайте ошибки клиента и серверных функций, идентификаторы деплоев и структурированные события приложения. Присваивайте каждому входящему запросу correlation ID и по возможности передавайте его в журналы базы и внешних сервисов. Записывайте идентификатор исполнителя, клиента, действие, результат, длительность и безопасный идентификатор объекта. Не записывайте токены доступа, заголовки авторизации, ссылки сброса, полные платежные данные или все тело запроса.

Последовательно используйте короткий формат события:

```json
{
  "level": "error",
  "event": "project.create.failed",
  "request_id": "req_01J...",
  "actor_id": "usr_...",
  "tenant_id": "ten_...",
  "release": "git_sha",
  "duration_ms": 842,
  "error_code": "db_timeout"
}
```

Такая запись отвечает на вопросы «кто», «где», «что» и «в каком релизе», но не копирует личное содержимое. По ней можно найти все ошибки одного клиента или все сбои после одного деплоя. Сгенерированный текст ошибки не годится как стабильный код. Определите коды, на которые смогут опираться оповещения и инструкции поддержки.

До запуска создайте три оповещения: рост числа неудачных запросов, сквозной сбой важного пользовательского сценария и перегрузка базы или нехватка хранилища. Настройте пороги после наблюдения за обычным трафиком. Сигнал на каждое исключение приучает людей игнорировать канал, а отсутствие сигналов превращает клиентов в систему мониторинга.

Наконец, отрепетируйте одно восстановление и один откат. Проверьте, у кого есть доступ, пока основной разработчик спит, где лежат секреты, кто управляет DNS и как определить запущенный релиз. Если ответ зависит от памяти о нужном разговоре с Bolt, команда еще не контролирует эксплуатацию.

## В системе контроля версий команда принимает ответственность

Подключите проект к GitHub до того, как от него начнут зависеть несколько людей или несколько продуктивных сред. Документация Bolt по GitHub говорит, что интеграция сохраняет полную историю, поддерживает ветки и разрешает деплой на других платформах. Там же отмечено, что Bolt не сливает ветки внутри приложения, поэтому команде все равно нужен привычный процесс pull request и проверки в GitHub.

Не смешивайте Bolt Version History с командным контролем версий. Version History отлично возвращает прежнее сгенерированное состояние. Git дает проверяемые различия, ветки, метки релизов, автоматические тесты, правила владения и постоянный выход из редактора. Оба удобства нужны для разных задач.

Установите небольшой барьер перед слиянием:

1. Ветка содержит одно законченное изменение и связанную миграцию схемы.
2. CI ставит зависимости из lock-файла, собирает проект, запускает тесты и ищет секреты в сохраненных файлах.
3. Второй человек проверяет авторизацию, разрушительные операции с данными и новые зависимости.
4. В тестовую среду попадает тот же коммит, который предназначен для продакшена.
5. Продакшен записывает этот коммит как идентификатор релиза.

Проверяйте сгенерированные изменения по риску, а не по числу строк. Тратьте время на политики, серверные функции, установочные скрипты зависимостей, удаление данных, переходы платежных состояний и обработку ошибок. Большому изменению стилей иногда достаточно быстрой визуальной проверки. Пять строк новой политики могут открыть всех клиентов.

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

## Сохраняйте Bolt, когда границы понятны и скучны

Сохраняйте стек Bolt, если приложение использует поддерживаемые веб-технологии, команда владеет репозиторием, а задачи продакшена укладываются в обычные управляемые сервисы. Сгенерированное происхождение не делает приложение на React временным. Переписывание ради солидного вида создает новые дефекты и откладывает контроль, который уже нужен существующему приложению.

Решение оставить стек должно опираться на конкретные признаки: сборка воспроизводится из lock-файла; тестовая и продуктивная среды используют отдельные учетные данные и базы; тесты авторизации проверяют границы клиентов; миграции хранятся по версиям; ошибки несут идентификаторы релиза и запроса; резервирование и восстановление отвечают требованиям бизнеса; развернуть или откатить приложение умеет еще один человек помимо автора.

Продолжайте использовать Bolt для интерфейса и ограниченных функций, если изменения можно проверить. Выносите чувствительные процессы в серверные функции с ясными именами. Окружайте эти стыки тестами. GitHub-репозиторий также позволяет сохранить Bolt как редактор и сменить хостинг или базу.

Я не согласен с популярным советом «перепишите после появления первых успехов». В этот момент у команды меньше всего свободного внимания и больше всего клиентских данных под риском. Переписывайте только тогда, когда текущая архитектура блокирует четкое требование, а постепенное извлечение обойдется дороже замены. Боязнь неопрятного сгенерированного кода таким требованием не считается.

## Переносите узкое место, а не название платформы

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

Не переносите все сразу. Если фоновая обработка видео превышает лимит функции, перенесите этот обработчик и оставьте интерфейс. Если политики базы стали слишком сложны для тестирования, переделайте границу данных, не трогая хостинг. Если мешает управление деплоем, развертывайте тот же репозиторий через CI с подтверждениями. Каждое извлечение должно уменьшать один названный риск.

Для каждого переноса заполните такую запись решения:

```text
Constraint: Monthly export exceeds the current function duration limit.
Evidence: 3 of 5 staging runs timed out with production-sized data.
Repair tried: Pagination and streaming reduced memory but not total duration.
Smallest move: Queue export jobs on a worker and store the result.
Success test: 5 production-sized runs complete and retries create one file.
Rollback: Route new jobs to the original function while queued jobs drain.
```

Такой формат не дает расплывчатому спору о платформе превратиться в переписывание. Он также показывает случаи, когда команда не попробовала меньший ремонт или не знает, как измерить успех.

У переноса есть цена подготовки. Сначала экспортируйте исходный код, схему, миграции, файлы, перечень секретов, DNS-записи и запрос для сверки данных. Если вы управляете доменом, заранее уменьшите TTL перед переключением. Где можно предотвратить двойные побочные эффекты, запустите старый и новый путь параллельно. После переключения сравните число записей и бизнес-итоги, а не только HTTP-статусы.

Если нужен взгляд со стороны, Team & AI Audit на oleg.is длится пять рабочих дней и стоит $5,000. Услуга гарантирует не менее $50,000 найденной годовой экономии, иначе оплата не взимается. В этой ситуации нужен ранжированный инженерный план: какие сгенерированные части безопасно оставить, какого контроля не хватает и какой компонент оправдывает стоимость переноса.

Готовое к продакшену приложение Bolt.new не обязано перестать быть сгенерированным. Его команда должна уметь объяснить каждую границу доверия, воспроизвести каждую среду, увидеть каждый значимый сбой и заменить один компонент без ставки на весь продукт. Сохраните скорость, но примите ответственность до того, как первый серьезный клиент преподаст этот урок во время аварии.
