Skip to main content

Arquitetura da Plataforma

O Switchbord é implantado como uma aplicação Next.js multi-tenant na Vercel, com o Supabase como base para persistência, autenticação e realtime, e um worker hospedado na Railway para processamento em segundo plano. Não existe um serviço de control-plane separado — esse caminho arquitetural foi descontinuado e todas as responsabilidades de runtime foram consolidadas.

Topologia

  • apps/app: produto do operador — caixa de entrada, contatos, templates, campanhas, Margaret AI, configurações. Implantado na Vercel.
  • apps/web: site de marketing, fluxos de QR/opt-in, landing pages restritas. Implantado na Vercel.
  • apps/api: superfície de API Next.js para ingestão de webhook da Meta, API REST pública v1 (especificação OpenAPI em /spec), endpoints de compatibilidade e rotas de health/status. Implantado na Vercel.
  • apps/docs: documentação baseada em Mintlify. Implantado no Mintlify.
  • apps/worker: processamento de queue, retries, agendadores de campanha, despacho de mensagens, ferramentas de replay. Implantado na Railway.
  • Supabase: Postgres, Auth, Storage, Realtime, Vault. Fonte única de verdade.
O serviço apps/control-plane foi removido. Todo o trabalho de control-plane orientado a webhook agora é executado dentro de apps/api e apps/worker. Quaisquer referências locais à porta 4000 ou a apps/control-plane/.env.example são artefatos legados.

Caminhos Principais de Runtime

  1. Webhook de entrada — a Meta entrega um webhook para apps/api → assinatura verificada com crypto.timingSafeEqual → envelope bruto armazenado em webhook_events → o Supabase notifica o apps/worker → o worker roteia para o processador de mensagem, status, template ou jornada.
  2. Envio de saída — o operador ou uma automação cria uma intenção de envio → o Supabase registra em outbox_jobsapps/worker agenda considerando limites de throughput/pares → a resposta da Meta é registrada → webhooks de status atualizam o ledger.
  3. Disparos em massa — um snapshot de audiência é criado → o worker distribui os jobs de outbox → o Supabase Realtime envia o progresso da campanha ao dashboard do operador.
  4. Margaret AI — o operador aciona um rascunho de resposta de IA → apps/app chama /api/ai-assistant → o provider de LLM do workspace é resolvido a partir de llm_provider_configs → PII é pseudonimizado antes de qualquer prompt → a resposta é despseudonimizada → o rascunho aparece na caixa de entrada. A execução de agentes (BORD-140–143) adiciona uso de ferramentas (tool-use) sobre isso.

Modelo de Workspace Multi-Tenant

Cada tenant é um workspace isolado. As garantias centrais de isolamento são:
  • O contexto do workspace é resolvido no lado do servidor a partir de workspace_members — nunca a partir de variáveis de ambiente ou headers fornecidos pelo cliente.
  • Todas as consultas de dados são delimitadas por workspace_id, derivado dessa resolução.
  • O despacho de mensagens lê as credenciais da Meta a partir dos segredos do Vault pertencentes ao workspace proprietário — sem vazamento de credenciais entre workspaces.
  • Quatro papéis de RBAC aplicados em toda rota: owner, admin, developer, operator.
Veja Multi-Tenancy e Isolamento de Workspace para o modelo de segurança completo.

Camada Margaret AI

A camada de IA introduz três novas preocupações de runtime:
  • Configurações de provider de LLM — registros pertencentes ao workspace em llm_provider_configs, apontando para OpenAI, Anthropic, OpenRouter, Ollama ou vLLM. Chaves de API armazenadas no Supabase Vault via workspace_secret_bindings.
  • Agentes de IA — a tabela ai_agents define persona, modelo, permissões de ferramentas e configurações de pseudonimização de PII por workspace.
  • Threads de IAai_threads e ai_thread_messages mantêm o contexto de conversa para as respostas da Margaret. ai_agent_executions registra execuções de uso de ferramentas para fins de auditoria.

Ledger de Consentimento

O ledger de consentimento (BORD-193) fornece um registro durável e auditável de todo evento de opt-in e opt-out por contato:
  • Tabela consent_events — log somente de inserção (append-only) das transições de consentimento (opt-in / opt-out / revogado). Um trigger AFTER INSERT nessa tabela desnormaliza o estado mais recente em contacts.consent_state para leituras rápidas.
  • Detecção de palavras-chave STOP / STARTpackages/whatsapp analisa mensagens de entrada em busca de palavras-chave localizadas de opt-out (STOP, BLOQUEAR, FERMA, PARAR) e opt-in (START, INICIO, INIZIO, COMEÇAR) em inglês, italiano, português e espanhol.
  • Gate de opt-out no despacho de campanhas — o motor de disparos em massa verifica contacts.consent_state antes de enfileirar qualquer job de outbox. Contatos em estado opted_out ou revoked são ignorados silenciosamente.
  • Endpoints RESTGET /api/v1/contacts/:id/consent retorna o estado atual e o histórico de eventos; POST /api/v1/contacts/:id/consent registra uma transição de consentimento manual (apenas owner/admin).

Command Palette

O command palette (BORD-204) é uma superfície ⌘K para navegação, busca e ações em todo o produto do operador:
  • command-palette.tsx — o shell da paleta, acionado por ⌘K / Ctrl+K. Renderiza uma lista pesquisável de comandos agrupados por categoria.
  • command-palette-provider.tsx — contexto React que agrega os comandos disponíveis de cada módulo (caixa de entrada, contatos, campanhas, templates, jornadas, configurações) e gerencia o estado aberto/fechado.
  • command-palette-hint.tsx — badge de dica inline renderizado na barra lateral e nos cabeçalhos de página para ajudar a descobrir o atalho.
A paleta é extensível: qualquer módulo pode registrar comandos por meio do hook registerCommands do provider.

Editor Gráfico de Jornadas

Um canvas React Flow em /journeys/[id] para construir automações multi-etapas visualmente:
  • 9 tipos de node — Trigger, Condition, Wait, Send Template, Update Attribute, Add/Remove Tag, Outbound Webhook, AI Agent Step e Exit.
  • Validação — o editor valida campos obrigatórios, conectividade de edges e detecção de ciclos antes de publicar. Erros aparecem inline em cada node.
  • Pipeline de publicação — os grafos validados são serializados na tabela journeys como JSON versionado. Uma mutation publish cria um snapshot imutável e ativa a jornada para execução em tempo real pelo apps/worker.

Construtor Visual de Templates

Um construtor de 3 painéis em /templates/new para compor templates de mensagem do WhatsApp:
  • 7 editores — Header, Body, Footer, Buttons, Examples, Language e Category.
  • Coluna parameter_format — armazenada em message_templates para declarar o tipo e a ordem esperados das variáveis do template.
  • Pipeline de submissão à Meta — o construtor faz um POST do template composto para a Meta Business API e acompanha o status de aprovação por meio de webhooks de status de template.
  • Renderizador em phone-frame — um componente de preview em tempo real renderiza o template como ele apareceria em um dispositivo, com substituição de placeholders pelas variáveis.

Agente de Auto-Trigger

O agente de auto-trigger (BORD-192) estende a Margaret AI para redigir respostas automaticamente em mensagens de WhatsApp de entrada:
  • Gatilho de execução do agente — quando uma mensagem de entrada chega e o workspace tem um agente de auto-trigger configurado, agent.run é invocado automaticamente pelo worker.
  • API de aceitar/rejeitar rascunhoPOST /api/v1/contacts/:id/drafts/:draftId/accept e POST /api/v1/contacts/:id/drafts/:draftId/reject permitem que operadores aprovem ou descartem rascunhos gerados por IA.
  • Banner de rascunho na caixa de entrada — um banner visível na visualização da conversa avisa os operadores quando um rascunho está pendente, com ações de aceitar/rejeitar em um clique.

Armazenamento de Assets

O armazenamento de assets (BORD-187) fornece uploads de arquivos delimitados por workspace para templates, jornadas e assets de conhecimento:
  • Tabela asset_files — registra metadados do arquivo (nome, tipo MIME, tamanho, escopo de workspace) e aponta para o objeto armazenado.
  • Pipeline compatível com S3 — os uploads passam por um pipeline de URL pré-assinada para qualquer object store compatível com S3. O worker recupera os objetos no momento do despacho para envios de mídia.
  • Isolamento de workspace — todo arquivo é delimitado por workspace_id; o acesso entre workspaces é rejeitado na camada de API.

Alertas de Conta

Os alertas de conta (BORD-189) exibem para os operadores problemas em nível de conta da Meta:
  • Handler de webhookapps/api processa eventos de webhook account_alerts da Meta e os armazena em account_alert_events.
  • Painel de UI do operador — um painel dedicado nas configurações exibe alertas ativos (por exemplo, violações de política, avisos de rate limit, expiração de credencial) com severidade e passos de resolução.

Logs de Auditoria

Os logs de auditoria (BORD-158) registram ações do operador para conformidade e forense:
  • Tabela audit_logs — log somente de inserção (append-only), delimitado por workspace, de ator, ação, recurso alvo e payload de diff.
  • writeAuditLog() — um helper do lado do servidor que toda rota de mutation chama antes de fazer commit. Garante estrutura consistente e evita omissões acidentais.

Retenção de Dados LGPD/GDPR

A retenção de dados LGPD/GDPR (BORD-165 / BORD-167) impõe limites de retenção por workspace:
  • data_retention_days — uma configuração em nível de workspace (padrão 365). Controla por quanto tempo envelopes de webhook, conteúdo de mensagem e eventos de consentimento são retidos.
  • Job retention_sweep — um job agendado do worker que exclui registros mais antigos que a janela de retenção do workspace. Executa diariamente; registra métricas de limpeza em audit_logs.

Geração de Chave de API

A geração de chave de API (BORD-178) permite que owners de workspace provisionem chaves de API de longa duração:
  • Chaves com prefixo swb_ — geradas no servidor com um segredo criptograficamente aleatório de 32 bytes. O prefixo permite identificação visual rápida e detecção programática em logs.
  • Metadados de chave — armazenados em api_keys com timestamp de criação, timestamp de último uso e descrição opcional. As chaves são armazenadas com hash em repouso; o segredo completo é exibido apenas uma vez, no momento da criação.

Wizard Guiado

O wizard guiado (BORD-194) fornece um fluxo de onboarding do primeiro acesso até a primeira mensagem:
  • Sequência de etapas — conectar número de WhatsApp → configurar provider de LLM → criar o primeiro template → enviar a primeira mensagem.
  • Rastreamento de progresso — armazenado em workspace_onboarding_state. O wizard avança automaticamente e pode ser dispensado após a conclusão.
  • Ponto de entrada — workspaces recém-criados são redirecionados para /welcome no primeiro login. O wizard também está acessível a partir de Configurações.

Primitivas do Design System

Novas primitivas de design system lançadas em packages/design-system:
  • Tokens de design — tokens semânticos de cor, espaçamento e tipografia em tokens.css, consumidos por todos os componentes shadcn/ui.
  • Motion — utilitários consistentes de transição e animação em motion.ts (durações, easings, presets de entrada/saída).
  • Skeleton — componente Skeleton com animação de pulso, usado como placeholder de carregamento em todo o produto do operador.

Atualizações de Marca

  • Wordmark transparente — o logo da barra lateral expandida agora usa um wordmark SVG com fundo transparente para renderização limpa em qualquer superfície.
  • Favicon com fundo pretofavicon.ico atualizado para uma variante com fundo preto para maior visibilidade nas abas do navegador.

Princípios de Dados e Segurança

  • Todo envelope de webhook é imutável; corpo bruto + metadados são retidos com controles de retenção configuráveis.
  • O histórico de entrega é somente de inserção (append-only) (outbox_jobs, message_status_events) — nunca sobrescrito.
  • RBAC, feature flags e segredos de provider permanecem exclusivamente no lado do servidor.
  • Tópicos privados de Supabase Realtime Broadcast alimentam os feeds em tempo real do operador; nenhum Postgres Changes broadcast é usado, para evitar problemas de escalabilidade.
  • Log de auditoria em toda ação do operador e rotação de credencial.
  • O ledger de consentimento impõe opt-out antes de qualquer despacho de campanha ou automação.
  • As limpezas de retenção de dados impõem os prazos de exclusão da LGPD/GDPR por workspace.
Veja Visão Geral de Segurança para o status completo de implementação dos controles.

UI do Operador — Barra Lateral e Navegação

A UI do operador (apps/app) usa uma barra lateral construída sobre as primitivas Sidebar do shadcn/ui.

Componente

  • Arquivo: apps/app/components/operator-sidebar.tsx (~165 linhas)
  • Padrão: collapsible='icon' — recolhe para um trilho somente com ícones; expande ao passar o mouse ou ao alternar. A interface de props é estável.
  • Layout: cada página que precisa da barra lateral envolve seu conteúdo com SidebarProvider.

Estrutura de navegação

  • Seção superior (nav plana): Caixa de entrada / Contatos / Disparos em massa / Templates / Operações
  • Seção inferior (rodapé): Configurações / Docs / Conta do usuário

Tema

A barra lateral usa os valores padrão de variáveis CSS claras do shadcn — não há tema escuro customizado ou className='dark' aplicado ao elemento da barra lateral. Variáveis relevantes (definidas em :root em packages/design-system/styles/globals.css):
  • --sidebar: fundo quase branco
  • --sidebar-foreground: texto quase preto
O tema escuro customizado quase preto da barra lateral, existente antes do PR #270, foi removido. A barra lateral agora herda os tokens padrão do design system claro do workspace.
  • Expandida: wordmark completo
  • Recolhida: marca somente com ícone

Monitoramento + Deployment

  • Endpoints de health: /health, /ready, /internal/runtime.
  • Endpoints operacionais: /internal/webhooks, /internal/webhook-rejections, /internal/webhooks/:id/replay.
  • Especificação OpenAPI + explorador Scalar: /spec.
  • Deploy de apps/app, apps/web, apps/api e apps/docs na Vercel/Mintlify. Deploy de apps/worker na Railway. Todas as superfícies compartilham o mesmo projeto Supabase.
  • O CI valida builds, migrations, lint de docs e verificações de segredos. Veja CI/CD.

Leia a seguir