Initial commit: Dockerized, Postgres, CI/CD pipeline
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 3m36s

This commit is contained in:
Cauê Faleiros
2026-05-04 14:40:14 -03:00
commit 0e5354f1fe
40 changed files with 6640 additions and 0 deletions

2
backend/.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules
npm-debug.log

7
backend/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3004
CMD ["npm", "start"]

124
backend/index.js Normal file
View File

@@ -0,0 +1,124 @@
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const { Pool } = require('pg');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3004;
const API_KEY = process.env.API_KEY || "nexstar_secret_key_123";
app.use(cors());
app.use(bodyParser.json());
// PostgreSQL Connection Pool
const pool = new Pool({
connectionString: process.env.DATABASE_URL || 'postgres://graphuser:graphpassword@localhost:5432/graphdb',
});
// Initialize Database Table
const initDB = async () => {
try {
await pool.query(`
CREATE TABLE IF NOT EXISTS orders (
id SERIAL PRIMARY KEY,
cliente_nome VARCHAR(255),
data_pedido VARCHAR(50),
valor_pedido NUMERIC(10, 2),
produto_id VARCHAR(100),
produto_descricao TEXT,
quantidade INTEGER,
valor_unitario NUMERIC(10, 5),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`);
console.log("Database initialized successfully.");
} catch (err) {
console.error("Failed to initialize database:", err);
}
};
initDB();
// Middleware for Security
const authenticate = (req, res, next) => {
const apiKey = req.headers['x-api-key'];
if (apiKey === API_KEY) {
next();
} else {
res.status(401).json({ error: 'Unauthorized: Invalid API Key' });
}
};
// Helper to format rows to match the old JSON structure for the frontend
const formatRow = (row) => ({
Nome_Cliente: row.cliente_nome,
Data_Pedido: row.data_pedido,
Valor_Pedido: parseFloat(row.valor_pedido),
ID_Produto: row.produto_id,
Descricao_Produto: row.produto_descricao,
Quantidade: row.quantidade,
Valor_Unitario: parseFloat(row.valor_unitario)
});
// GET data (for the frontend)
app.get('/api/data', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM orders ORDER BY id ASC');
const formattedData = result.rows.map(formatRow);
res.json(formattedData);
} catch (error) {
console.error("Error fetching data:", error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
// POST data (for n8n)
app.post('/api/data', async (req, res) => {
// Respond IMMEDIATELY to prevent slowing down n8n / WhatsApp flows
res.status(201).json({ message: 'Data received, processing in background' });
const newData = req.body;
const payload = Array.isArray(newData) ? newData : [newData];
// Process asynchronously
(async () => {
const client = await pool.connect();
try {
await client.query('BEGIN');
const insertQuery = `
INSERT INTO orders (
cliente_nome, data_pedido, valor_pedido,
produto_id, produto_descricao, quantidade, valor_unitario
) VALUES ($1, $2, $3, $4, $5, $6, $7)
`;
for (const item of payload) {
// Handle potential missing fields gracefully
const values = [
item.Nome_Cliente || 'Unknown',
item.Data_Pedido || '',
item.Valor_Pedido || 0,
item.ID_Produto || '',
item.Descricao_Produto || '',
item.Quantidade || 0,
item.Valor_Unitario || 0
];
await client.query(insertQuery, values);
}
await client.query('COMMIT');
} catch (error) {
await client.query('ROLLBACK');
console.error("Database insert error:", error);
} finally {
client.release();
}
})();
});
app.listen(PORT, '0.0.0.0', () => {
console.log(\`Nexstar Backend running at http://localhost:\${PORT}\`);
console.log(\`Endpoint for n8n: POST http://localhost:\${PORT}/api/data\`);
});

1057
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

22
backend/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"body-parser": "^2.2.2",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"express": "^5.2.1",
"fs-extra": "^11.3.4",
"pg": "^8.20.0"
}
}