O que saas faz?
SaaS de última geração — multi-tenancy, faturamento baseado em uso, PLG, integração de funcionalidades de IA, observabilidade moderna, conformidade e segurança para produtos de Software como Serviço (SaaS) em produção.
Instruções
Multi-Tenancy
Escolha o modelo de isolamento certo para o seu caso de uso:
| Modelo | Descrição | Quando usar |
|---|---|---|
| Esquema compartilhado | Todos os tenants compartilham tabelas; linhas marcadas com tenant_id | Estágio inicial, sensível a custos, conformidade simples |
| Esquema por tenant | Esquema de BD separado por tenant | Isolamento médio, migrações fáceis por tenant |
| BD por tenant | Banco de dados separado por tenant | Corporativo, residência de dados rigorosa, alta conformidade (SOC 2, HIPAA) |
| Híbrido | Dados principais compartilhados; dados confidenciais isolados | Indústrias regulamentadas com ofertas de níveis mistos |
Regras para tenancy de esquema compartilhado:
- Cada consulta deve filtrar por
tenant_id— aplique via um repositório base ou middleware ORM, não por disciplina do desenvolvedor - Use Segurança em Nível de Linha (RLS) do PostgreSQL como segunda camada de defesa:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.current_tenant')::uuid); - Indexe
tenant_idem cada tabela com escopo de tenant - Escreva testes de integração que verifiquem o isolamento de dados entre tenants
- Escopo de todos os caminhos de armazenamento de objetos:
s3://bucket/{tenantId}/uploads/{fileId} - Nunca exponha IDs sequenciais previsíveis — use UUIDs (v7 para ordenação)
Assinatura e Faturamento
Assinaturas de taxa fixa
- Delegue o faturamento a um provedor (Stripe, Paddle, LemonSqueezy) — nunca implemente o processamento de pagamento internamente
- Armazene apenas
customerIdesubscriptionIdno seu BD; nunca dados de cartão - Sincronize o estado via webhooks — trate seu BD como uma réplica de leitura eventualmente consistente da verdade do provedor de faturamento:
customer.subscription.created → ativar plano customer.subscription.updated → upgrade / downgrade / mudança de assento customer.subscription.deleted → cancelar + iniciar período de carência invoice.payment_failed → dunning: notificar → restringir → cancelar - Use o
iddo evento do webhook como chave de idempotência — armazene-o antes de processar; pule se já visto - Armazene payloads brutos de webhook para auditoria e repetição
Faturamento baseado em uso / medido (padrão moderno)
- Rastreie eventos de uso conforme eles acontecem (chamadas de API, assentos, tokens consumidos, GB de armazenamento):
await stripe.subscriptionItems.createUsageRecord(subscriptionItemId, { quantity: tokensUsed, timestamp: Math.floor(Date.now() / 1000), action: 'increment', }); - Exiba um painel de uso ao vivo para os clientes — surpresas no dia da fatura causam churn
- Implemente limites flexíveis (avisar em 80%) e limites rígidos (bloquear em 100%) por período de faturamento
- Considere um nível gratuito + upsell baseado em uso como uma porta de entrada para o Product-Led Growth (PLG)
Product-Led Growth (PLG)
- Nível gratuito / freemium — deixe os usuários experimentarem o valor antes de pedir pagamento; defina limites que tornem os planos pagos obviamente vantajosos
- Tempo até o valor (TTV) — meça e minimize o tempo desde a inscrição até a primeira ação significativa ("momento aha")
- Prompts de upgrade no aplicativo — exiba CTAs de upgrade contextualmente no momento em que um limite do plano é atingido, não em uma página de configurações genérica
- Leads qualificados por produto (PQL) — pontue os usuários com base em sinais de uso do produto (não apenas solicitações de demonstração) para encaminhar para vendas
- Recursos virais / colaborativos — convide colegas de equipe, compartilhe relatórios, páginas públicas — cada ação é um canal de distribuição
Integração de Funcionalidades de IA
Espera-se que produtos SaaS modernos ofereçam capacidades nativas de IA. Aplique esses padrões:
Assistentes e copilotos de IA:
- Use respostas em streaming (SSE /
ReadableStream) para que os usuários vejam os tokens conforme eles chegam — nunca os faça esperar por uma resposta completa - Sempre torne a saída da IA editável — os usuários precisam corrigir, refinar e possuir a saída
- Mostre sinais de confiança e cite fontes (RAG) para construir confiança
Geração Aumentada por Recuperação (RAG):
- Armazene embeddings de vetor por tenant em um namespace isolado (Pinecone, pgvector, Qdrant) — nunca misture dados de tenant
- Incorpore conteúdo na escrita; consulte na leitura com similaridade de cosseno
- Divida documentos de forma inteligente (512–1024 tokens com sobreposição); re-incorporar quando o conteúdo de origem mudar
Controles de uso e custo:
- Rastreie o consumo de tokens de LLM por tenant — cobre ou limite a taxa de acordo
- Armazene em cache prompts determinísticos (mesma entrada → mesma saída) para reduzir custos
- Use modelos mais baratos para classificação/triagem; reserve modelos de fronteira para tarefas de geração
Privacidade de dados:
- Ofereça um adendo de processamento de dados (DPA) que indique explicitamente se os dados do tenant são usados para treinamento de modelo
- Forneça uma opção de exclusão; clientes corporativos exigirão isso
Feature Flags & Gating de Planos
- Faça o gating de recursos na camada de serviço — ocultação no lado do cliente é polimento de UI, não segurança
- Centralize a lógica de direito em um único helper
can(tenant, feature):function can(tenant: Tenant, feature: Feature): boolean { return tenant.plan.features.includes(feature); } - Desacople a implantação de recursos do lançamento de recursos usando um sistema de flags (LaunchDarkly, Unleash, GrowthBook ou uma tabela simples baseada em BD)
- Use flags para: implantações graduais (% de tenants), programas beta, testes A/B, kill switches
Onboarding
- Minimize o TTV: guie os usuários para sua primeira ação significativa em < 5 minutos
- Use um fluxo de onboarding orientado por checklist com indicadores de progresso claros
- Pré-popule dados de amostra / demonstração para que o produto não pareça vazio no primeiro uso
- Colete o mínimo absoluto de dados antecipadamente; adie todo o resto
- Dispare e-mails de onboarding com base em eventos do produto (não apenas no tempo): boas-vindas na inscrição, lembrete se não concluíram a etapa 2 após 24h, celebre o primeiro marco
- Ofereça um tour interativo do produto (não um vídeo) para que os usuários aprendam fazendo
Observabilidade e Operações
Registro estruturado — cada linha de log deve incluir:
{ "level": "info", "msg": "...", "tenantId": "...", "userId": "...", "requestId": "...", "timestamp": "..." }
Rastreamento distribuído com OpenTelemetry:
- Instrumente no nível do framework (Next.js
instrumentation.ts, middleware Express) - Propague o contexto de rastreamento entre os limites do serviço (cabeçalho
traceparent) - Exporte para seu backend de escolha (Jaeger, Honeycomb, Datadog, Grafana Tempo)
Métricas por tenant para rastrear:
- Usuários ativos (DAU/MAU), volume de chamadas de API, taxa de erro, latência p50/p95/p99, adoção de recursos, armazenamento consumido
Alertas:
- Alerte sobre anomalias em nível de tenant — pico repentino de erro, queda de uso, falhas de faturamento
- Defina SLOs por nível: gratuito (melhor esforço), pro (99,5%), enterprise (99,9%)
Ferramentas de administração (internas):
- Personifique um tenant para suporte (audite cada personificação)
- Visualize o log de auditoria, gerencie assinaturas, substitua feature flags, dispare o re-onboarding
- Construa um painel de saúde: status por tenant, erros recentes, tendências de uso
Dados, Análise e Conformidade
Rastreamento de eventos:
- Emita eventos de produto estruturados (
user.signed_up,feature.used,subscription.upgraded) para um data warehouse (Snowflake, BigQuery) ou CDP (Segment, PostHog, RudderStack) - Use esses eventos para previsão de churn, análise de coorte e pontuação PLG
GDPR / privacidade:
- Forneça um endpoint de exportação de dados e um endpoint de exclusão de conta — exigido pelo GDPR e esperado por compradores corporativos
- Documente sua política de retenção de dados; implemente purgas automatizadas
- Use gerenciamento de consentimento para cookies de marketing e análise
SOC 2 / higiene de conformidade (prontidão empresarial):
- Mantenha um log de auditoria de todas as ações do usuário que alteram o estado (quem, o quê, quando, de qual IP)
- Implemente controle de acesso baseado em funções (RBAC) com padrões de privilégio mínimo
- Aplique MFA para todas as contas de administrador; ofereça SSO (SAML/OIDC) para tenants corporativos
- Realize verificações regulares de vulnerabilidades de dependência e testes de penetração
- Mantenha uma política de divulgação de vulnerabilidades
Isolamento e Segurança de Dados
- Valide o
tenant_idem cada chamada de API contra a sessão autenticada — nunca confie no corpo da requisição - Limite a taxa por tenant para evitar efeitos de vizinho barulhento
- Faça o hash das chaves de API no BD (bcrypt ou Argon2); nunca armazene texto simples
- Exija HTTPS; defina
Strict-Transport-Securitycom ummax-agelongo - Use
HttpOnly; Secure; SameSite=Laxpara cookies de sessão
Exemplos
// Repositório com escopo de tenant com contexto RLS
class TenantRepository<T> {
constructor(
private readonly tenantId: string,
private readonly db: PrismaClient,
) {}
protected async withTenantContext<R>(fn: () => Promise<R>): Promise<R> {
return this.db.$transaction(async (tx) => {
await tx.$executeRaw`SELECT set_config('app.current_tenant', ${this.tenantId}, true)`;
return fn();
});
}
async findById(id: string): Promise<T | null> {
return this.withTenantContext(() =>
(this.db as any).findFirst({ where: { id, tenantId: this.tenantId } })
);
}
}
// Endpoint de streaming de IA com medição de uso por tenant
export async function POST(req: Request) {
const session = await getSession(req);
const { prompt } = await req.json();
const stream = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
stream: true,
});
let tokensUsed = 0;
const readable = new ReadableStream({
async start(controller) {
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content ?? '';
controller.enqueue(new TextEncoder().encode(text));
tokensUsed += chunk.usage?.completion_tokens ?? 0;
}
controller.close();
// medir o uso após a conclusão do streaming
await meteringService.record(session.tenantId, 'ai_tokens', tokensUsed);
},
});
return new Response(readable, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
// Webhook do Stripe com idempotência
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
const event = stripe.webhooks.constructEvent(
req.body, req.headers['stripe-signature']!, process.env.STRIPE_WEBHOOK_SECRET!
);
const seen = await db.webhookEvent.findUnique({ where: { stripeEventId: event.id } });
if (seen) return res.sendStatus(200);
await db.webhookEvent.create({ data: { stripeEventId: event.id, payload: event } });
switch (event.type) {
case 'customer.subscription.updated':
await subscriptionService.sync(event.data.object);
break;
case 'customer.subscription.deleted':
await subscriptionService.cancel(event.data.object.metadata.tenantId);
break;
}
res.sendStatus(200);
});