Sistema de Assinaturas

Publicado em

08/03/2025

Entendendo o sistema de Assinaturas para o SaaS Boilerplate

O SaaS Boilerplate inclui um sistema de billing completo e desacoplado que permite gerenciar assinaturas, planos, preços e limites de uso de forma flexível e independente do provedor de pagamento.

Visão Geral

O sistema de billing do SaaS Boilerplate foi projetado com os seguintes princípios:

  1. Desacoplamento de provedores: Troque facilmente entre Stripe, PayPal ou qualquer outro provedor
  2. Gerenciamento automático de limites: Rastreamento e aplicação automática de limites por recurso
  3. Multi-tenant por design: Isolamento completo entre organizações
  4. Flexibilidade de preços: Suporte a diferentes ciclos de cobrança e moedas

Configuração Inicial

1. Configuração do Provedor

O sistema usa uma arquitetura de adaptadores que permite trocar facilmente entre diferentes provedores de pagamento:

// Em src/core/providers/payment.ts
import { prismaAdapter } from "@/saas-boilerplate/providers/payment/databases/prisma";
import { stripeAdapter } from "@/saas-boilerplate/providers/payment/providers/stripe.adapter";
import { AppConfig } from "@/configs/app.config";
import { prisma } from './prisma'
import { PaymentProvider } from "@/saas-boilerplate/providers/payment/payment.provider";
import { freePlan } from "../data/plans/free";
import { proPlan } from "../data/plans/pro";

const { keys, paths } = AppConfig.providers.billing

export const payment = PaymentProvider.initialize({
  database: prismaAdapter(prisma),
  adapter: stripeAdapter(keys),
  
  paths: {
    checkoutCancelUrl: paths.checkoutCancelUrl,
    checkoutSuccessUrl: paths.checkoutSuccessUrl,
    portalReturnUrl: paths.portalReturnUrl
  },
  subscriptions: {
    enabled: true,
    defaultPlan: freePlan.slug,
    plans: [freePlan, proPlan]
  },
})

2. Configuração de Variáveis de Ambiente

Para o Stripe, você precisará configurar as seguintes variáveis de ambiente:

# .env
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

Definição de Planos

Os planos são definidos como objetos TypeScript com metadados que incluem recursos, limites e ciclos:

// Em src/core/data/plans/free.ts
import { PaymentProvider } from "@/saas-boilerplate/providers/payment";

export const freePlan = PaymentProvider.plan({
  slug: 'free',
  name: 'Free',
  description: 'Start for free and explore the essential features',
  metadata: {
    features: [
      {
        slug: 'seats',
        name: 'Seats',
        description: 'Add up to 1 member to collaborate with your team',
        table: 'Member',
        enabled: true,
        limit: 1,
      },
      {
        slug: 'leads',
        name: 'Leads',
        description: 'Capture and manage up to 100 leads monthly through the bot',
        table: 'Lead',
        enabled: true,
        limit: 100,
        cycle: 'month',
      },
      // Mais recursos...
    ]
  },
  prices: [
    {
      amount: 0,
      currency: 'brl',
      interval: 'month',
      intervalCount: 1,
      slug: 'free-monthly'
    },
    {
      amount: 0,
      currency: 'brl',
      interval: 'year',
      intervalCount: 1,
      slug: 'free-yearly'
    }
  ]
})

Cada plano tem:

  • Metadados básicos: slug, nome e descrição
  • Lista de recursos: cada recurso pode ter seu próprio limite e ciclo de renovação
  • Opções de preço: diferentes preços para diferentes ciclos de cobrança (mensal, anual, etc.)

Sistema de Cotas e Limites

Como Funciona o Rastreamento de Uso

O sistema rastreia automaticamente o uso de recursos para cada organização com base na tabela do banco de dados:

  1. Definição de Recursos no Plano: Você define um recurso no plano com um slug e um table que corresponde à tabela que deseja rastrear
  2. Rastreamento Automático: O sistema conta automaticamente as entradas na tabela para cada organização
  3. Verificação de Limites: Quando um usuário tenta criar um novo registro, o sistema verifica se está dentro do limite

Ciclos de Renovação

Cada recurso pode ter seu próprio ciclo de renovação:

  • Mensal: Limites são renovados a cada mês
  • Anual: Limites são renovados anualmente
  • Semanal: Limites são renovados semanalmente
  • Diário: Limites são renovados diariamente

Uso na Aplicação

Verificação de Limites

Para verificar se um usuário pode criar um novo recurso:

import { payment } from "@/core/providers/payment";

// Verificar se o usuário pode criar um novo lead
const canCreateLead = await payment.canCreate({
  organizationId: "org_123",
  feature: "leads"
});

if (canCreateLead) {
  // Criar o lead
} else {
  // Mostrar mensagem de limite excedido
}

Criação de Assinaturas

Para criar uma nova assinatura:

import { payment } from "@/core/providers/payment";

// Criar uma assinatura para o plano Pro
const subscription = await payment.createSubscription({
  customerId: "cus_123",
  plan: "pro",
  cycle: "month"
});

Portal de Billing

Para redirecionar o usuário para o portal de billing:

import { payment } from "@/core/providers/payment";

// Criar uma sessão do portal de billing
const portalUrl = await payment.createBillingPortal(
  "cus_123",
  "https://seuapp.com.br/retorno"
);

// Redirecionar o usuário para o portal
window.location.href = portalUrl;

Webhooks e Sincronização

O sistema inclui um gerenciador de webhooks que processa eventos do provedor de pagamento:

// Em src/app/api/webhooks/stripe/route.ts
import { payment } from "@/core/providers/payment";

export async function POST(request: Request) {
  return payment.handle(request);
}

Personalização Avançada

Eventos de Ciclo de Vida

Você pode reagir a eventos do ciclo de vida de assinaturas:

const payment = PaymentProvider.initialize({
  // ...outras configurações
  events: {
    onSubscriptionCreated: async (subscription) => {
      // Lógica personalizada quando uma assinatura é criada
      await enviarEmailDeBoasVindas(subscription.customerId);
    },
    onSubscriptionCanceled: async (subscription) => {
      // Lógica personalizada quando uma assinatura é cancelada
      await enviarPesquisaDeCancelamento(subscription.customerId);
    }
  }
});

Implementação de Novos Adaptadores

Para adicionar suporte a um novo provedor de pagamento, crie um novo adaptador:

// Em src/saas-boilerplate/providers/payment/providers/meu-provedor.adapter.ts
import { IPaymentProviderAdapter } from "../providers/provider-adapter.interface";

export const meuProvedorAdapter = (config: any): IPaymentProviderAdapter => {
  return {
    createCustomer: async (params) => {
      // Implementação específica do provedor
    },
    // Implementar outros métodos da interface
  };
};

Considerações de Segurança

  • Nunca armazene chaves de API no frontend: Use variáveis de ambiente no servidor
  • Verifique assinaturas de webhook: Valide que os webhooks realmente vêm do seu provedor de pagamento
  • Implemente verificações de segurança adicionais: Verifique permissões antes de modificar assinaturas

Próximos Passos

  1. Configure seus planos e preços de acordo com seu modelo de negócio
  2. Personalize o portal de billing para corresponder à sua marca
  3. Implemente lógica de negócio específica para lidar com upgrades e downgrades
  4. Teste o fluxo completo de assinatura em ambiente de desenvolvimento

Com este sistema implementado, você pode se concentrar na construção dos recursos principais do seu produto, enquanto oferece uma experiência de billing profissional e flexível para seus clientes.

SaaS Boilerplate

Acelere seu desenvolvimento

Construa aplicações SaaS completas em minutos com nosso boilerplate moderno. Autenticação, pagamentos, gerenciamento de usuários e muito mais!

Conheça o SaaS Boilerplate

Você também pode gostar