Decisões Arquiteturais (ADR)
Histórico de decisões técnicas importantes da plataforma Triadeflow. Cada decisão documenta contexto, alternativas consideradas e consequências.
Formato baseado em Michael Nygard ADR template.
ADR-001: Multi-tenant via instância única + config.yaml
Status: Aceito Data: 2026-04-15
Contexto
Triadeflow precisa servir N clientes (tenants) com perfis e configurações diferentes. Cada tenant tem seu próprio prompt, KB, integrações, custom fields. Como organizar?
Alternativas consideradas
- Uma instância por tenant — Isolation total, mas custo operacional alto e duplicação massiva.
- Multi-tenant na mesma instância via DB — Configs no Postgres. Flexível, mas mistura dados sensíveis.
- Multi-tenant via arquivo
config.yamlpor tenant — Configs versionadas em Git, instância única consome.
Decisão
Opção 3: Multi-tenant via instância única + config.yaml por tenant.
agent-{tipo}/└── tenants/ ├── _defaults.yaml ├── usa-salus/config.yaml ├── dra-milena/config.yaml └── ...A instância carrega config baseado em tenant_id extraído do webhook URL ou do payload.
Consequências
Positivas:
- Configs versionadas no Git (auditoria)
- Hot-reload sem restart
- Zero duplicação de código
- Custo operacional baixo
Negativas:
- Bug em uma instância afeta todos os tenants daquele tipo
- Necessário cuidado com isolation de RAG (collections separadas no Qdrant)
- Configs com secrets requerem
${VAR}resolution em runtime
ADR-002: Agentes independentes, sem orquestrador
Status: Aceito Data: 2026-04-15
Contexto
Cliente pode ter necessidade de múltiplos tipos de agente (SDR + Pós-venda, ou Vendas + Suporte). Como organizar?
Alternativas
- Orquestrador roteando: um número WhatsApp, “supervisor” decide qual agente atende
- Agentes independentes: cada tipo é deploy/produto separado, cliente contrata múltiplos números
Decisão
Opção 2: Agentes independentes.
Razão: orquestrador adiciona complexidade enorme (handoff de contexto, state compartilhado, decisão de roteamento) sem benefício proporcional. Cliente que quer múltiplos agentes geralmente tem volume e operação que justifica múltiplos números.
Consequências
Positivas:
- Cada agente é simples, focado, deploy independente
- Falha em um não afeta outro
- Pricing transparente (cliente sabe exatamente o que paga)
Negativas:
- Cliente precisa entender que vai ter múltiplos números
- Marketing precisa explicar limitação clara
- Casos onde “transbordo” entre agentes seria ideal não são suportados
ADR-003: GraphRAG é overkill, vetorial vence
Status: Aceito Data: 2026-04-22
Contexto
GraphRAG (Microsoft) é tendência recente. Vale adotar?
Análise
GraphRAG brilha em:
- Knowledge bases enormes (1M+ docs)
- Perguntas complexas multi-hop
- Necessidade de “entender” relações entre conceitos
Casos Triadeflow típicos:
- KB de 50-500 documentos por tenant
- Perguntas factuais ou conversacionais
- Relações são lineares (produto → preço, política → exceção)
Decisão
Manter Qdrant (vetorial simples) + tools + bom prompt. GraphRAG fica como tema de pesquisa, não roadmap.
Consequências
Positivas:
- Stack mais simples
- Custo de infra menor
- Iteração mais rápida
Negativas:
- Casos raros multi-hop podem ter qualidade subótima — mitigação via tools específicas
ADR-004: Provider abstrato (Evolution + Stevo)
Status: Aceito Data: 2026-04-25
Contexto
Clientes usam dois ecossistemas de CRM (Kommo e GHL) que pedem providers diferentes de WhatsApp.
Decisão
Interface WhatsAppProvider no core, com implementações concretas:
EvolutionProviderpara clientes KommoStevoProviderpara clientes GHL
class WhatsAppProvider(ABC): @abstractmethod async def send_text(self, to: str, text: str) -> SendResult: ...
@abstractmethod async def send_media(self, to: str, media_url: str, ...) -> SendResult: ...Tenant config indica qual provider usar.
Consequências
Positivas:
- Lógica de domínio agnóstica de provider
- Fácil adicionar Z-API, WhatsApp Cloud API no futuro
- Testes podem usar
MockProvider
Negativas:
- Capabilities específicas (ex: stickers customizados em algum provider) ficam abstraídas no menor denominador comum
ADR-005: Langfuse self-hosted
Status: Aceito Data: 2026-04-26
Contexto
Observabilidade de LLMs é crítica. Opções: Langfuse, Helicone, LangSmith, Arize, custom.
Análise
- LangSmith: vendor lock LangChain, paid, dados na nuvem deles
- Helicone: bom mas menos features de eval
- Arize: enterprise, caro, complexo
- Langfuse: open source, self-hosted possível, dataset/eval/annotation built-in
- Custom: tempo de dev grande, manter pra sempre
Decisão
Langfuse self-hosted no Hetzner.
Razões:
- Dados sensíveis ficam em servidor próprio
- Custo zero de licença (apenas infra)
- Features completas: tracing, eval, datasets, scoring, annotation queue
- Comunidade ativa
- Pode escalar conforme necessário
Consequências
Positivas:
- Controle total dos dados
- Sem vendor lock
- Possibilidade de customização
Negativas:
- Manutenção da infra é responsabilidade nossa
- Updates manuais
- Backup/DR é nossa responsabilidade
ADR-006: Sem emojis em código, prompts e docs internos
Status: Aceito Data: 2026-05-01
Contexto
Preferência forte do Alex (operador principal). Emojis em logs, comentários e docs são ruído.
Decisão
Zero emojis em:
- Código fonte (comentários, docstrings, logs)
- Prompts de agente
- Configurações YAML
- Documentação interna (
.md) - Mensagens de commit
Permitido:
- Mensagens visíveis ao cliente final SE o tom do nicho/cliente requer (raro, geralmente não)
- Caracteres Unicode estruturais (▣, ✓, →) em casos específicos de visual
Consequências
Positivas:
- Comunicação mais profissional
- Menos ambiguidade em logs
- Diff cleaner
Negativas:
- Necessário lembrar quando usar libs/templates externos com emojis padrão
ADR-007: Hetzner como cloud principal
Status: Aceito Data: 2026-04-30
Contexto
Onde hospedar a infra? AWS, GCP, DigitalOcean, Hetzner, Railway?
Análise comparativa (CPX31 equivalente)
| Provider | RAM | vCPU | SSD | Preço/mês |
|---|---|---|---|---|
| Hetzner CPX31 | 8GB | 4 | 160GB | €15.39 |
| DigitalOcean | 8GB | 4 | 160GB | $48 |
| AWS t3.large | 8GB | 2 | 100GB | ~$60 |
| Railway | 8GB | 8 | varia | ~$20+escala alta |
Decisão
Hetzner Cloud como principal.
Razão: melhor custo/benefício do mercado, performance excelente, SSD NVMe rápido, datacenters Europa (latência aceitável para Brasil), API moderna.
Consequências
Positivas:
- Custo de infra ~3-4x menor que AWS
- Performance previsível
- Suporte responsivo
Negativas:
- Datacenters fora do Brasil (latência ~150-200ms)
- Menos serviços managed (precisa gerenciar Postgres, Redis, etc)
- Mitigação: Cloudflare CDN para assets e proxy reverso
ADR-008: Astro + Cloudflare Pages para docs
Status: Aceito Data: 2026-05-03
Contexto
Documentação técnica precisa de site visual. Opções: MkDocs, Docusaurus, VuePress, Astro, custom.
Decisão
Astro + Cloudflare Pages.
Razões:
- Astro renderiza markdown nativamente, com syntax highlighting e componentes
- Build extremamente rápido
- Cloudflare Pages: deploy automático, grátis, CDN global
- URL custom (triadeflow.dev)
- Preview por PR
Consequências
Positivas:
- Site profissional sem complexidade
- Deploy automático em cada push
- Preview de PRs para revisão
Negativas:
- Build local requer Node.js
- Componentes customizados em Astro têm curva de aprendizado
Como adicionar uma decisão nova
Ao tomar decisão arquitetural relevante:
- Adicione nova entrada neste arquivo com próximo número (ADR-009, ADR-010, …)
- Use o formato: Status, Data, Contexto, Alternativas, Decisão, Consequências
- Mencione no commit
- Se altera comportamento de produção, atualize
CHANGELOG.md
Decisões “menores” (ex: trocar versão de lib) não precisam ser ADR — registre no commit message.
Última atualização: 2026-05-03