feat: add multi-dashboard routing support for n8n
All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m36s

- Refactor `sendToN8n` service to accept dynamic webhook URLs.
- Update `order-status` controller to fan-out payload to both STATUS and GRAPHS webhooks.
- Add new endpoints and controllers for stock and graphs updates (`/stock-update`, `/graphs-update`).
- Maintain backward compatibility with existing `N8N_WEBHOOK_URL` environment variable.
This commit is contained in:
Cauê Faleiros
2026-05-05 11:26:56 -03:00
parent 325099ec94
commit ff2f5aca29
3 changed files with 82 additions and 5 deletions

View File

@@ -110,9 +110,84 @@ export const handleTinyOrderUpdate = async (req: Request, res: Response): Promis
};
console.log('Forwarding formatted payload to n8n...');
await sendToN8n(finalPayload);
// 1. Send to the Status Dashboard
const statusUrl = process.env.N8N_WEBHOOK_STATUS || process.env.N8N_WEBHOOK_URL;
if (statusUrl) {
console.log('-> Sending to Status Workflow...');
// We don't await here so they send in parallel, or we can await them one by one.
// Awaiting sequentially is safer for error handling.
await sendToN8n(finalPayload, statusUrl);
}
// 2. Send a copy to the Graphs Dashboard (it will just use the data it needs, like values and dates)
const graphsUrl = process.env.N8N_WEBHOOK_GRAPHS;
if (graphsUrl) {
console.log('-> Sending copy to Graphs Workflow...');
await sendToN8n(finalPayload, graphsUrl);
}
} catch (error) {
console.error('Error handling Tiny webhook:', error);
}
};
export const handleTinyStockUpdate = async (req: Request, res: Response): Promise<void> => {
try {
const expectedToken = process.env.TINY_WEBHOOK_SECRET;
const providedToken = req.query.token;
if (expectedToken && providedToken !== expectedToken) {
console.warn('Unauthorized webhook attempt on stock. Invalid or missing token.');
res.status(401).json({ error: 'Unauthorized' });
return;
}
res.status(200).send('OK');
const targetUrl = process.env.N8N_WEBHOOK_STOCK;
if (!targetUrl) {
console.warn('N8N_WEBHOOK_STOCK is not defined in environment variables. Skipping forward.');
return;
}
console.log('Received stock webhook from Tiny. Forwarding to n8n...');
let payload = req.body || {};
if (payload && typeof payload.dados === 'string') {
try { payload.dados = JSON.parse(payload.dados); } catch (e) {}
}
await sendToN8n(payload, targetUrl);
} catch (error) {
console.error('Error handling Tiny stock webhook:', error);
}
};
export const handleTinyGraphsUpdate = async (req: Request, res: Response): Promise<void> => {
try {
const expectedToken = process.env.TINY_WEBHOOK_SECRET;
const providedToken = req.query.token;
if (expectedToken && providedToken !== expectedToken) {
console.warn('Unauthorized webhook attempt on graphs. Invalid or missing token.');
res.status(401).json({ error: 'Unauthorized' });
return;
}
res.status(200).send('OK');
const targetUrl = process.env.N8N_WEBHOOK_GRAPHS;
if (!targetUrl) {
console.warn('N8N_WEBHOOK_GRAPHS is not defined in environment variables. Skipping forward.');
return;
}
console.log('Received graphs webhook from Tiny. Forwarding to n8n...');
let payload = req.body || {};
if (payload && typeof payload.dados === 'string') {
try { payload.dados = JSON.parse(payload.dados); } catch (e) {}
}
await sendToN8n(payload, targetUrl);
} catch (error) {
console.error('Error handling Tiny graphs webhook:', error);
}
};

View File

@@ -1,8 +1,10 @@
import { Router } from 'express';
import { handleTinyOrderUpdate } from '../controllers/webhook.controller';
import { handleTinyOrderUpdate, handleTinyStockUpdate, handleTinyGraphsUpdate } from '../controllers/webhook.controller';
const router = Router();
router.post('/tiny/order-status', handleTinyOrderUpdate);
router.post('/tiny/stock-update', handleTinyStockUpdate);
router.post('/tiny/graphs-update', handleTinyGraphsUpdate);
export default router;

View File

@@ -1,7 +1,7 @@
import axios from 'axios';
export const sendToN8n = async (data: any): Promise<void> => {
const n8nWebhookUrl = process.env.N8N_WEBHOOK_URL;
export const sendToN8n = async (data: any, targetWebhookUrl?: string): Promise<void> => {
const n8nWebhookUrl = targetWebhookUrl || process.env.N8N_WEBHOOK_URL;
const n8nAuthToken = process.env.N8N_AUTH_TOKEN;
if (!n8nWebhookUrl) {