> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# Перенос существующего SaaS в supastack

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

_Опубликовано 2026-10-29._
_Обновлено 2026-10-29._

> **Как перенести существующий SaaS в supastack?**
> Зависит от кодовой базы, но последовательность неизменна: переносите поэтапно, никогда — одним переписыванием. Проведите инвентаризацию репозитория, разделив его на продуктовый код (роуты, схема, доменная логика — он остаётся вашим) и инфраструктуру (аутентификация, тенантность, биллинг, задачи, почта — её заменяет кит). Подключайте модули в порядке зависимостей: структура, аутентификация, воркспейсы, биллинг, затем фоновая работа. Переносите данные перезапускаемым скриптом, сохраняйте ID клиентов Stripe и переключайтесь после прохождения приёмки. Большинство веб-приложений занимает дни вечерами, а не недели.

## Проведите инвентаризацию, прежде чем трогать код

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

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

- Выпишите каждую группу роутов и пометьте её как продукт или обвязку — будьте беспощадны: страница настроек, которая лишь переключает URL вебхука, — это обвязка.
- Выпишите переменные окружения и отметьте, какие настраивают инфраструктуру (секреты аутентификации, ключи провайдеров), а какие — поведение продукта.
- Выпишите таблицы и отметьте, какие перейдут под управление кита (пользователи, сессии, воркспейсы, состояние биллинга), а какие остаются вашими.
- Запишите тот самый пользовательский сценарий, который приносит вам деньги, — этот поток будет приёмочным тестом для каждого этапа ниже.


## Сопоставьте каждый стык с модулем кита

Инфраструктура кита — набор модулей с контрактами между ними; ваша задача — направить каждый кусок старой обвязки к модулю, который теперь за него отвечает. Большая часть сопоставления один к одному; там, где это не так, вы и принимаете настоящие решения.

Два выбора при сопоставлении заслуживают обдумывания, а не механического переноса. Если вы пришли с `Prisma` — кит стандартизирован на Drizzle: на время перехода Prisma можно оставить для продуктовых таблиц, но планируйте сойтись на одном варианте; две ORM в одной кодовой базе — налог на поддержку, который накапливается. [Сравнение Prisma и Drizzle](https://supastack.dev/ru/blog/prisma-vs-drizzle-for-saas.md) раскладывает, что именно меняется.

А если вы пришли от управляемого провайдера аутентификации — сдерживайте желание воспроизвести каждую его функцию до переключения. Managed auth незаметно упаковывает вещи, которыми ваш продукт может и не пользоваться: списки сессий, интерфейсы организаций, синхронизация вебхуков. Сопоставляйте то, что ваш продукт реально вызывает; [сравнение решений аутентификации](https://supastack.dev/ru/blog/better-auth-vs-nextauth-vs-clerk.md) разбирает различия в возможностях, которые действительно важны.

| Ваша текущая обвязка | Модуль supastack | Что переезжает |
|---|---|---|
| Сессии NextAuth.js / Auth.js | Аутентификация (Better Auth) | Пользователи и аккаунты мигрируют; сессии перевыпускаются при переключении |
| Clerk или управляемый провайдер аутентификации | Аутентификация (Better Auth) | Пользователи мигрируют по email; сторонние сессии не переигрываются, а бросаются |
| Свои таблицы организаций/команд | Воркспейсы | Строки организаций становятся строками воркспейсов и членства |
| Самописные вебхуки Stripe | Биллинг | ID клиентов Stripe сохраняются; состояние подписки выводится заново |
| Задачи на CRON + setTimeout | Задачи (Trigger.dev) | Плановая работа переезжает за общий контракт JobRunner |
| Nodemailer / почта на коленке | Почта | Шаблоны переезжают; отправка идёт через один адаптер провайдера |


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

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

- Этап 1 — каркас: разверните кит, настройте env, положите продуктовые роуты в структуру проекта. Пока ничего не подключено: приложение запускается, и ваши страницы рендерятся.
- Этап 2 — аутентификация: переведите вход на Better Auth, мигрируйте таблицы пользователей и аккаунтов, проверьте вход и выход от начала до конца. Каждый следующий этап зависит от существования сессии.
- Этап 3 — тенантность: внедрите модель воркспейсов, заполните `workspaceId` в продуктовых таблицах задним числом, применяйте контекст в чтениях и записях. Именно здесь окупается статья о [границах воркспейса](https://supastack.dev/ru/blog/workspace-boundaries.md).
- Этап 4 — биллинг: направьте оформление заказа и вебхуки в биллинговый модуль, пересопоставьте существующие подписки, проверьте проверки прав доступа на реальных данных Stripe в тестовом режиме.
- Этап 5 — фоновая работа и почта: перенесите задачи на контракт JobRunner, а транзакционную почту — на адаптер email. Они последние, потому что зависят от уже существующих пользователей и воркспейсов.


## Переносите данные честно

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

Пользователи и аккаунты приземляются в схеме Better Auth — email служит ключом соединения, а для аккаунтов с паролем нужно решение: либо ваш текущий формат хеша умеет проверять Better Auth, либо при переключении вы выпускаете сценарий сброса пароля и относитесь к нему как к принудительной мере. Сторонние OAuth-аккаунты — простой случай: провайдер перевыпускает их при следующем входе.

В биллинге честный путь — перевывод, а не копирование строк: сохраните ID клиента Stripe, позвольте обработке вебхуков кита заново построить состояние прав доступа из истины провайдера и сравните то, что она вычисляет, с вашими текущими записями о подписках. [Идемпотентный реестр вебхуков](https://supastack.dev/ru/blog/idempotent-billing-webhooks.md) кита существует именно для того, чтобы переигранные исторические события ничего не провизионировали дважды.

```
// migration scripts are boring by design: upsert-shaped,
// re-runnable, and they verify counts instead of trusting themselves
for (const legacyUser of legacyUsers) {
  await upsertAuthUser({
    email: legacyUser.email.toLowerCase(),
    name: legacyUser.displayName,
    externalId: legacyUser.id, // preserved for one-shot joins
  });
}
const migrated = await countAuthUsers();
if (migrated !== legacyUsers.length) {
  throw new Error(`count mismatch: ${migrated} of ${legacyUsers.length}`);
}
```


## Что остаётся вашим

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

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


## Чек-лист переключения

Переключение — это чек-лист, а не событие. Прогоните его на стейджинге хотя бы один раз с данными продакшн-формы до настоящей даты.

- Перезапустите скрипт данных на свежем продакшн-снимке; количества и выборочные проверки проходят.
- Войдите через каждый провайдер аутентификации, который поддерживает ваш продукт, — включая те, о существовании которых вы забыли.
- Купите собственный продукт в тестовом режиме Stripe и проследите вебхук до выдачи прав доступа.
- Отправьте каждое транзакционное письмо по разу; проверьте, что ссылки ведут на новый деплой.
- Проверьте платящий сценарий от начала до конца, затем переключите DNS/env и наблюдайте первую реальную сессию.
- Держите старый деплой запущенным неделю — откат это смена DNS, а не миграция.


## Частые вопросы о переезде в стартовый кит

Одна и та же горстка вопросов всплывает каждый раз, когда кто-то садится за это дело.

- Сколько на самом деле занимает миграция? — Для одного веб-приложения со стандартной аутентификацией + Stripe: дни вечерами, а не недели. Мультитенантный B2B с кастомным биллингом добавляет времени на этапах три и четыре — растягивается именно работа с данными, никогда не перенос файлов.
- Мигрировать или начать с нуля и портировать функции? — Если ваш продуктовый код меньше инфраструктурного долга, старт на ките с нуля и перенос продуктовых роутов часто быстрее. Если схема и доменная логика — сложная часть, мигрируйте на месте.
- Можно ли оставить существующую ORM / библиотеку аутентификации на время перехода? — Ненадолго, да — по одной границе модулей за раз. Навсегда, нет: два экземпляра чего угодно в инфраструктурном слое — накапливающийся налог.
- А как насчёт моих вебхуков Stripe, которые уже в пути? — Направьте существующий эндпоинт вебхуков на обработчик кита, как только этап четыре проверен; идемпотентный реестр делает переигранные или продублированные события безопасными, а не опасными.
- Обязательно ли внедрять все модули? — Нет. Мобильный клиент, десктоп, задачи и AI — это поверхности, которые можно внедрять или игнорировать: лицензия — фундамент, а не обязанность выпускать приложение на каждую платформу.
