Arquitetura
A arquitetura do Nodaro, para operadores e colaboradores: editor, API Fastify, workers BullMQ, Redis, armazenamento, três modos de autenticação e edições.
O Nodaro é um motor de workflows de IA que prioriza REST (REST-first). Um editor no navegador permite que os usuários conectem nós de IA — geração de imagens e de vídeos, composição de vídeo, modelos de texto e áudio — em um grafo. O grafo é armazenado no Supabase Postgres e, quando é executado, uma API Fastify o ordena e entrega o trabalho de cada nó a workers de filas no Redis. Os provedores de modelos fazem a geração, e os resultados vão para um armazenamento compatível com S3.
O mesmo código atende três edições, Community, Business e Cloud, e aceita três tipos de tokens de acesso. Esta página é para os operadores que rodam o Nodaro e para os colaboradores que o modificam.
O sistema em uma visão geral
O repositório
O repositório público, github.com/nodaroai/app.nodaro.ai, é um monorepo com npm workspaces:
| Pasta | O que fica ali |
|---|---|
backend/ | A API Fastify, os workers do BullMQ e o orquestrador. Node.js 22, TypeScript. |
frontend/ | O app do navegador: o editor, o executor de apps e o painel de administração. React 19, React Router 7, React Flow. |
packages/ | O código compartilhado e os pacotes npm publicados @nodaro/shared, @nodaro/sdk e @nodaro/cli, além das composições de vídeo do Remotion. |
supabase/ | O esquema do banco de dados, como migrações SQL que só avançam. |
docs/ | A documentação do produto, incluindo notas de design. |
tools/ | Scripts para operadores: o gerador de chaves, o teste de contrato, o backup e a restauração. |
examples/ | Exemplos, como um workflow do GitHub Actions que atualiza um servidor por SSH. |
Frontend
O frontend é um app de página única em Vite. Na imagem Docker, o servidor web, o Caddy, o serve como arquivos estáticos. Ele reúne quatro produtos em um único bundle:
- O editor — o canvas React Flow, um painel de configurações por família de nós e um executor de grafos que executa os workflows no navegador durante a edição.
- O executor de apps — mostra um workflow publicado como um formulário simples de entradas e resultados.
- A tela de consentimento OAuth — onde os usuários aprovam apps de terceiros e clientes MCP, em
/oauth/authorize. - O painel de administração — só nas edições Business e Cloud.
O estado do servidor fica no React Query, o estado da interface no Zustand, e o estado do canvas no store do próprio React Flow.
API
A API é um servidor Fastify em Node.js 22, escrito em TypeScript. As rotas são plugins do Fastify, e todo endpoint declara um schema para a requisição e a resposta. Os mesmos schemas validam cada requisição e geram o documento OpenAPI 3.1 em /v1/openapi.json. GET /v1/nodes lista os tipos de nó que a instalação consegue executar.
Um único hook de autenticação roda antes de todas as rotas: veja Autenticação.
Processos e filas
O backend vem como cinco processos Node.js em uma única imagem:
| Processo | Papel |
|---|---|
| Servidor da API | A API HTTP. |
| Worker de mídia | Pega da fila os jobs por nó, chama os provedores de modelos e envia os resultados para o armazenamento. Mais de 40 tipos de job, como geração de imagens e de vídeos, processamento com ffmpeg e áudio. Concorrência padrão: 50, porque ele passa a maior parte do tempo esperando a rede. |
| Worker de renderização | O renderizador Remotion, para composições, gráficos animados, sobreposições Lottie, títulos 3D e composições de camadas. Ele roda um Chrome headless e é limitado pela CPU. Concorrência padrão: 2. |
| Orquestrador | Executa workflows inteiros: lê uma execução, ordena o grafo dela e o executa nível por nível. Concorrência padrão: 20. |
| Worker de pipeline | O pipeline História → vídeo. Ele vem em todas as edições, mas só roda no Nodaro Cloud e encerra na hora nas outras. |
No Docker, um único script de inicialização inicia todos eles, e o Caddy fica na frente da API. Em uma instalação escalonada, cada um pode rodar no próprio contêiner. Eles só se coordenam pelas filas do BullMQ no Redis e pelos registros de execução no Postgres. Veja Escalonamento.
Como um workflow é executado
Quando um usuário clica em Executar no editor, há dois caminhos:
- No navegador. Durante a edição, o próprio editor executa o grafo e chama um endpoint da API por nó. Você vê cada resultado assim que o nó dele termina.
- No servidor. As execuções disparadas, por um webhook, um agendamento ou a API, as execuções de apps e as execuções explícitas no servidor vão para o orquestrador. Ele salva o progresso no registro da execução, para que qualquer cliente possa acompanhá-lo.
O orquestrador:
- Carrega os nós e as conexões do workflow.
- Ordena o grafo em níveis. Um nível reúne os nós cujas entradas estão todas prontas.
- Executa os nós de cada nível em paralelo, até o paralelismo do próprio usuário e o teto do servidor,
MAX_CONCURRENT_NODES_PER_EXECUTION. - Executa cada nó de uma de três formas:
| Forma | Onde | Exemplos | Por quê |
|---|---|---|---|
| Na fila | Um job para o worker de mídia ou de renderização | Gerar imagem (Generate Image), Gerar vídeo (Generate Video), Texto para fala (Text to Speech), Combinar vídeos (Combine Videos), Renderizar vídeo (Render Video) | Trabalho longo ou chamadas externas, desacoplados do orquestrador para controlar a contrapressão (back-pressure) |
| HTTP direto | Uma chamada interna a uma rota da API | Prompt, Gráficos animados (Motion Graphics), o auxiliar de prompts, os nós de publicação em redes sociais | Chamadas rápidas a modelos de texto, sem o custo extra da fila |
| Inline | Dentro do orquestrador | Combinar texto (Combine Text), Dividir texto (Split Text), Composição de camadas (Composite) | Lógica pura, sem chamadas externas |
- Depois de cada nó, passa a saída dele para os nós que dependem dele e salva o progresso da execução com uma gravação no banco de dados por nó.
Uma execução pode parar de duas formas. Com Interrompido, ela para na hora: os nós que já estão em execução são abandonados, e os créditos já cobrados não são reembolsados. Com Interrompendo, ela termina o nível atual e para antes do seguinte.
Limites. Cada nó pode levar até 90 minutos, e uma execução inteira, até 120 minutos. Um nó que declara o próprio orçamento de tempo, hoje o Aplicar EDL (Apply EDL), dimensionado a partir da edição que ele renderiza, recebe esse orçamento, e o limite da execução cresce na mesma medida. Se o orquestrador reiniciar durante uma execução, um nó com orçamento cujo worker ainda está ativo é retomado, em vez de ser executado duas vezes. Os Sub-workflows são executados de forma recursiva, até 5 níveis de profundidade, com detecção de ciclos.
Armazenamento e banco de dados
- Mídia — toda imagem, todo vídeo e todo arquivo de áudio gerado vai para o armazenamento compatível com S3 e é referenciado pela chave dele. O Nodaro nunca apaga sozinho a mídia armazenada.
- Banco de dados — o Supabase Postgres guarda perfis, projetos, workflows, execuções e o progresso delas, jobs, registros de mídia, transações de créditos, apps OAuth e os tokens deles, tokens de API pessoais e conexões com redes sociais, criptografadas. Todas as tabelas aplicam segurança em nível de linha (row-level security), então o próprio banco de dados restringe cada usuário às próprias linhas.
- Migrações — o esquema fica em
supabase/migrations/, aplicado na ordem dos nomes dos arquivos e só para a frente. - Redis — guarda as filas e pequenos caches compartilhados. O estado dos jobs nele é de curta duração: veja Backup e restauração.
Autenticação
A API aceita três tipos de tokens bearer e os diferencia pelo formato:
| Token | Vem de | Age como |
|---|---|---|
eyJ…, um JWT | Uma sessão de login do Supabase no editor | O usuário logado |
ndr_app_<64 hex> | Um app OAuth que um usuário autorizou | O usuário que autorizou o app, limitado aos escopos concedidos |
ndr_<64 hex> | Um token de API pessoal | O dono do token |
Os processos de uma instalação também se autenticam entre si com o INTERNAL_ORCHESTRATOR_SECRET, comparado em tempo constante. O servidor web remove esse cabeçalho das requisições externas.
Para cada requisição, a API verifica nesta ordem:
- Rotas públicas, como
/v1/openapi.jsone os webhooks de entrada, pulam a autenticação. - O segredo interno, para as chamadas entre os processos.
- Um token de app OAuth, que não pode estar revogado nem expirado.
- Um token de sessão do Supabase. A função do usuário é lida do perfil dele e fica em cache por 5 minutos.
- Qualquer outra coisa responde
401.
Os tokens de API pessoais são verificados pelas rotas que os aceitam, que também aplicam limites de taxa e restringem um token aos workflows dele. Veja Autenticação e Apps OAuth.
As edições no código
Uma única base de código atende as três edições:
- Community (
EDITION=community, o padrão) — self-hosted, sem painel de administração, sem registro de créditos e sem cobrança. Qualquer pessoa que cria uma conta é um usuário comum. - Business (
EDITION=business) — acrescenta o painel de administração e o gerenciamento de usuários, e continua self-hosted e sem cobrança. - Cloud (
EDITION=cloud) — acrescenta créditos, cobrança e preços de crédito definidos por administradores. Ela é a base do app.nodaro.ai e não é feita para self-hosting.
As rotas verificam os recursos da edição, não o nome dela: uma rota de administração só roda em uma edição com painel de administração, e o código de créditos só roda em uma edição com créditos. A verificação vem primeiro na rota, antes de qualquer outra lógica. O app do navegador lê a edição dele na build, a partir de VITE_EDITION. Veja Edições e perfis de superfície.
Status e streaming
O status dos jobs e das execuções é consultado periodicamente, a cada 2 a 5 segundos: ele muda em uma escala de segundos, e a consulta periódica é simples de implantar. A saída em streaming — o texto dos modelos de texto, as execuções de workflows e os pipelines — usa Server-Sent Events. É por isso que um proxy reverso na frente do Nodaro não pode armazenar as respostas em buffer.
Por que estas escolhas
- Fastify — tipos de TypeScript de primeira classe, validação guiada por schemas e plugins que mantêm cada rota no próprio escopo.
- BullMQ — uma fila madura sobre o Redis, com novas tentativas, backoff e controles de concorrência, na mesma stack Node.js.
- REST — escopos OAuth fáceis de definir por rota, um documento OpenAPI gerado e um modelo simples para clientes de terceiros.
- Supabase — Postgres, login, realtime e segurança em nível de linha em um único serviço. A segurança em nível de linha substitui boa parte do código de autorização personalizado.
- React Flow — um canvas comprovado para grafos de nós, que o Nodaro estende bastante.
- Remotion — composições declarativas em React que renderizam no servidor da mesma forma que na prévia do editor.
- Uma única camada de provedores — toda chamada a modelos passa por uma única abstração, então um modelo pode passar para outro provedor sem mudanças no código dos recursos.
Perguntas frequentes
Páginas relacionadas
Escalonamento
Como contribuir
Autenticação
SDK para TypeScript
Edições e perfis de superfície
Última atualização
Solução de problemas
Resolva problemas do Nodaro self-hosted a partir de /setup: sintomas e correções de inicialização, portas, CORS, migrações, armazenamento, filas e chaves.
Como contribuir
Contribua com o Nodaro no GitHub: prepare o ambiente de desenvolvimento, crie a branch a partir de dev, rode os testes, inclua um changeset e assine o CLA.