Files
graphs/CONTEXT.md
Cauê Faleiros 62a0bcfbc9
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 44s
docs: add project context and remove boilerplate
2026-05-27 16:18:10 -03:00

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 pg 8.20.0)
  • Authentication: JWT (jsonwebtoken 9.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 explicit ID_Pedido fields are missing.
  • "Waiting Room" Debounce Pattern: To prevent webhook spam during massive inventory updates, the /api/stock route 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 useMemo hooks 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 (orders table): Tracks cliente_nome, data_pedido, valor_pedido, produto_id, quantidade, valor_unitario, pedido_id, and cliente_fone.
  • Stock Entity (stock table): Tracks produto_id, nome, saldo (absolute current inventory), and delta_estoque. The database treats the ERP's saldo as 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, or celular). 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 localStorage to survive page reloads. The "Hoje" (Today) date preset explicitly extends to 23:59:59.999 to 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.yml triggers on pushes to the main branch.
  • Docker Registry: The pipeline builds the frontend and backend Docker images and pushes them directly to gitea.blyzer.com.br/blyzer/.
  • Production Deployment: Updates are deployed manually via Portainer by pulling the latest image 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 via docker-compose.yml.

7. Environment Setup & Scripts

Running Locally:

  1. Start the database:
    docker compose up -d db
    
  2. Start the Backend (from /backend):
    npm install
    npm start
    
  3. 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). Avoid any where 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 in useMemo to 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 in backend/index.js using IF NOT EXISTS clauses for safe startup execution.
  • API Security: All backend modifications exposing or altering data MUST use the verifyToken middleware for frontend requests or authenticateAPIKey for external n8n webhooks.