From 62a0bcfbc9589ce7ecd69abe7341ad7e27e2dee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Wed, 27 May 2026 16:18:10 -0300 Subject: [PATCH] docs: add project context and remove boilerplate --- .env.example | 1 + CONTEXT.md | 99 +++++++++++++++++++++++ README.md | 169 ++++++++++++++++++++++++--------------- fake-data.cjs | 33 -------- fake-data.js | 42 ---------- src/App.css | 184 ------------------------------------------- src/assets/hero.png | Bin 13057 -> 0 bytes src/assets/react.svg | 1 - src/assets/vite.svg | 1 - src/data.json | 146 ---------------------------------- test-fetch.js | 15 ---- test-payload.json | 32 -------- 12 files changed, 206 insertions(+), 517 deletions(-) create mode 100644 CONTEXT.md delete mode 100644 fake-data.cjs delete mode 100644 fake-data.js delete mode 100644 src/App.css delete mode 100644 src/assets/hero.png delete mode 100644 src/assets/react.svg delete mode 100644 src/assets/vite.svg delete mode 100644 src/data.json delete mode 100644 test-fetch.js delete mode 100644 test-payload.json diff --git a/.env.example b/.env.example index cf254c8..3953dc1 100644 --- a/.env.example +++ b/.env.example @@ -13,6 +13,7 @@ POSTGRES_DB=graphdb # --- Application Security --- # The API key used by n8n to authenticate with the backend API_KEY=nexstar_secret_key_123 +N8N_WHATSAPP_TRIGGER_URL=https://n8n.example.com/webhook/whatsapp-stock # --- Dashboard Login Credentials --- ADMIN_EMAIL=admin@admin.com diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..d503712 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,99 @@ +# 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 +```text +/ +├── .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: + ```bash + docker compose up -d db + ``` +2. Start the Backend (from `/backend`): + ```bash + npm install + npm start + ``` +3. Start the Frontend (from project root): + ```bash + npm install + npm run dev # For HMR development + npm run preview # For production build testing + ``` + +**Building the Frontend:** +```bash +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. \ No newline at end of file diff --git a/README.md b/README.md index 7dbf7eb..b7b533d 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,116 @@ -# React + TypeScript + Vite +# Nexstar Graphs -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +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. -Currently, two official plugins are available: +## Stack -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) +- Frontend: React, TypeScript, Vite, Tailwind CSS, Recharts +- Backend: Node.js, Express, PostgreSQL, JWT, API-key webhook auth +- Runtime: Docker Compose, Nginx, n8n -## React Compiler +## Main Flows -The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). +### Sales Ingestion -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: - -```js -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - - // Remove tseslint.configs.recommended and replace with this - tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - tseslint.configs.stylisticTypeChecked, - - // Other configs... - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]) +```text +n8n -> POST /api/data -> PostgreSQL orders -> dashboard ``` -You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: +The endpoint accepts a single order item or an array. Requests must include: -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' - -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - // Enable lint rules for React - reactX.configs['recommended-typescript'], - // Enable lint rules for React DOM - reactDom.configs.recommended, - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]) +```text +x-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 +} +``` + +## 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:3001 +Backend: http://127.0.0.1:3004 +``` + +Vite may choose a different frontend port if `3001` 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 +``` + +## 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 ``` diff --git a/fake-data.cjs b/fake-data.cjs deleted file mode 100644 index f729e16..0000000 --- a/fake-data.cjs +++ /dev/null @@ -1,33 +0,0 @@ -const products = []; - -// Group 1: High Quantity, Low Price (Top 10 in Bar Chart, won't show in Pie Chart) -for (let i = 0; i < 10; i++) { - products.push({ - Nome_Cliente: "Fake Client A" + i, - Data_Pedido: "06-05-2026", - Valor_Pedido: 100, - ID_Produto: "QA" + i, - Descricao_Produto: "Produto Muito Vendido " + i, - Quantidade: 1000 + i, // High sales - Valor_Unitario: 0.10 // Low revenue - }); -} - -// Group 2: Low Quantity, High Price (Top 10 in Pie Chart, won't show in Bar Chart) -for (let i = 0; i < 10; i++) { - products.push({ - Nome_Cliente: "Fake Client B" + i, - Data_Pedido: "06-05-2026", - Valor_Pedido: 10000, - ID_Produto: "QB" + i, - Descricao_Produto: "Produto Muito Caro " + i, - Quantidade: 1, // Low sales - Valor_Unitario: 10000 + i // High revenue - }); -} - -fetch('http://localhost:3004/api/data', { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'x-api-key': 'nexstar_secret_key_123' }, - body: JSON.stringify(products) -}).then(res => console.log("Status:", res.status)).catch(console.error); \ No newline at end of file diff --git a/fake-data.js b/fake-data.js deleted file mode 100644 index 642c0a6..0000000 --- a/fake-data.js +++ /dev/null @@ -1,42 +0,0 @@ -// Clear previous data for a clean slate -const { Pool } = require('pg'); -const pool = new Pool({ connectionString: 'postgres://graphuser:graphpassword@localhost:5432/graphdb' }); - -async function run() { - await pool.query('TRUNCATE TABLE orders RESTART IDENTITY;'); - - // Group 1: High Quantity, Low Price (Top 10 in Bar Chart, won't show in Pie Chart) - const group1 = Array.from({length: 10}, (_, i) => ({ - Nome_Cliente: "Fake Client A" + i, - Data_Pedido: "06-05-2026", - Valor_Pedido: 100, - ID_Produto: "QA" + i, - Descricao_Produto: "Produto Muito Vendido " + i, - Quantidade: 1000 + i, // High sales - Valor_Unitario: 0.10 // Low revenue - })); - - // Group 2: Low Quantity, High Price (Top 10 in Pie Chart, won't show in Bar Chart) - const group2 = Array.from({length: 10}, (_, i) => ({ - Nome_Cliente: "Fake Client B" + i, - Data_Pedido: "06-05-2026", - Valor_Pedido: 10000, - ID_Produto: "QB" + i, - Descricao_Produto: "Produto Muito Caro " + i, - Quantidade: 1, // Low sales - Valor_Unitario: 10000 + i // High revenue - })); - - const products = [...group1, ...group2]; - - const res = await fetch('http://localhost:3004/api/data', { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'x-api-key': 'nexstar_secret_key_123' }, - body: JSON.stringify(products) - }); - - console.log(res.status); - process.exit(0); -} - -run(); diff --git a/src/App.css b/src/App.css deleted file mode 100644 index f90339d..0000000 --- a/src/App.css +++ /dev/null @@ -1,184 +0,0 @@ -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; - color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; - - &:hover { - border-color: var(--accent-border); - } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - } -} - -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); - } -} - -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } -} - -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { - position: relative; - width: 100%; - - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; - } - - &::before { - left: 0; - border-left-color: var(--border); - } - &::after { - right: 0; - border-right-color: var(--border); - } -} diff --git a/src/assets/hero.png b/src/assets/hero.png deleted file mode 100644 index 02251f4b956c55af2d76fd0788124d7eee2b45eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13057 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 P00000NkvXXu0mjft=yBf diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/vite.svg b/src/assets/vite.svg deleted file mode 100644 index 5101b67..0000000 --- a/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/src/data.json b/src/data.json deleted file mode 100644 index 9d9f4d6..0000000 --- a/src/data.json +++ /dev/null @@ -1,146 +0,0 @@ -[ - { - "Nome_Cliente": "Luiz Felipe Oliveira Silva", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 19.9, - "ID_Produto": "951438842", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (1 METRO)", - "Quantidade": 1, - "Valor_Unitario": 19.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 69.65, - "ID_Produto": "951438842", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (1 METRO)", - "Quantidade": 3, - "Valor_Unitario": 19.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 69.65, - "ID_Produto": "978770094", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X0,50 (50 CENTÍMETROS)", - "Quantidade": 1, - "Valor_Unitario": 9.95 - }, - { - "Nome_Cliente": "Guilherme de Souza", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 65.66, - "ID_Produto": "951438842", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (1 METRO)", - "Quantidade": 3, - "Valor_Unitario": 20.51889 - }, - { - "Nome_Cliente": "Guilherme de Souza", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 65.66, - "ID_Produto": "978776637", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X0,20 (20 CENTÍMETROS)", - "Quantidade": 1, - "Valor_Unitario": 4.103778 - }, - { - "Nome_Cliente": "Guilherme de Souza", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 24.54, - "ID_Produto": "919483299", - "Descricao_Produto": "BASE LISA CAMISETA COR PRETO TAMANHO - P", - "Quantidade": 1, - "Valor_Unitario": 12.27009 - }, - { - "Nome_Cliente": "Guilherme de Souza", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 24.54, - "ID_Produto": "919483307", - "Descricao_Produto": "BASE LISA CAMISETA COR PRETO TAMANHO - G", - "Quantidade": 1, - "Valor_Unitario": 12.27009 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 95.2, - "ID_Produto": "919483303", - "Descricao_Produto": "BASE LISA CAMISETA COR PRETO TAMANHO - M", - "Quantidade": 2, - "Valor_Unitario": 11.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 95.2, - "ID_Produto": "919483311", - "Descricao_Produto": "BASE LISA CAMISETA COR PRETO TAMANHO - GG", - "Quantidade": 2, - "Valor_Unitario": 11.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 95.2, - "ID_Produto": "976044109", - "Descricao_Produto": "BASE LISA CAMISETA COR MARINHO TAMANHO - GG", - "Quantidade": 2, - "Valor_Unitario": 11.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 95.2, - "ID_Produto": "919483255", - "Descricao_Produto": "BASE LISA CAMISETA COR PEROLA TAMANHO - G", - "Quantidade": 1, - "Valor_Unitario": 11.9 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 95.2, - "ID_Produto": "919483299", - "Descricao_Produto": "BASE LISA CAMISETA COR PRETO TAMANHO - P", - "Quantidade": 1, - "Valor_Unitario": 11.9 - }, - { - "Nome_Cliente": "Francieli Campos", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 224.95, - "ID_Produto": "978761156", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (10 METROS)", - "Quantidade": 1, - "Valor_Unitario": 199 - }, - { - "Nome_Cliente": "Daniela Gutierrez", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 217.45, - "ID_Produto": "951438842", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (1 METRO)", - "Quantidade": 10, - "Valor_Unitario": 19.9 - }, - { - "Nome_Cliente": "Joyce Pretel", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 22.47, - "ID_Produto": "951540701", - "Descricao_Produto": "BONÉ - PRETO", - "Quantidade": 3, - "Valor_Unitario": 7.49 - }, - { - "Nome_Cliente": "61.855.899 WALTER PONCE JUNIOR", - "Data_Pedido": "30-04-2026", - "Valor_Pedido": 59.7, - "ID_Produto": "951438842", - "Descricao_Produto": "IMPRESSÃO DTF PERSONALIZADO 57X100 (1 METRO)", - "Quantidade": 3, - "Valor_Unitario": 19.9 - } -] \ No newline at end of file diff --git a/test-fetch.js b/test-fetch.js deleted file mode 100644 index dc4b63f..0000000 --- a/test-fetch.js +++ /dev/null @@ -1,15 +0,0 @@ -async function run() { - const loginRes = await fetch('http://localhost:3004/api/login', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: 'admin@admin.com', password: 'admin123' }) - }); - const { token } = await loginRes.json(); - const dataRes = await fetch('http://localhost:3004/api/data?start=2020-01-01&end=2030-01-01', { - headers: { 'Authorization': `Bearer ${token}` } - }); - const data = await dataRes.json(); - const fabricio = data.find(d => d.Nome_Cliente.includes('Teste Hoje')); - console.log(fabricio); -} -run(); \ No newline at end of file diff --git a/test-payload.json b/test-payload.json deleted file mode 100644 index 794f8c7..0000000 --- a/test-payload.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "Nome_Cliente": "Fabrcio Araujo leme", - "Data_Pedido": "13/02/2025", - "Valor_Pedido": 94.95, - "ID_Pedido": "942384335", - "ID_Produto": "942384336", - "Descricao_Produto": "Camiseta Plus Size Premium Algodão Estampada Paris Tira G4 Grafite", - "Quantidade": "1.0000", - "Valor_Unitario": "31.650000" - }, - { - "Nome_Cliente": "Fabrcio Araujo leme", - "Data_Pedido": "13/02/2025", - "Valor_Pedido": 94.95, - "ID_Pedido": "942384335", - "ID_Produto": "942384339", - "Descricao_Produto": "Camiseta Plus Size Premium Algodão Estampada Fichas Rolando G4 Preto", - "Quantidade": "1.0000", - "Valor_Unitario": "31.650000" - }, - { - "Nome_Cliente": "Fabrcio Araujo leme", - "Data_Pedido": "13/02/2025", - "Valor_Pedido": 94.95, - "ID_Pedido": "942384335", - "ID_Produto": "942384342", - "Descricao_Produto": "Camiseta Plus Size Unissex T-Shirt Premium Sorte Nas Cartas G4 Preto", - "Quantidade": "1.0000", - "Valor_Unitario": "31.650000" - } -] \ No newline at end of file