Estou construindo uma plancia (dashboard) de análise interna para uma PME para comparar o desempenho de vendas em dois períodos diferentes (comparação Ano a Ano / Período a Período) - selecionando 1 cliente ou para visualizar análises dos artigos.
Meu Stack Atual e Arquitetura de Workflow:
Frontend: Uma página HTML simples baseada em navegador gerada e servida via n8n Webhook Node (usando Bootstrap, inputs HTML5 para Date 1 Inizio/Fine, Date 2 Inizio/Fine, filtros de texto para Clients/Zones, e um dropdown para alternar entre 4 ou 5 visualizações estatísticas diferentes como Brand, Client, Geographical Zone, e Category).
Database:Supabase (PostgreSQL) armazenando uma tabela principal de vendas (test1) com aproximadamente 80.000 linhas de registros de vendas limpos de 2025 e 2026.
Backend / Lógica: Quando um usuário clica em “Elabora Statistica”, JavaScript envia uma requisição GET de volta para o webhook n8n com os parâmetros de consulta. n8n busca os dados do Supabase usando o Supabase Node (Get many rows) e os passa para um Code Node (JavaScript) para agregar valores, inverter sinais para notas de crédito (Note di Credito), formatar métricas e gerar a tabela HTML dinâmica final.
Os Pontos de Dor e Problemas Encontrados:
1. Limites de Memória e Bad Gateway (Erro 502): Ao executar a consulta com “Return All” ativado no nó Supabase para extrair o conjunto de dados completo para processamento dentro do n8n, o n8n Cloud fica sem RAM e falha com um 502 Bad Gateway. 80.000 linhas são simplesmente muito pesadas para serem processadas sincronamente na memória dentro de um loop de execução de workflow n8n.
2. O Dilema do “Limit”: Se desativar “Return All” e definir um Limit (por exemplo, 3.000 linhas) no nível do nó Supabase, ele fatiará as primeiras 3.000 linhas antes de aplicar a lógica de cliente/data, levando a cálculos matemáticos completamente incompletos e errados.
3. Bugs de Sincronia de Texto e Layout: Ao passar parâmetros SQL complexos ou arrays de lógica dinamicamente através de formulários de expressão n8n padrão (como tentar filtrar parâmetros LIKE dinamicamente com base em campos de texto opcionais do frontend), o mecanismo de banco de dados ocasionalmente rejeita as árvores de lógica do parser (PGRST100 unexpected '2' expecting isVal...).
4. Página Travando no Fetch: Ao passar parâmetros de um lado para o outro de forma assíncrona, o spinner do frontend frequentemente trava indefinidamente, sugerindo que respostas síncronas em fluxos de execução pesada não estão escalando.
Estratégia de Mitigação Atual:
Para resolver isso, movemos todo o trabalho pesado completamente para o Supabase. Em vez de chamar a tabela bruta, criamos uma View PostgreSQL (CREATE OR REPLACE VIEW vista_statistiche_aziendali) que agrega, corta e limpa dados por Dia, Brand, Zone, Category, e Client diretamente no nível do banco de dados.
Isso comprimiu com sucesso o conjunto de dados, permitindo que o n8n tratasse com segurança o payload sem gerar erros 502.
Minhas Perguntas para a Comunidade:
Esta é a arquitetura recomendada? Servir um Dashboard BI/Analytics HTML interativo através de um Webhook n8n e depender de Code nodes para alternar visualizações é escalável para operações comerciais, ou devemos considerar desacoplar completamente o frontend (por exemplo, Retool, Budibase, ou um aplicativo Next.js leve falando diretamente com Supabase)?
Como vocês lidam com relatórios pesados no n8n? Se um usuário precisar de uma análise granular profunda (por exemplo, observar um cliente específico até os exatos códigos SKU/item ao longo de 2 anos), qual é a melhor prática para fazer lotes/paginação de linhas dinamicamente em um fluxo n8n sem enfrentar timeouts de gateway?
Otimizando Respostas de Webhook: Qual é a forma mais segura de evitar travamento/congelamento da UI do frontend durante requisições de alta concorrência ou grandes operações dentro de loops n8n?
Aguardo seu conselho, dicas arquiteturais ou exemplos de como vocês resolveram dashboards de relatórios semelhantes!
@Dedi_srl todos os quatro problemas vêm de uma coisa só: você está puxando 80 mil linhas para o n8n e agregando no nó Code, isso causa o RAM/502, e é por isso que um Limit quebra a matemática (ele faz slice antes de você agregar). faça a agregação no banco de dados, retorne apenas as linhas resumidas.
conecte o nó Postgres ao Supabase (Host/Db/User/Port do Supabase → Project Settings → Database) e execute uma query parametrizada, períodos como parâmetros:
SELECT brand,
SUM(amount) FILTER (WHERE sale_date BETWEEN $1 AND $2) AS period1,
SUM(amount) FILTER (WHERE sale_date BETWEEN $3 AND $4) AS period2
FROM test1
WHERE ($5 = '' OR client ILIKE '%' || $5 || '%')
GROUP BY brand;
isso retorna algumas centenas de linhas, então nada pesado fica na memória, a matemática fica correta (o agrupamento roda sobre a tabela inteira), e PGRST100 desaparece porque os filtros agora são SQL puro, não o parser do PostgREST. o nó Code só formata aquilo em html.
Sua abordagem atual de mover a camada de agregação para o Supabase é exatamente a direção que eu tomaria. n8n é excelente para orquestração e automação, mas não foi projetado para atuar como um mecanismo de análise de alto volume processando dezenas de milhares de linhas na memória.
Tenho experiência construindo sistemas n8n escaláveis com Supabase, APIs, webhooks e fluxos de trabalho com inteligência artificial. Para projetos de relatórios, geralmente coloco filtragem pesada, agregação e paginação na camada de banco de dados e uso n8n principalmente como a camada de orquestração. Isso ajuda a evitar gargalos de memória, tempos limite de gateway e problemas de desempenho.
Posso ajudar a otimizar sua arquitetura atual, melhorar o desempenho das consultas, implementar estratégias eficientes de paginação para relatórios com busca profunda, e recomendar a melhor abordagem de frontend com base em seus objetivos de escalabilidade.
Ficarei feliz em discutir sua implementação atual e sugerir melhorias práticas.
Sua arquitetura atual é “de nível prototipagem”. É frágil porque depende de um ciclo de requisição-resposta síncrono em que o n8n precisa manter todo o estado da requisição, a busca de dados, o processamento lógico e a renderização de HTML na RAM.
Migre para um Low-Code Frontend (Retool, Budibase ou Appsmith). Essas ferramentas foram projetadas especificamente para esse caso de uso. Conectam-se diretamente ao Supabase (PostgreSQL), tratam a paginação nativamente e permitem que você escreva consultas SQL que executam no lado do banco de dados, retornando apenas o resultado final à UI. Você ainda pode usar o n8n para o “trabalho pesado” (por exemplo, enviar um relatório PDF semanal desses dados por e-mail), mas não para a UI interativa.
Use Supabase RPC (Remote Procedure Calls) Em vez de uma View ou um nó “Get Many Rows”, crie uma PostgreSQL Function no Supabase.
CREATE OR REPLACE FUNCTION get_sales_stats(
start_date_1 DATE, end_date_1 DATE,
start_date_2 DATE, end_date_2 DATE,
client_filter TEXT DEFAULT NULL
)
RETURNS TABLE (category TEXT, total_sales NUMERIC, diff_percent NUMERIC) AS $$
BEGIN
RETURN QUERY
-- Sua lógica de agregação complexa aqui usando os parâmetros
-- Isso acontece inteiramente dentro do mecanismo do banco de dados
END;
$$ LANGUAGE plpgsql;
Como isso resolve seu problema:
Sem Travamentos de Memória: O n8n recebe apenas o resultado agregado final (por exemplo, 20 linhas de categorias) em vez de 80.000 registros brutos.
Filtragem Dinâmica: Você passa as datas e nomes de clientes como argumentos para a função. Sem mais erros de parser PGRST100 porque você não está construindo strings complexas nas expressões do n8n; está chamando uma função com parâmetros.
Dados Granulares: Para detalhamentos em nível de SKU, você pode adicionar parâmetros LIMIT e OFFSET à sua função RPC para implementar paginação verdadeira no lado do servidor.
2 sugestões:
Estratégia A: O Padrão Assíncrono (A Abordagem “Job”) Se você precisa ficar com o n8n, pare de tentar retornar o HTML na mesma requisição.
Processamento: O n8n continua o workflow em background, calcula as estatísticas e escreve o resultado em uma tabela report_results no Supabase.
Verificação: O spinner do frontend permanece ativo e faz ping em um segundo webhook “Check Status” a cada 2 segundos. Assim que o status for “concluído”, o frontend busca os dados finais.
Estratégia B: Acesso Direto ao Supabase Se você usar uma ferramenta como Retool ou um app Next.js, o frontend se comunica com o Supabase via API. O Supabase lida com a concorrência e o connection pooling, o que é várias ordens de magnitude mais eficiente do que o manipulador de webhook do n8n.
n8n é uma boa opção para o segundo. Não é um bom lugar para manter uma requisição de análise interativa aberta enquanto puxa linhas, agrega-as e renderiza HTML.
Para a parte interativa, o teste de prova é simples:
nenhum nó Code do n8n deve receber 80 mil linhas brutas;
Supabase/Postgres deve retornar linhas já agregadas;
o navegador deve receber uma resposta pequena, idealmente centenas de linhas no máximo;
n8n deve apenas orquestrar ou chamar uma consulta armazenada/RPC se você mantê-la no caminho.
A arquitetura que eu testaria primeiro:
Função ou view do Postgres para cada tipo de relatório;
parâmetros: period_1_start, period_1_end, period_2_start, period_2_end, filtros de cliente/categoria;
SQL faz o agrupamento e comparação de períodos;
frontend chama um endpoint leve que retorna apenas o resultado agrupado;
n8n lida com exportações agendadas, alertas ou entrega de email/PDF fora do caminho da requisição interativa.
Isso te dá uma regra clara:
Se o usuário está esperando no navegador, mantenha a requisição pequena e no formato do banco de dados.
Se o trabalho é pesado, torne-o assíncrono ou agendado e deixe n8n ser o dono daquele fluxo de trabalho.