docs: add project context and remove boilerplate
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 44s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 44s
This commit is contained in:
169
README.md
169
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: <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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user