
TL;DR: Мы сделали автоматическое подключение Supabase через OAuth, чтобы каждый разработчик мог получить готовую базу данных под свой SaaS без ручного деплоя. Миграции выполняем через Supabase CLI, а работу с данными — через PostgREST.
Зачем всё это
Я развиваю сервис AgentCraft — платформу, которая превращает n8n‑автоматизации в готовый SaaS «из коробки».
AgentCraft подключает Stripe, Supabase, дашборды и систему пользователей — буквально за несколько минут.
Цель — минимизировать количество шагов, которые нужно сделать разработчику, чтобы развернуть свою инфраструктуру.

Когда мы дошли до вопроса автоматического развертывания БД, стало очевидно: нужен инструмент, который:
уже знаком no-code-разработчикам,
предоставляет API, CLI и OAuth,
и не требует ручной настройки PostgreSQL.
Выбор пал на Supabase — популярную open-source платформу поверх PostgreSQL.
Архитектура решения
Наша схема работы выглядит следующим образом:
AgentCraft работает на классической PostgreSQL базе данных на бэкенде
Разработчики регистрируются на AgentCraft и подключают свои вебхуки
Разработчики подключают свою учетную запись Supabase через OAuth
-
AgentCraft автоматически создает основные таблицы в их Supabase проекте:
Биллинг —
billing_plans,subscriptions,invoicesКонечные пользователи —
users,user_sessionsСтатистика —
webhook_executions,usage_trackingи другие служебные таблицы
Таким образом, разработчик просто нажимает “Connect Supabase” — и получает полноценную инфраструктуру SaaS с базой данных, billing’ом и аналитикой. Как все это выглядит можно посмотреть тут - https://www.loom.com/share/e55bb4d7698547d9a31c676f2a109bb0
Как работает Supabase: инструменты взаимодействия
Supabase предоставляет несколько способов взаимодействия с базой данных:
1. Supabase CLI
CLI — основной инструмент для миграций и управления схемой базы данных.
# Логин через OAuth токен
supabase login --token $ACCESS_TOKEN
# Привязка к проекту
supabase link --project-ref $PROJECT_REF
# Создание новой миграции
supabase migration new saas_migration
# Применение миграций
supabase db push --yes
CLI идеально подходит для автоматического деплоя схемы в разных проектах Supabase — ровно то, что нам нужно.
2. PostgREST API
PostgREST — это REST API, которое Supabase автоматически генерирует для всех таблиц PostgreSQL.
GET /rest/v1/users?select=id,email&status=eq.active
POST /rest/v1/users
PATCH /rest/v1/users?id=eq.{id}
DELETE /rest/v1/users?id=eq.{id}
Этот API работает “из коробки” и позволяет AgentCraft взаимодействовать с чужими базами, не имея прямого доступа к PostgreSQL.
3. Management API
Management API используется для получения списка проектов, ключей и метаданных.
Через него мы получаем anon_key, service_key и project_ref для последующей работы.

Сравнительная таблица инструментов Supabase
Инструмент |
Назначение |
Ограничения |
|---|---|---|
Supabase CLI |
Миграции, управление схемой, деплой |
Требует локальной установки, работает через OAuth |
PostgREST API |
CRUD операции с данными, выборка, фильтрация |
Не поддерживает DDL (CREATE TABLE, ALTER TABLE и т.д.) |
Management API |
Управление проектами, получение ключей |
Не управляет схемой БД |
Прямое подключение PostgreSQL |
Полный контроль над БД |
Требует service_key, не всегда доступен |
Создание миграций через CLI
В AgentCraft мы используем Supabase CLI для создания и применения миграций.
Вот как это реализовано на Go:
func (h *SaaSHandler) deployDatabaseWithOAuth(
ctx context.Context,
integration *models.ExternalIntegration,
project *models.SupabaseOAuthProject,
organization *models.SupabaseOAuthOrganization,
productID uuid.UUID,
) (map[string]interface{}, error) {
accessToken := *organization.AccessTokenEnc
// Применяем миграции через CLI
err := h.applyDatabaseTemplatesViaCLI(ctx, accessToken, project.Ref, productID)
if err != nil {
return nil, fmt.Errorf("failed to apply database templates: %w", err)
}
return deploymentConfig, nil
}
А вот сам процесс применения миграций:
func (h *SaaSHandler) applyDatabaseTemplatesViaCLI(
ctx context.Context,
accessToken, projectRef string,
productID uuid.UUID,
) error {
tempDir, _ := os.MkdirTemp("/app", "supabase-cli-*")
defer os.RemoveAll(tempDir)
// Логинимся в Supabase
exec.CommandContext(ctx, "supabase", "login", "--token", accessToken).Run()
exec.CommandContext(ctx, "supabase", "link", "--project-ref", projectRef).Run()
// Создаем миграцию
exec.CommandContext(ctx, "supabase", "migration", "new", "saas_migration").Run()
// Записываем SQL
os.WriteFile(tempDir+"/migration.sql", []byte(migrationSQL), 0644)
// Применяем миграции
exec.CommandContext(ctx, "supabase", "db", "push", "--yes").Run()
return nil
}


Почему не удалось использовать PostgREST для миграций
PostgREST не поддерживает DDL операции — то есть нельзя делать CREATE TABLE, ALTER TABLE, CREATE FUNCTION и т.п.
Причины:
Безопасность — нельзя давать возможность создавать таблицы через HTTP
Назначение — PostgREST предназначен для CRUD, а не для схемы
Именно поэтому мы выбрали Supabase CLI — он безопасен, легитимен и поддерживает OAuth-доступ.

OAuth подключение Supabase
Наша цель - сделать максимально простое подключение БД, как у Lovable.
После того, как разработчик жмет кнопку “Connect Supabase”, происходит классический OAuth flow:
func (h *IntegrationsHandler) HandleSupabaseOAuthCallback(w http.ResponseWriter, r *http.Request) {
tokens, _ := h.exchangeSupabaseOAuthCode(request.Code)
organizations, _ := h.fetchSupabaseOrganizations(tokens.AccessToken)
h.storeSupabaseOAuthData(r.Context(), userID, tokens, organizations)
}
Далее мы создаем интеграции для всех доступных проектов пользователя:
for _, org := range organizations {
for _, project := range org.Projects {
details, _ := h.fetchProjectDetailsFromSupabase(accessToken, project.Ref)
h.createIntegration(userID, project.Ref, details.ServiceKey, details.AnonKey)
}
}

Взаимодействие через PostgREST
После миграции мы используем PostgREST API для CRUD операций с таблицами клиента:
func (c *SupabaseCommon) ExecuteSupabasePostgRESTRequest(
ctx context.Context,
projectRef, serviceKey, method, endpoint string,
payload interface{},
) ([]byte, error) {
url := fmt.Sprintf("https://%s.supabase.co/rest/v1/%s", projectRef, endpoint)
req, _ := http.NewRequestWithContext(ctx, method, url, reqBody)
req.Header.Set("Authorization", "Bearer "+serviceKey)
req.Header.Set("apikey", serviceKey)
return c.httpClient.Do(req)
}
Практические советы
1. Обработка таймаутов
Supabase может “засыпать” после неактивности — добавьте retry-механику:
for attempt := 1; attempt <= 3; attempt++ {
err := h.applyDatabaseTemplatesViaCLI(...)
if strings.Contains(err.Error(), "connection") {
time.Sleep(time.Duration(attempt) * 5 * time.Second)
continue
}
break
}
2. Обновление OAuth токенов
Токены истекают, поэтому мы проверяем их перед каждым деплоем и обновляем при необходимости.
3. Валидация после миграции
Проверяем, что все таблицы созданы корректно:
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'users'
);
Вывод
Интеграция Supabase через OAuth и CLI позволила нам:
автоматизировать развёртывание инфраструктуры SaaS для пользователей,
избавить разработчиков от ручного конфигурирования PostgreSQL,
использовать PostgREST как стандартный REST API поверх готовой схемы.