ADR-0001 -- Arquitetura Geral do Pilot Status
Status
Accepted
Context
O Pilot Status é uma plataforma SaaS para envio e automação de mensagens (atualmente via WhatsApp) utilizando números da plataforma e/ou números conectados.
Requisitos principais:
- Multi-tenant
- Ambientes separados (test e live)
- Versionamento e aprovação de templates
- Processamento assíncrono
- Rate limit por plano
- Observabilidade interna
- Sem exposição de webhook para clientes
Stack definida:
- TypeScript (full stack)
- Next.js (Frontend + API Routes como BFF)
- NextAuth (Google e GitHub)
- Prisma ORM
- PostgreSQL (gerenciado)
- Redis (gerenciado)
- BullMQ
- Workers dedicados
- Docker multi-stage
- VPS como ambiente de deploy
- Evolution API para envio de mensagens
1. Arquitetura Geral
Decisão
Adotar arquitetura baseada em:
- BFF com Next.js
- Processamento assíncrono com BullMQ
- Filas FIFO dedicadas por tenant
- Webhook interno para atualização de status
Fluxo de envio:
- Cliente chama API com API Key (ps_test_ ou ps_live_)
- API valida chave e aplica rate limit
- Registro é criado no banco
- Job é enviado para fila do tenant
- Worker consome fila e chama Evolution API
- Evolution API envia webhook interno
- Status é atualizado no banco
Consequências
- Escalabilidade horizontal via workers
- Desacoplamento entre requisição e envio real
- Melhor controle de throughput por tenant
2. Modelo Multi-Tenant
Decisão
- Isolamento lógico via tenant_id
- Cada tenant possui fila FIFO própria
- Redis único compartilhado
- Banco único com segregação lógica
Consequências
- Simplicidade operacional
- Escalável para MVP
- Risco de contenção futura no Redis
3. Ambientes Teste vs Produção
Decisão
- Tabela environment
- API Keys separadas:
- ps_test_xxxxx
- ps_live_xxxxx
- Filas separadas por ambiente
- Templates podem ser duplicados de test para live
- Modo teste limitado a 10 mensagens/dia
Consequências
- Controle seguro de uso
- Separação lógica clara
- Não há sandbox real de WhatsApp
4. Templates e Versionamento
Decisão
- Templates armazenados em JSON estruturado
- Versionamento obrigatório
- Cada versão deve ser aprovada por admin
- Logs armazenam template_version_id utilizado
Consequências
- Auditoria completa
- Histórico preservado
- Complexidade adicional na modelagem
5. API Keys
Decisão
Formato:
- ps_test_xxxxxxxxx
- ps_live_xxxxxxxxx
Armazenamento:
- Hash no banco
- Sem rotação
- Sem escopo granular
Usadas para:
- Identificar tenant
- Aplicar rate limit
Consequências
- Simplicidade
- Risco maior em caso de vazamento
- Não há controle fino de permissões
6. Rate Limiting
Decisão
- Rate limit por API Key
- Baseado no plano do usuário e no saldo de pacotes (ver ADR 9)
- Limites por plano: Gratuito 300/mês e 10/dia; Basic 700/mês; Pro 3000/mês; pacotes somam ao limite mensal
- Sem retry automático
- Sem Dead Letter Queue
- Fila FIFO por tenant
Consequências
- Simplicidade no MVP
- Falhas transitórias resultam em falha definitiva
- Sem reprocessamento automático
7. Observabilidade
Decisão
Implementar:
- Structured logs
- Correlation ID por mensagem
- Métricas internas:
- Taxa de falha
- Tempo médio de envio
- Volume por tenant
- Monitoramento de filas
- Analytics com Umami para frontend e backend (coleta de uso e comportamento)
Consequências
- Maior controle operacional
- Base para evolução futura
- Umami centraliza métricas de produto em ferramenta única, open-source e com foco em privacidade
8. Infraestrutura
Decisão
- Deploy em VPS
- PostgreSQL gerenciado
- Redis gerenciado
- Docker multi-stage
- Sem estratégia formal de backup (MVP)
Consequências
- Custo reduzido
- Risco operacional em caso de perda de dados
- Backup deverá ser implementado em fase posterior
9. Planos, Pacotes e Rate Limit
Decisão
- Três planos: Gratuito (300 msg/mês, 10 msg/dia), Basic (700 msg/mês, sem limite diário), Pro (3000 msg/mês, sem limite diário).
- Dois pacotes adicionais: Pacote 1 (+300 msg), Pacote 2 (+1000 msg).
- Rate limit por API Key baseado no plano e no saldo de mensagens (plano + pacotes comprados no período).
Consequências
- Lógica de contagem mensal e, no Gratuito, contagem diária.
- Necessidade de modelo de assinatura (plano) e de compra de pacotes (crédito de mensagens).
10. Pagamentos
Decisão
- Stripe: pagamento com cartão para assinatura mensal (planos Basic e Pro) e para compra de pacotes.
- Pague Dev: pagamento via Pix para compra de pacotes e pagamento único quando aplicável.
Consequências
- Integração com duas plataformas de pagamento.
- Webhooks ou confirmação de pagamento para ativar/renovar plano e creditar mensagens dos pacotes.
Trade-offs Conscientes (MVP)
- Sem retry
- Sem DLQ
- Sem rotação de API Key
- Sem backup formal
- Redis único compartilhado
Essas decisões foram tomadas para reduzir complexidade inicial e acelerar validação do produto.