Início Tecnologia Pare de pensar em “inscrição no usuário”. Comece a pensar “novo inquilino”

Pare de pensar em “inscrição no usuário”. Comece a pensar “novo inquilino”

31
0

 

Em qualquer produto SaaS de vários inquilinos, no momento em que um novo usuário se inscreve é ​​mais do que apenas adicionar uma linha em uma tabela de “usuários”. Esse usuário representa uma nova equipe, um novo limite de dados e uma nova estrutura de permissão.

Tomamos uma decisão consciente mais cedo: Trate a criação da conta como a raiz da arquitetura.

Em vez de aparecer nas organizações após a criação de usuários ou armazenar dados de organizações como apenas mais um campo no usuário, criamos o conta o objeto principal. Os usuários pertencem a contas. Os dados pertencem a contas. As permissões derivam de contas.

Esse enquadramento influenciou todas as partes do nosso back -end, desde o design do esquema até a lógica de cobrança e o RBAC.

Aqui está como construímos.

Repensando o registro: conta antes do usuário

A maioria da lógica de integração de saas se parece com a seguinte:

POST /signup → Create user → Later: create org / assign team

Mas em SaaS de vários inquilinos, essa ordem leva a problemas sutis … dados sem casa, permissões no limbo e suposições frágeis em todo o seu aplicativo.

Então começamos com:

POST /signup → Create account → Create user inside account → Done

Essa mudança pode parecer pequena, mas moldou tudo sobre a nossa arquitetura daqui para frente.

O código se parece com o seguinte:

export async function registerAccount(payload: RegistrationDTO) {
  return withTransaction(async (session) => {
    const account = await AccountModel.create([{
      name: payload.company,
      active: true
    }], { session });

    const user = await UserModel.create([{
      accountId: account[0]._id,
      email: payload.email,
      role: 'admin'
    }], { session });

    return { account: account[0], user: user[0] };
  });
}

Ao vincular o usuário diretamente à conta do primeiro dia e envolvê -la em uma transação, evitamos uma longa lista de casos de borda que, de outra forma, surgem rapidamente.

Por que isso importa: os dados pertencem aos inquilinos

Aqui está o que aprendemos da maneira mais difícil: Os dados não são globais, são escopos de inquilino.

Toda consulta, verificação de permissão, portão de recurso e controle da interface do usuário em seu aplicativo se comportarão de maneira diferente, dependendo de quem é o usuário e a que conta eles pertencem.

Então, fizemos uma regra:

Tudo importante carrega um accountId.

Isso inclui:

  • Usuários
  • BattleCards
  • Permissões
  • Assinaturas
  • Logs de auditoria
  • ALTERAÇÕES DE RECURSOS

Mantenha as transações apertadas

Ao construir o fluxo de registro de conta, um dos nossos principais princípios foi separando a validação da persistência e sendo intencional sobre onde Usamos transações de banco de dados.

Aqui está o que se parece na prática:

await ensureEmailFree(payload.email);
await ensureCompanyFree(payload.company);

return withTransaction(async (session) => {
  // Only the critical writes happen here
  const account = await Account.create([{ name: payload.company }], { session });
  const user = await User.create([{ email: payload.email, accountId: account[0]._id }], { session });

  return { account: account[0], user: user[0] };
});

Por que? Portanto, a transação permanece pequena e rápida, mais fácil de escalar, menos problemas de bloqueio e mais fácil de recuperar de falhas.

Administradores de bootstrap, automaticamente

O primeiro usuário dentro de qualquer conta se torna seu administrador. Sem lógica especial, sem definição manual de bandeira. Está construído diretamente no fluxo.

Esse primeiro usuário pode:

  • Convide sua equipe
  • Defina funções e permissões
  • Configure o faturamento
  • Transfira os direitos de administrador se eles partirem

Isso nos deu um caminho de integração limpo e prático que escalava bem, mesmo nos primeiros dias.

Papéis escondidos por conta que crescem com você

Não queríamos construir sobrecarregar um sistema de função, mas precisávamos de estrutura suficiente para cobrir 90% dos casos de uso de SaaS do mundo real.

const ROLE_HIERARCHY = {
  admin: ['admin', 'manager', 'user'],
  manager: ['manager', 'user'],
  user: ['user']
};

function hasPermission(userRole, requiredRole) {
  return ROLE_HIERARCHY[userRole]?.includes(requiredRole) || false;
}

Nós escovamos papéis nas contas e usamos herança simples. Não é sofisticado, mas funciona e é fácil de refatorar mais tarde em um modelo de política mais granular, se necessário.

Assinaturas do primeiro dia

Demos a cada conta um objeto de assinatura na criação, mesmo durante o julgamento. Isso significava sinalizadores de recursos, limites de uso e avisos de atualização foram ligados diretamente à conta desde o início.

const defaultSubscription = {
  tier: 'trial',
  status: 'active',
  limits: {
    maxUsers: 5,
    maxBattlecards: 10,
    aiBattlecardGeneration: true
  }
};

Usamos isso no middleware para os recursos do GATE:

if (!account.subscription.limits.aiBattlecardGeneration) {
  return res.status(402).json({ error: 'Upgrade required' });
}

Namespaces, singularidade e isolamento

Algumas coisas são globalmente únicas. Alguns são localizados de inquilino. Nós desenhamos a linha assim:

Campo Escopo Por que
email Global Um usuário = um email
account.name Global Usado em URLs e cobrança
Outros dados Inquilino Escopo por accountId

O que acertamos (e o que você pode roubar)

Esta pequena mudança, Fazendo a criação da conta o centro de integração, Volte imediatamente e continua a economizar tempo hoje.

Vitórias de curto prazo:

  • Isolamento de dados limpos
  • Acesso baseado em função desde o primeiro dia
  • Recurso da lógica do sinalizador que realmente funciona
  • Fluxo de ensaios totalmente funcional

Retornos de longo prazo:

  • As consultas são fáceis de cuidar e otimizar
  • Cobrança e permissões são dissociadas
  • Não é necessário migração estranha quando você “adiciona equipes mais tarde”
  • Padrões mais seguros em todos os lugares

Pensamentos finais: comece com o modelo mental certo

A página de registro pode parecer simples, mas inicia a estrutura mais importante em seu SaaS: o inquilino.

Então construa como isso importa.

Comece com a conta. Anexe todo o resto a ele. Aplicar os limites mais cedo. Tudo o mais, papéis, permissões, cobrança, se encaixa mais naturalmente.

Em vez de pensar em “primeiro usuário” e, em vez disso, pensar que “contas primeiro” nos deu uma arquitetura em que poderíamos confiar … e construir.

fonte