Nexstar Graphs
Real-time sales and stock dashboard for Nexstar. The app receives Tiny ERP data through n8n webhooks, stores it in PostgreSQL, and renders sales, products, clients, stock, and WhatsApp campaign data in a React dashboard.
Stack
- Frontend: React, TypeScript, Vite, Tailwind CSS, Recharts
- Backend: Node.js, Express, PostgreSQL, JWT, API-key webhook auth
- Runtime: Docker Compose, Nginx, n8n
Main Flows
Sales Ingestion
n8n -> POST /api/data -> PostgreSQL orders -> dashboard
The endpoint accepts a single order item or an array. Requests must include:
x-api-key: <API_KEY>
Content-Type: application/json
Stock Ingestion
n8n -> POST /api/stock -> PostgreSQL stock + campaign queue
Positive stock deltas are queued for WhatsApp campaigns. The scheduled processor groups pending queue rows by base product name and sends a campaign only when the accumulated pending delta reaches at least 100.
Scheduled WhatsApp Campaigns
n8n schedule at 12:00/18:00 BRT
-> POST /api/internal/process-stock-campaigns
-> backend calls N8N_WHATSAPP_TRIGGER_URL
-> n8n WhatsApp workflow sends templates
The scheduled endpoint is API-key protected and returns a summary:
{
"claimed": 0,
"sentGroups": 0,
"skippedGroups": 0,
"failedGroups": 0,
"pendingBelowThresholdGroups": 0
}
Cutting Workbook Import
Manual cutting/replenishment workbooks can be normalized into JSON before they are persisted or shown in the app:
python3 backend/scripts/normalize_cut_workbook.py "/path/to/NECESSIDADE DE CORTE.xlsx" --pretty -o /tmp/necessidade_corte_normalized.json
The output includes purchase need rows, production orders, finished stock,
stock plus OP availability, real purchase need, outside items, and cut-plan
sections by family (BLCS, BLMC, BLOS, BLPM). The importer reads cached
workbook values and reports broken formula references instead of making the app
depend on Excel formulas at runtime.
Local Development
Start PostgreSQL:
docker compose up -d db
Start the backend:
cd backend
npm install
npm start
Start the frontend:
npm install
npm run dev
Default local URLs:
Frontend: http://127.0.0.1:3002
Backend: http://127.0.0.1:3004
Vite may choose a different frontend port if 3002 is already in use.
Environment
Copy .env.example and configure production secrets in the runtime environment:
POSTGRES_USER
POSTGRES_PASSWORD
POSTGRES_DB
API_KEY
N8N_WHATSAPP_TRIGGER_URL
ADMIN_EMAIL
ADMIN_PASSWORD
JWT_SECRET
TURNSTILE_SITE_KEY
TURNSTILE_SECRET
TURNSTILE_SECRET enables backend CAPTCHA enforcement on /api/login. Set
TURNSTILE_SITE_KEY with Cloudflare's public site key so the login page can load
the verification widget at runtime.
The backend also accepts VITE_TURNSTILE_SITE_KEY as a site-key alias and
TURNSTILE_SECRET_KEY as a secret alias for older deployments.
Validation
npm run lint
npm run build
For backend syntax checks:
cd backend
node --check index.js
node --check services/campaignService.js
node --check services/stockService.js