Pular para o conteúdo
Supastack
PT
Tema
EntrarObter Supastack
Todos os artigos

Mover um SaaS existente para o Supastack

Um manual faseado para migrar um SaaS funcional — auth, tenancy, faturação, jobs — para a fundação supastack sem reescrita nem fim de semana de downtime.

Noah Zixin Zhang4 min de leitura

Como migro um SaaS existente para o supastack?

Depende do teu codebase, mas a sequência não muda: migra por fases, nunca numa só reescrita. Faz o inventário do repositório em código de produto (rotas, schema, lógica de domínio — fica teu) e infraestrutura (auth, tenancy, faturação, jobs, email — o kit substitui-a). Adota os módulos por ordem de dependência: estrutura, auth, workspaces, faturação e depois trabalho em segundo plano. Move os dados com um script que possas correr duas vezes, mantém os IDs de cliente Stripe e faz a transição depois de a aceitação passar. A maioria das apps web demora dias de serões, não semanas.

Faz o inventário antes de tocar no código

Todas as migrações que correm mal começaram da mesma maneira: alguém abriu o repositório do kit e começou a apagar ficheiros. O kit é uma fundação, não um tema — substitui a tua infraestrutura e não tem opinião sobre o teu produto. Antes de moveres o que quer que seja, divide o teu repositório nas duas pilhas com honestidade.

Código de produto é tudo o que um cliente conseguiria descrever-te de volta: as tuas rotas, o teu schema, a tua lógica de domínio, os teus textos, a tua página de preços. Infraestrutura é tudo o que eles nunca veem: sessões, verificações de tenancy, webhooks de pagamento, jobs em fila, email transacional. A primeira pilha migra intacta. A segunda é substituída — que é exatamente a ideia.

  • Lista cada grupo de rotas e etiqueta-o como produto ou canalização — sê implacável; uma página de definições que só alterna um URL de webhook é canalização.
  • Lista as tuas variáveis de ambiente e marca quais configuram infraestrutura (segredos de auth, chaves de fornecedores) versus comportamento do produto.
  • Lista as tuas tabelas e marca quais ficam a cargo do kit (utilizadores, sessões, workspaces, estado de faturação) versus quais são tuas.
  • Escreve a única jornada de utilizador que te paga — esse fluxo é o teste de aceitação de cada fase abaixo.

Mapeia cada junção a um módulo do kit

A infraestrutura do kit é um conjunto de módulos com contratos entre eles — o teu trabalho é apontar cada peça da tua canalização antiga ao módulo que agora a detém. A maior parte do mapeamento é um-para-um; os sítios onde não é são onde tomas decisões a sério.

Duas escolhas de mapeamento merecem reflexão real em vez de portagem mecânica. Se vens do Prisma, o kit padroniza no Drizzle — podes manter o Prisma nas tabelas do produto durante a transição, mas planeia convergir; dois ORMs num só codebase são um imposto de manutenção que se acumula. A comparação Prisma vs Drizzle expõe o que muda.

E se vens de um fornecedor de auth gerida, resiste à vontade de replicar cada funcionalidade do fornecedor antes da mudança. A auth gerida embrulha discretamente coisas que o teu produto pode não usar — listas de sessões, UIs de organizações, sincronização de webhooks. Mapeia o que o teu produto realmente chama; a comparação de auth cobre as diferenças de capacidades que importam.

A tua canalização atualMódulo supastackO que atravessa
Sessões NextAuth.js / Auth.jsAutenticação (Better Auth)Utilizadores e contas migram; as sessões são reemitidas na transição
Clerk ou um fornecedor de auth geridaAutenticação (Better Auth)Os utilizadores migram por email; as sessões de terceiros são abandonadas, não reproduzidas
Tabelas próprias de organização/equipaEspaços de trabalhoAs tuas linhas de organização tornam-se linhas de workspace + pertença
Webhooks da Stripe feitos à mãoFaturaçãoOs IDs de cliente Stripe sobrevivem; o estado da subscrição é rederivado
Jobs CRON + setTimeoutTarefas (Trigger.dev)O trabalho agendado passa para trás do contrato partilhado JobRunner
Nodemailer / email ad hocE-mailOs templates migram; o envio passa por um único adaptador de fornecedor

Adota os módulos por ordem de dependência

A ordem de migração não é uma preferência — é um grafo de dependências. Cada fase abaixo é lançável separadamente e cada uma produz um sistema funcional que podes verificar antes de a próxima começar. A tentação é fazer tudo num fim de semana e depurar a interseção; resiste-lhe — uma migração faseada significa que cada bug que encontras pertence a exatamente um módulo, um superpoder de depuração que só vais apreciar quando o saltares.

  • Fase 1 — esqueleto: faz o scaffold do kit, configura o env, larga as tuas rotas de produto na estrutura do projeto. Ainda nada está ligado; a app arranca e as tuas páginas renderizam.
  • Fase 2 — auth: passa o início de sessão para o Better Auth, migra as tabelas de utilizadores/contas, verifica o sign-in + sign-out de ponta a ponta. Todas as fases seguintes dependem de existir uma sessão.
  • Fase 3 — tenancy: adota o modelo de workspaces, preenche retroativamente o workspaceId nas tuas tabelas de produto, impõe o âmbito nas leituras e escritas. É aqui que o post sobre fronteiras do workspace se paga a si próprio.
  • Fase 4 — faturação: aponta o checkout e os webhooks ao módulo de faturação, remapeia as subscrições existentes, verifica os controlos de direitos contra dados reais da Stripe em modo de teste.
  • Fase 5 — trabalho em segundo plano e email: porta os jobs para o contrato JobRunner e passa o email transacional para o adaptador de email. Ficam para o fim porque dependem de utilizadores e workspaces já existentes.

Move os dados com honestidade

A migração de dados é onde as migrações ganham a sua reputação. As regras que a mantêm aborrecida: escreve um script que possas correr duas vezes, nunca mutes a origem até à transição e verifica contagens em vez de confiar no script.

Utilizadores e contas aterram no schema do Better Auth — o email é a chave de junção, e as contas com palavra-passe exigem uma decisão: ou o teu formato de hash atual é um que o Better Auth consegue verificar, ou lanças um fluxo de reposição de palavra-passe na transição e tratas isso como uma função de força. As contas OAuth de terceiros são o caso fácil — o fornecedor reemite-as no próximo início de sessão.

Na faturação, o caminho honesto é a rederivação em vez de copiar linhas: mantém o ID de cliente Stripe, deixa o tratamento de webhooks do kit reconstruir o estado de direitos a partir da verdade do fornecedor e faz diff do que ele calcula contra os teus registos de subscrição existentes. O ledger idempotente de webhooks do kit existe precisamente para que eventos históricos reproduzidos não provisionem nada duas vezes.

// 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}`);
}

O que fica teu

Vale a pena dizê-lo claramente, porque é a parte em que as pessoas erram nas duas direções: as tuas rotas de produto, o teu schema, a tua lógica de domínio e o teu design não mudam. Não estás a reconstruir a tua app dentro do kit — estás a pousá-la em cima dele.

O erro inverso é manter a canalização antiga viva «temporariamente» ao lado do módulo novo. Uma segunda verificação de sessão, um segundo handler de webhooks, uma segunda tabela de direitos — cada sistema paralelo «temporário» é permanente até alguém o apagar, e cada um é um incidente futuro. Substitui, verifica, apaga. Se uma fase ainda não consegue apagar o caminho antigo, não está terminada.

A checklist da transição

A transição é uma checklist, não um evento. Corre-a num ambiente de staging pelo menos uma vez com dados com formato de produção antes da data real.

  • Corre novamente o script de dados contra um snapshot fresco de produção; as contagens e as verificações aleatórias passam.
  • Inicia sessão com cada fornecedor de auth que o teu produto suporta — incluindo aqueles cuja existência esqueceste.
  • Compra o teu próprio produto no modo de teste da Stripe e segue o webhook até ao direito.
  • Envia cada email transacional uma vez; confirma que os links aterram no novo deploy.
  • Verifica a jornada pagante de ponta a ponta, depois muda o DNS/env e observa a primeira sessão real.
  • Mantém o deploy antigo a correr durante uma semana — o rollback é uma mudança de DNS, não uma migração.

Perguntas frequentes sobre migrar para um starter kit

O mesmo punhado de perguntas surge sempre que alguém se senta para fazer isto.

  • Quanto tempo demora realmente uma migração? — Para uma única app web com auth padrão + Stripe: dias de serões, não semanas. B2B multi-tenant com faturação personalizada acrescenta tempo nas fases três e quatro — é o trabalho de dados que se estica, nunca a mudança de ficheiros.
  • Devo migrar ou começar de raiz e portar funcionalidades? — Se o teu código de produto é menor que a tua dívida de infraestrutura, começar de raiz no kit e portar as rotas de produto é muitas vezes mais rápido. Se o teu schema e lógica de domínio são a parte difícil, migra no sítio.
  • Posso manter o meu ORM / a minha biblioteca de auth durante a transição? — Por pouco tempo, sim — uma fronteira de módulo de cada vez. Para sempre, não: dois de qualquer coisa na camada de infraestrutura é um imposto que se acumula.
  • E os meus webhooks da Stripe já em trânsito? — Aponta o endpoint de webhooks existente ao handler do kit assim que a fase quatro estiver verificada; o ledger idempotente torna eventos reproduzidos ou duplicados seguros em vez de perigosos.
  • Tenho de adotar todos os módulos? — Não. Mobile, desktop, jobs e IA são superfícies para adotar ou ignorar — a licença é a fundação, não um mandato para lançar uma app por plataforma.