141 lines
3.1 KiB
Markdown
141 lines
3.1 KiB
Markdown
# 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
|
|
|
|
```text
|
|
n8n -> POST /api/data -> PostgreSQL orders -> dashboard
|
|
```
|
|
|
|
The endpoint accepts a single order item or an array. Requests must include:
|
|
|
|
```text
|
|
x-api-key: <API_KEY>
|
|
Content-Type: application/json
|
|
```
|
|
|
|
### Stock Ingestion
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
docker compose up -d db
|
|
```
|
|
|
|
Start the backend:
|
|
|
|
```bash
|
|
cd backend
|
|
npm install
|
|
npm start
|
|
```
|
|
|
|
Start the frontend:
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
Default local URLs:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
POSTGRES_USER
|
|
POSTGRES_PASSWORD
|
|
POSTGRES_DB
|
|
API_KEY
|
|
N8N_WHATSAPP_TRIGGER_URL
|
|
ADMIN_EMAIL
|
|
ADMIN_PASSWORD
|
|
JWT_SECRET
|
|
TURNSTILE_SECRET
|
|
VITE_TURNSTILE_SITE_KEY
|
|
```
|
|
|
|
`TURNSTILE_SECRET` enables backend CAPTCHA enforcement on `/api/login`.
|
|
Set `VITE_TURNSTILE_SITE_KEY` at frontend build time to show Cloudflare Turnstile
|
|
on the login page.
|
|
|
|
If `TURNSTILE_SECRET` is set but the login page does not show the verification
|
|
widget, rebuild the frontend image with `VITE_TURNSTILE_SITE_KEY` available.
|
|
|
|
## Validation
|
|
|
|
```bash
|
|
npm run lint
|
|
npm run build
|
|
```
|
|
|
|
For backend syntax checks:
|
|
|
|
```bash
|
|
cd backend
|
|
node --check index.js
|
|
node --check services/campaignService.js
|
|
node --check services/stockService.js
|
|
```
|