Skip to content

Arquitetura do flow-ai

Plataforma de atendimento multicanal — WhatsApp, WebChat e Instagram — com suporte a chatbot, agentes de IA (LLM) e handoff humano. A arquitetura é orientada a eventos: serviços internos comunicam-se exclusivamente por Redis Streams, sem chamadas HTTP entre si. HTTP existe apenas nas bordas — entrada dos canais (Meta, Instagram) e entrada dos frontends.


Visão de 30 segundos

   Meta Cloud API      Instagram Graph API        Browser
        │                     │                      │
        │ webhook             │ webhook              │ Socket.io
        ▼                     ▼                      ▼
 flow-ai-meta-api      flow-ai-ig-api      flow-ai-webchat-gateway
     (:4444)              (:4445)                (:4001)
        │                     │                      │
        └─────────────────────┼──────────────────────┘
                              │ stream:incoming

                   flow-ai-orchestrator (sem HTTP)
                (persiste, gerencia sessão, roteia)
              ┌───────────────┼────────────────┐
        stream:flow      stream:agent      stream:helpdesk
              │               │                 │
              ▼               ▼                 ▼
       flow-ai-engine   flow-ai-agent     flow-ai-core (:3333)
      (executa o flow)  (loop LLM/tools)  (helpdesk, CRUD, API)
              │               │                 │
              └───────┬───────┘                 │ Socket.io
                      │                          │
     stream:outgoing-{meta,chat,ig}             ▼
                      │              flow-ai-desk / flow-ai-core-ui
        ┌─────────────┼──────────────┐        (frontends)
        ▼             ▼              ▼
 flow-ai-meta-api  webchat-gw   flow-ai-ig-api
 (envia p/ Meta)  (envia browser)(envia p/ IG)

Nota: stream:agent só é usado quando a sessão está no modo agent; o flow-ai-agent executa o loop de tool-calling do LLM e devolve respostas ao canal de origem.


Serviços

flow-ai-core — porta 3333

API administrativa + helpdesk em tempo real.

Responsabilidades:

  • CRUD de todas as entidades de negócio (Router, Flow, WhatsAppNumber, Tickets, Queues, etc.)
  • Fronteira de criptografia: único serviço que conhece CRYPTO_SECRET e popula os caches Redis com segredos decifrados
  • Helpdesk em tempo real via Socket.io: emissão de eventos para agentes, contagem de tickets em espera
  • Warm-up dos caches Redis no boot (bloqueante antes do listen())
  • Serve flow-ai-core-ui e flow-ai-desk via REST + Socket.io

Stack: Fastify 5, Prisma, PostgreSQL, Socket.io, JWT, Redis


flow-ai-meta-api — porta 4444

Borda burra entre a Meta e o sistema interno.

Responsabilidades:

  • Recebe webhooks da Meta, valida verify token + assinatura HMAC-SHA256 e normaliza o payload
  • Publica mensagens recebidas em stream:incoming (e stream:status, stream:templates, stream:wa-flow-logs)
  • Consome stream:outgoing-meta (grupo send) e envia mensagens para a Meta Cloud API
  • Resolve credenciais e app secret exclusivamente via Redis — nunca toca o Postgres

Stack: Fastify 5, Redis Streams


flow-ai-ig-api — porta 4445

Borda do canal Instagram — análogo ao flow-ai-meta-api para o Instagram.

Responsabilidades:

  • Recebe webhooks do Instagram, valida verify token (IG_VERIFY_TOKEN) e normaliza DMs em stream:incoming
  • Moderação de comentários de post/live: publica em stream:ig-comments e registra ativações em stream:ig-comment-activations
  • Consome stream:outgoing-ig (grupo send) e envia mensagens via Instagram Graph API
  • Resolve credenciais e roteamento exclusivamente via caches ig:* no Redis — nunca toca o Postgres

Stack: Fastify 5, Redis Streams


flow-ai-orchestrator — sem HTTP

Consumer de stream:incoming. Ponto de coordenação central.

Responsabilidades:

  • Persiste mensagens recebidas no banco
  • Cria ou retoma SessionState no Redis
  • Em nova sessão: resolve routerId + initialFlowId por canal — wa:router:{phoneNumberId} (WhatsApp), wc:channel:{channelId} (WebChat) ou ig:router:{igUserId} (Instagram)
  • Roteia para stream:flow (modo flow), stream:agent (modo agent) ou stream:helpdesk (modo human)
  • Persiste as mensagens outbound (consome stream:outgoing-meta e stream:outgoing-chat no grupo persist)
  • Persiste status de entrega das mensagens outbound (stream:status)

Stack: Prisma, PostgreSQL, Redis Streams


flow-ai-engine — sem HTTP

Consumer de stream:flow. Executa a máquina de estados do flow.

Responsabilidades:

  • Carrega SessionState + PublishedFlow + variáveis do router/flow do Redis
  • Percorre blocos: avalia condições, executa actions, aguarda input do usuário
  • Publica respostas no stream de saída conforme o prefixo do sessionIdstream:outgoing-meta (WhatsApp), stream:outgoing-chat (wc-*, WebChat) ou stream:outgoing-ig (ig-*, Instagram)
  • Publica handoff em stream:helpdesk quando entra num HumanAttendanceBlock
  • Ao pausar num AgentBlock, publica em stream:agent para transferir o controle ao flow-ai-agent
  • Emite stream:analytics, stream:tool-executions e stream:summary durante a execução
  • Suporta scripts V8 Isolate sandboxado, chamadas HTTP, redirecionamentos entre flows

Stack: isolated-vm (sandbox), OpenAI SDK, flow-ai-runtime, Prisma, Redis Streams


flow-ai-agent — sem HTTP

Consumer de stream:agent. Executa o loop de tool-calling do LLM quando a sessão está no modo agent.

Responsabilidades:

  • Consome stream:agent (grupo agent, consumer serial único)
  • Roda o loop LLM (Responses API): monta contexto, chama tools, encadeia agentes (orchestrator → specialist)
  • Mantém SessionState.mode = "agent" e o AgentState (histórico, previousResponseId, pilha de agentes)
  • Emite respostas ao canal em stream:outgoing-meta / stream:outgoing-chat
  • Emite stream:agent-turns (AI Debugger), stream:llm-usage (custo/tokens) e stream:summary
  • Cria/fecha tickets de IA e faz handoff via stream:helpdesk; ao encerrar, retoma o flow via stream:flow

Nota: o flow-ai-agent ainda não roteia para stream:outgoing-ig. Uma sessão de agente de IA respondendo em uma conversa ig-* publica em stream:outgoing-meta (canal incorreto) — ver services/flow-ai-agent/src/tools/response.ts.

Stack: @anthropic-ai/sdk, OpenAI SDK, flow-ai-runtime, Prisma, Redis Streams


flow-ai-webchat-gateway — porta 4001

Canal WebChat — equivalente ao flow-ai-meta-api para o browser.

Responsabilidades:

  • Autentica conexões Socket.io via sessionKey (bcrypt) + channelId
  • Cria/retoma WebChatIdentity no Postgres
  • Publica mensagens do browser em stream:incoming com channelType: "webchat"
  • Consome stream:outgoing-chat e entrega ao socket correto via room wc-{channelId}-{userId}

Stack: Socket.io, Prisma, Redis, bcrypt


Modos de sessão

O SessionState carrega um campo mode (SessionMode) que determina para qual stream o orchestrator roteia cada mensagem recebida:

modeRoteia paraQuem processa
flowstream:flowflow-ai-engine (máquina de estados do flow)
agentstream:agentflow-ai-agent (loop LLM de tool-calling)
humanstream:helpdeskflow-ai-core (atendimento humano)

Nota: não existe modo frozen. Uma sessão travada por erro de runtime permanece em mode: "human" e carrega o campo frozenByError (SessionFrozenError). O AgentState só está presente quando mode === "agent".


Packages

PackageResponsabilidade
flow-ai-databaseSchema Prisma centralizado + client singleton. Fonte da verdade do banco.
flow-ai-redisFunções de acesso ao Redis: streams, caches, pub/sub, sessões, constantes de chaves e graceful shutdown.
flow-ai-typesTipos TypeScript compartilhados: SessionState, eventos de stream, ai-agents, instagram, webchat, FlowDefinition, DTOs.
flow-ai-whatsapp-flow-engineEngine declarativo para WhatsApp Flows Meta — validação, steps HTTP, criptografia RSA+AES.
flow-ai-runtimePrimitivas de execução de Tool compartilhadas por flow-ai-engine e flow-ai-agent: interpolação, avaliação de condições, sandbox isolated-vm, executeTool, executeCallAI, executeFetchMedia.
flow-ai-telemetryBootstrap OpenTelemetry: initTelemetry(serviceName) (async, ordem forçada), spans e propagação de contexto de trace entre mensagens de stream. Config dirigida pela UI via observability:config.
flow-ai-loggerFactory de logger pino (createLogger); níveis via LOG_LEVEL / LOG_LEVEL_{SERVICE}, pino-pretty em dev.
flow-ai-benchmarkFramework de load/chat-test, CLI flow-benchmark; consumido pelo flow-ai-core.

Apps (frontends)

AppPortaDescrição
flow-ai-core-ui3001Studio de configuração — routers, builder de flows, números WhatsApp, variáveis, templates.
flow-ai-desk3000Desk de atendimento humano — tickets em tempo real, histórico de conversas, transferências.
flow-ai-docs5173Este portal de documentação — VitePress + Scalar API Reference.

Stack dos frontends: Next.js 15, React 19, TypeScript, Tailwind CSS, Socket.io-client


Streams Redis

Todos os serviços internos se comunicam por streams. Nenhuma chamada HTTP interna existe.

Nomes e grupos canônicos em packages/flow-ai-redis/src/constants.ts; mapa de grupos em STREAM_GROUP_MAP (streams.ts).

StreamProdutorConsumidor(es) — grupoConteúdo
stream:incomingmeta-api, ig-api, webchat-gatewayorchestratorMensagem recebida do usuário (sempre em formato WhatsApp)
stream:floworchestrator, engine, agent, coreengine (engine)Evento para execução do flow
stream:helpdeskorchestrator, engine, agent, corecore (core)Handoff e mensagens em atendimento humano
stream:outgoing-metaengine, agent, coremeta-api (send) + orchestrator (persist)Mensagem a enviar via WhatsApp
stream:outgoing-chatengine, agent, corewebchat-gateway (webchat) + orchestrator (persist)Mensagem a entregar no browser
stream:outgoing-igengine, core, ig-apiig-api (send)Mensagem a enviar via Instagram
stream:statusmeta-api, ig-api, webchat-gatewayorchestrator (status), core (core-status, core-campaigns-status)Status de entrega (sent, delivered, read, failed)
stream:wa-flow-logsmeta-apicore (core-wa-flow-logs, core-wa-flow-deferred)Logs de webhook de WhatsApp Flows
stream:templatesmeta-apicore (core-templates)Eventos WABA-level de status/quality de templates
stream:analyticsenginecore (core-analytics)Eventos de recordEvent — persistidos em event_occurrences
stream:tool-executionsenginecore (core-tool-executions)Execuções de Tool — persistidas em tool_execution_log
stream:agentengine, agent, orchestrator, coreagent (agent)Início/retomada de sessão de agente de IA e handoff manual
stream:agent-turnsagentcore (core-agent-turns)Turnos do agente de IA (AI Debugger) — persistidos em agent_turns
stream:llm-usageagentcore (core-llm-usage)Uso de tokens/custo — persistido em llm_usage
stream:summaryengine, agent, corecore (core-summary)Pedidos de sumarização de conversa via LLM
stream:ig-commentsig-apiig-api (ig-comments)Comentários de post/live do Instagram (moderação)
stream:ig-comment-activationsig-apicore (core-ig-comment-activations)Disparos de gatilho de comentário — persistidos em instagram_comment_activations

Nota: stream:outgoing é legado/inativo — a constante OUTGOING existe em constants.ts, mas não está no STREAM_GROUP_MAP e não tem produtor nem consumidor. Os três streams de saída vivos são stream:outgoing-meta, stream:outgoing-chat e stream:outgoing-ig.

Nota: o grupo persist está registrado em stream:outgoing-ig (STREAM_GROUP_MAP), mas nenhum consumidor o lê. Consequência: as mensagens de saída do Instagram são enviadas, porém não são persistidas no Postgres pelo orchestrator.


Caches Redis (chaves principais)

Sessão e estado (escritos pelos serviços de runtime):

ChaveQuem escreveQuem lêConteúdo
session:{sessionId}orchestrator, engine, agentorchestrator, engine, agent, coreSessionState com TTL = expiryTimeout
sessions:active:{routerId}orchestrator, corecoreSorted set de sessões ativas (score = lastInteractionAt)
sessions:frozenengine, corecoreSorted set de sessões congeladas por erro

Config e credenciais (flow-ai-core é o único escritor):

ChaveQuem lêConteúdo
wa:router:{phoneNumberId}orchestrator{ routerId, initialFlowId }
wa:credentials:{phoneNumberId}meta-api{ accessToken, displayName, wabaId }
wa:webhook:{phoneNumberId} / wa:webhook:waba:{wabaId}meta-api{ routerId, appSecret }
wa:encryption:{phoneNumberId}meta-api{ privateKeyPem, passphrase }
meta:verify-token:{token}meta-api{ routerId }
wa:flow:{metaFlowId}meta-api{ endpointConfig, phoneNumberId, ... }
wc:channel:{channelId}webchat-gateway, orchestrator{ routerId, initialFlowId, appearance } (TTL 3600s)
ig:credentials:{igUserId}ig-apiCredenciais do canal Instagram
ig:router:{igUserId}orchestrator{ routerId, initialFlowId } do Instagram
ig:webhook:{igUserId}ig-apiConfig de assinatura do webhook IG
ig:comment-triggers:{igUserId}ig-apiGatilhos (régua) de moderação de comentário
vars:router:{routerId}engineRecord<string, string> (variáveis decifradas)
vars:flow:{flowId}engineRecord<string, string> (variáveis decifradas)
tool:{toolId}engine, agentToolDefinition publicada
integration:server:{serverId}engine, agentConfig de servidor de integração
agent:{agentId}agentConfig do agente de IA (AgentConfig)
llm:credential:{credentialId}agent, coreCredencial LLM decifrada
observability:configtodos os serviçosConfig de telemetria (singleton, dirigida pela UI)

Chaves de moderação de comentário IG (escritas fora do core):

ChaveQuem escreveConteúdo
ig:comment-handled:{igUserId}:{commentId}ig-apiDedupe atômico (SET NX EX) por comentário
ig:comment-intent / ig:comment-destination:{igUserId}:{from}ig-apiIntent/destino pendente do gatilho (consumo GETDEL)
ig:pending-comment-reply:{sessionId}orchestratorcommentId para a 1ª resposta ir como Private Reply

Princípio: o flow-ai-core é o único escritor dos caches de config e credenciais (centraliza a fronteira de criptografia e simplifica a invalidação). Os caches de sessão/estado são escritos pelos serviços de runtime, e algumas chaves efêmeras de Instagram são escritas pelo flow-ai-ig-api e pelo orchestrator.


Banco de dados (PostgreSQL)

77 modelos (+ 10 enums) organizados em grupos lógicos:

  • Identidade / RBAC: User, Group (permissões em JSON + routerIds de escopo), ApiClient (token M2M SHA-256), UserDevice, PasswordRecovery
  • Conversação: Contact, Chat, Message, ContactOptIn
  • Helpdesk: Ticket (kind human/ai, lineage previousTicketId), TicketTag, Tag, Queue, QueueAgent, QueueDistributionRule
  • Flows / Tools: Flow, PublishedFlow, FlowVariable, FlowTag, ScriptTemplate, Tool, PublishedTool, ToolExecutionLog, IntegrationServer, IntegrationEndpoint, ImportDraft, SessionRuntimeError
  • Configuração / Router: Router, RouterVariable, WhatsAppNumber, LlmCredential, ObservabilitySettings (singleton), Integration, RouterIntegration, MetaDataDeletionRequest
  • WhatsApp Flows: WhatsAppFlow, WhatsAppFlowPublishLog, WhatsAppFlowWebhookLog, WhatsAppFlowDeferredJob, MessageTemplate
  • WebChat: WebChatChannel, WebChatIdentity
  • Instagram: InstagramAccount, InstagramCommentTrigger, InstagramCommentActivation
  • Multicanal: ChannelTypeMapping (conversão de conteúdo WA → IG/WebChat)
  • Agentes de IA: AiAgent, AiAgentRoute, AiAgentTool, SystemPrompt, AgentSystemPrompt, Guardrail, AgentRagDocument, AgentRagChunk (pgvector), LlmUsage, AgentTurn
  • Atendimento: Department, DepartmentAgent, MessageGroup, DepartmentMessageGroup, QuickReply, Agent, AgentGroup
  • DeskActions: DeskActionCategory, DeskAction, DeskActionAgentGroup, DeskActionDepartment
  • Eventos / Campanhas / Auditoria: EventDefinition, EventOccurrence, Report, Campaign, CampaignRecipient, AuditLog
  • Chat-Test: FlowGuide, FlowGuideStep, TestRun, TestRunStep

Ver o guia Modelo de dados para o diagrama completo com relações.


Infraestrutura de desenvolvimento

Monorepo: pnpm workspaces + Turborepo
Node: ≥ 20
Banco: PostgreSQL 16
Cache: Redis 7

bash
pnpm dev          # inicia todos os serviços em paralelo
pnpm dev:local    # sem flow-ai-meta-api (teste local sem Meta)
pnpm typecheck    # validação TypeScript em todo o monorepo
pnpm lint         # ESLint em todo o monorepo

Migrações:

bash
cd packages/flow-ai-database
pnpm prisma migrate dev    # aplica migrações pendentes
pnpm prisma generate       # regenera o Prisma Client

flow-ai — plataforma proprietária de atendimento via WhatsApp