Pular para o conteúdo

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

  1. Uma instância por tenant — Isolation total, mas custo operacional alto e duplicação massiva.
  2. Multi-tenant na mesma instância via DB — Configs no Postgres. Flexível, mas mistura dados sensíveis.
  3. Multi-tenant via arquivo config.yaml por 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

  1. Orquestrador roteando: um número WhatsApp, “supervisor” decide qual agente atende
  2. 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:

  • EvolutionProvider para clientes Kommo
  • StevoProvider para 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)

ProviderRAMvCPUSSDPreço/mês
Hetzner CPX318GB4160GB€15.39
DigitalOcean8GB4160GB$48
AWS t3.large8GB2100GB~$60
Railway8GB8varia~$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:

  1. Adicione nova entrada neste arquivo com próximo número (ADR-009, ADR-010, …)
  2. Use o formato: Status, Data, Contexto, Alternativas, Decisão, Consequências
  3. Mencione no commit
  4. 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