Como conectar workflows no seu SaaS em minutos
Se você é CTO ou Tech Lead de um SaaS B2B, provavelmente já viveu este cenário:
O Product Manager chega com uma "funcionalidade simples": “Precisamos permitir que o usuário crie uma regra onde, se um ticket chegar fora do horário comercial, ele seja atribuído a um atendente de plantão e envie um SMS.”
Sua mente de engenheiro já começa a calcular o débito técnico. Não é apenas uma regra if/else. Você precisa de uma interface drag-and-drop, gestão de retentativas, logs de execução, validação de segurança e escalabilidade para milhares de tenants.
O que parecia uma sprint de 3 dias vira um roadmap de 3 meses construindo infraestrutura, e não core business.
Aqui no Triglit, nós nascemos justamente para eliminar esse "trabalho de encanador". Hoje, quero mostrar na prática — código na tela — como você pode integrar uma engine de workflows completa no seu SaaS usando Next.js em menos de uma hora.
Vamos construir um caso de uso real: um sistema de distribuição de atendentes e envio de mensagens.
O que vamos construir
Neste tutorial, vamos integrar o Triglit em uma aplicação Next.js 14+ (App Router).
-
Frontend: Usaremos o
@triglit/react-sdkpara dar ao seu usuário final uma interface visual de workflows. -
Backend: Usaremos o SDK TypeScript para criar Custom Nodes (nós personalizados) que executam a lógica de negócio do seu SaaS.
Passo 1: Preparando o terreno
Primeiro, vamos instalar os pacotes necessários no seu projeto. A beleza aqui é que o overhead é mínimo.
pnpm add triglit @triglit/react-sdk
Configure suas variáveis de ambiente no .env. Você vai precisar das chaves de API do painel do Triglit.
# .env.local
TRIGLIT_SECRET_KEY=sk_live_xxx # Sua chave secreta (Backend)
TRIGLIT_PUBLIC_KEY=pk_live_xxx # Chave pública (Frontend)
TRIGLIT_CNP_SECRET=cnp_secret_xxx # Secret para validar que a requisição vem do Triglit
NEXT_PUBLIC_TRIGLIT_PUBLIC_KEY=pk_live_xxx
Passo 2: A Lógica de Negócio (Seu "Molho Secreto")
O maior erro das ferramentas de automação antigas é tentar substituir sua lógica de negócio. O Triglit faz o oposto: nós orquestramos, você executa.
Vamos criar um serviço (lib/triglit-service.ts) que simula duas ações do seu SaaS: enviar uma mensagem e escolher um agente para atendimento.
// lib/triglit-service.ts
export class TriglitService {
/**
* Envia mensagem para um usuário final (simulação)
*/
async sendMessage(
tenantId: string,
entityId: string,
content: string
): Promise<void> {
console.log(`[Tenant: ${tenantId}] Enviando mensagem para ${entityId}:`, content);
// Aqui entraria sua chamada real para Twilio, WhatsApp, etc.
}
/**
* Distribui um agente disponível para atendimento
*/
async distributeAgent(
tenantId: string,
entityId: string,
agentIds: string[],
fallbackAgentId?: string
): Promise<{ selectedAgentId: string; wasFallbackSelected: boolean }> {
// Lógica real: buscar no seu DB quem está online, quem tem menos tickets, etc.
const availableAgents = agentIds;
if (availableAgents.length > 0) {
// Exemplo simples: pega o primeiro. Poderia ser Round-Robin.
const selectedAgentId = availableAgents[0];
return {
selectedAgentId,
wasFallbackSelected: false,
};
}
if (fallbackAgentId) {
return {
selectedAgentId: fallbackAgentId,
wasFallbackSelected: true,
};
}
throw new Error("Nenhum agente disponível");
}
}
export const triglitService = new TriglitService();
Passo 3: Criando os "Custom Nodes"
Agora, a mágica acontece. Vamos expor essas funções para o motor de workflows do Triglit através de uma API Route do Next.js.
É aqui que garantimos a segurança. O Triglit assina cada requisição, garantindo que ninguém externo possa acionar suas funções de automação indevidamente.
Crie o arquivo app/api/triglit/route.ts:
// app/api/triglit/route.ts
import { NextRequest, NextResponse } from "next/server";
import Triglit from "triglit"; // Assumindo cliente inicializado em lib/triglit-client
import { triglitService } from "@/lib/triglit-service";
// Inicialize o cliente (idealmente em lib/triglit-client.ts)
const triglitClient = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
export async function POST(req: NextRequest) {
try {
// 1. Segurança: Validação da assinatura Triglit
const signature = req.headers.get("x-triglit-signature");
if (!signature) {
return NextResponse.json({ error: "Assinatura ausente" }, { status: 400 });
}
const rawBody = await req.text();
const secret = process.env.TRIGLIT_CNP_SECRET!;
const isValid = await triglitClient.customNodes.validateCNPSignature(
rawBody,
signature,
secret
);
if (!isValid) {
return NextResponse.json({ error: "Assinatura inválida" }, { status: 401 });
}
// 2. Processamento do Payload
const body = JSON.parse(rawBody);
// Heartbeat: O Triglit "pinga" sua URL para saber se ela está viva
if (body.type === "heartbeat") {
return NextResponse.json({ status: "ok" });
}
const { subTenantId: tenantId, entityId, nodeType, config } = body.payload;
// 3. Roteamento da Execução
switch (nodeType) {
case "send-message": {
await triglitService.sendMessage(tenantId, entityId, config.content);
return NextResponse.json({ status: "completed", outputs: {} });
}
case "distribute-agent": {
const result = await triglitService.distributeAgent(
tenantId,
entityId,
config.agents,
config.fallbackAgent
);
return NextResponse.json({
status: "completed",
outputs: {
selectedAgentId: result.selectedAgentId,
wasFallbackSelected: result.wasFallbackSelected,
},
});
}
default:
return NextResponse.json({ status: "failed", error: "Node desconhecido" });
}
} catch (error) {
console.error("Erro no Custom Node:", error);
return NextResponse.json({ status: "failed", error: "Erro interno" }, { status: 500 });
}
}
Passo 4: Entregando a interface para o usuário
Até agora fizemos o backend. Mas o valor percebido pelo seu cliente está na capacidade de ele mesmo montar o fluxo.
Com o @triglit/react-sdk, você embarca o editor visual diretamente na sua página Next.js. Diferente de soluções anteriores, você deve envolver o editor no TriglitProvider e garantir a importação dos estilos.
// app/workflows/page.tsx
"use client";
import { TriglitProvider, WorkflowEditor } from "@triglit/react-sdk";
import "@triglit/react-sdk/styles.css";
export default function WorkflowsPage() {
return (
<div className="container mx-auto p-6 h-screen flex flex-col">
<h1 className="text-2xl font-bold mb-6 text-slate-800">
Automações de Atendimento
</h1>
<div className="flex-1 border rounded-lg overflow-hidden shadow-sm">
<TriglitProvider
config={{
apiKey: process.env.NEXT_PUBLIC_TRIGLIT_PUBLIC_KEY!,
}}
>
<WorkflowEditor
workflowId="wf_exemplo_123" // ID do workflow a ser editado
onSave={(versionId) => {
console.log("Nova versão salva:", versionId);
}}
className="h-full"
/>
</TriglitProvider>
</div>
</div>
);
}
O Resultado Final
Em menos de 200 linhas de código, você implementou:
-
Orquestração de Eventos: O Triglit cuida do "quando" executar.
-
UI No-Code: Seu usuário ganha um builder visual profissional.
-
Segurança Enterprise: Validação de assinaturas e isolamento de tenants.
-
Extensibilidade: Se amanhã você precisar de um bloco "Gerar Nota Fiscal", basta adicionar um novo
casena API e um objeto no frontend.
Por que isso muda o jogo para SaaS?
Construir isso do zero ("in-house") exigiria lidar com filas (RabbitMQ/Kafka/SQS), gestão de estado de execução, retentativas exponenciais e construção de UI complexa (React Flow/D3).
Com a abordagem de Automação Embarcada do Triglit, você foca na regra de negócio (distributeAgent), e nós garantimos que ela rode na hora certa, na ordem certa, para o cliente certo.
Quer ver isso rodando no seu produto? A documentação completa está disponível em docs.triglit.com. Se você está construindo um SaaS e quer pular os meses de desenvolvimento de infraestrutura, peça acesso ao trial.
Estamos construindo a camada de automação para que você possa focar no seu produto. 🚀
