6.9 KiB
6.9 KiB
Context
1. Project Overview
This project (often referred to as "Nexstar Graphs" or simply "Graphs") is a real-time sales and inventory dashboard. Its primary purpose is to ingest live webhook payloads from an external ERP (Tiny ERP) via n8n, securely store that data, and provide a visually rich, responsive dashboard for business analytics. It tracks total sales, product performance, customer behavior, and live inventory levels, while also providing tools for WhatsApp marketing campaigns.
2. Tech Stack & Tooling
Frontend:
- Library: React 19.2.5
- Language: TypeScript 6.0.2
- Build Tool: Vite 8.0.10
- Styling: Tailwind CSS 4.2.4
- Icons: Lucide React 1.14.0
- Charts: Recharts 3.8.1
- Routing: React Router DOM 7.14.2
Backend:
- Environment: Node.js
- Framework: Express 5.2.1
- Database: PostgreSQL (via
pg8.20.0) - Authentication: JWT (
jsonwebtoken9.0.3) - CORS & Middleware:
cors,body-parser
Infrastructure & CI/CD:
- Containerization: Docker & Docker Compose
- Proxy: Nginx
- CI/CD: Gitea Actions (deploy.yml)
- Automation: n8n (External trigger source)
3. Architecture & Design Decisions
- Decoupled Client-Server: The frontend is a statically built SPA served by Nginx, communicating with an isolated Node.js API.
- Idempotent Database Operations: Due to potential retry/spam from n8n webhooks, database insertions strictly use
INSERT ... ON CONFLICT DO UPDATE SET(UPSERTs). The backend dynamically generates fallback IDs using composite keys (Name_Date_Value) to prevent historical data squashing when explicitID_Pedidofields are missing. - "Waiting Room" Debounce Pattern: To prevent webhook spam during massive inventory updates, the
/api/stockroute intercepts payloads with large deltas (>= 100). It parks them in an in-memory dictionary grouped by Base Product Name, accumulates the numbers over a 30-minute setTimeout, and then executes a single aggregated webhook to N8N targeting the Top 100 buyers. - Smart Polling vs. SSE: Real-time UI updates are handled via client-side polling (
setInterval) rather than Server-Sent Events (SSE) to bypass persistent connection drops caused by production reverse proxies. - Client-Side Analytics: The backend returns raw data arrays; sorting, mapping, deduplication (e.g., grouping unique orders by time), and chart metric generation are processed dynamically in the React
useMemohooks to reduce server load.
4. Directory Structure
/
├── .gitea/workflows/ # CI/CD pipeline definitions
├── backend/ # Node.js Express API
│ ├── Dockerfile # Backend container definition
│ ├── index.js # Core API logic, DB initialization, and Webhook handlers
│ └── package.json
├── public/ # Static assets (Favicons)
├── src/ # React Frontend Application
│ ├── components/ # Reusable UI elements (Layout, DateRangePicker)
│ ├── pages/ # Route-level views (Dashboard, Products, Clients)
│ ├── dataService.ts # Centralized API fetch logic and JWT handling
│ ├── types.ts # Shared TypeScript interfaces
│ └── main.tsx # React entry point
├── docker-compose.yml # Local orchestration and environment variable mapping
├── nginx.conf # Production web server routing
└── vite.config.ts # Frontend build configuration
5. Core Business Rules & Domain Entities
- Order Entity (
orderstable): Trackscliente_nome,data_pedido,valor_pedido,produto_id,quantidade,valor_unitario,pedido_id, andcliente_fone. - Stock Entity (
stocktable): Tracksproduto_id,nome,saldo(absolute current inventory), anddelta_estoque. The database treats the ERP'ssaldoas the Absolute Truth (overwriting existing values rather than performing math) to prevent desynchronization. - WhatsApp Marketing Integration: The system actively extracts phone numbers from incoming n8n payloads (checking
Fone_Cliente,fone, orcelular). Numbers are exposed in the UI for direct "Click-to-Chat" links and exported to CSV files for bulk marketing. - Filter Persistence: User preferences for Date Ranges, Sort options, and Auto-Refresh intervals are rigidly persisted to
localStorageto survive page reloads. The "Hoje" (Today) date preset explicitly extends to23:59:59.999to ensure incoming real-time webhooks remain visible on the current day's graph.
6. CI/CD & Deployment
- Gitea Actions: A workflow located in
.gitea/workflows/deploy.ymltriggers on pushes to themainbranch. - Docker Registry: The pipeline builds the
frontendandbackendDocker images and pushes them directly togitea.blyzer.com.br/blyzer/. - Production Deployment: Updates are deployed manually via Portainer by pulling the
latestimage tags from the Gitea registry and redeploying the stack. - Environment Variables: Security secrets (
API_KEY,JWT_SECRET,POSTGRES_PASSWORD,N8N_WHATSAPP_TRIGGER_URL) are injected via the Portainer stack configuration and passed into containers viadocker-compose.yml.
7. Environment Setup & Scripts
Running Locally:
- Start the database:
docker compose up -d db - Start the Backend (from
/backend):npm install npm start - Start the Frontend (from project root):
npm install npm run dev # For HMR development npm run preview # For production build testing
Building the Frontend:
npm run build
8. Coding Standards & AI Directives
- Strict Type Safety: Use explicit TypeScript interfaces (defined in
types.ts). Avoidanywhere possible. Do not bypass type checks with// @ts-ignore. - Idiomatic React: Use functional components and hooks (
useState,useEffect,useMemo). Complex data transformations (like merging arrays into chart-ready datasets) MUST be wrapped inuseMemoto prevent unnecessary re-renders. - Tailwind Architecture: All styling must be handled via Tailwind CSS utility classes. Avoid custom CSS files unless defining global font families or root variables in
index.css. - Robust Data Handling: Always implement graceful fallbacks for missing data. Never assume an API payload will contain all keys. (e.g.,
item.id || item.ID_Pedido || ''). - Database Migrations: There is no ORM (like Prisma or Sequelize). Table schemas and indexes are managed via raw SQL statements inside the
initDB()function inbackend/index.jsusingIF NOT EXISTSclauses for safe startup execution. - API Security: All backend modifications exposing or altering data MUST use the
verifyTokenmiddleware for frontend requests orauthenticateAPIKeyfor external n8n webhooks.