--- type: Entity layer: wiki tags: [stack, dashdescomplicar, backend, express, api, core] title: "Express-API" --- # Express-API Servidor backend Express 4 que expõe a REST API do DashDescomplicar. Orquestra 15 rotas, middleware de segurança e serve o frontend estático em produção. ## Responsabilidades - **Roteamento**: 15 rotas REST (`/api/dashboard`, `/api/monitor`, `/api/hetzner`, `/api/wp-monitor`, `/api/server-metrics`, `/api/financial`, `/api/mcps`, `/api/n8n`, `/api/paperclip`, `/api/operations`, `/api/ai`, `/api/beszel`, `/api/sessions`, `/api/diagnostic`, `/api/health`) - **Segurança**: Rate limiting (100 req/15min produção, 1000/15min dev), CORS restrito, validação Zod em todas as rotas, OIDC opcional - **Error Handling**: UUIDs para tracking de erros, sem stack traces em produção, logs estruturados - **Static Serving**: Serve o bundle Vite (React SPA) em produção na porta 3001 - **Health Check**: Endpoint `/health` (público) e `/api/health` (autenticado) ## Stack - **Runtime**: Node.js 22+ (Alpine no Docker) - **Framework**: Express 4.19+ com TypeScript 5.9 - **Validação**: Zod 4.3 (`z.object()`, `.passthrough()`, `z.coerce`) - **Rate Limit**: `express-rate-limit` 8.2 - **CORS**: `cors` 2.8 - **Auth**: `express-openid-connect` (opcional, via `OIDC_ENABLED`) - **DB Drivers**: `mysql2` 3.11 (promise), `ssh2` 1.17, `better-sqlite3` 12.9 - **Observabilidade**: SQLite local (`~/.claude-work/sessions.db`) para sessões Claude Code ## Localizações - **Código**: `Dev/DashDescomplicar/api/server.ts` (238 linhas) - **Rotas**: `api/routes/` (14 ficheiros) - **Serviços**: `api/services/` (16 ficheiros) - **Middleware**: `api/middleware/validation.ts` - **DB Pool**: `api/db.ts` - **Deploy**: `dash.descomplicar.pt:3001` (EasyPanel Swarm) - **Dev**: `http://localhost:3001` (tsx watch) ## Rotas Expostas | Rota | Ficheiro | Fonte Dados | |---|---|---| | `GET /api/dashboard` | `routes/dashboard.ts` | Desk CRM MySQL (16 queries paralelas) | | `GET /api/monitor` | `routes/monitor.ts` | `tbl_eal_monitoring` (MySQL) | | `GET /api/diagnostic` | `routes/diagnostic.ts` | Testes de conectividade (17 checks) | | `GET/POST /api/hetzner` | `routes/hetzner.ts` | Hetzner Cloud API + MySQL | | `GET/POST /api/wp-monitor` | `routes/wp-monitor.ts` | Plugin WP → MySQL (API key auth) | | `POST /api/server-metrics` | `routes/server-metrics.ts` | SSH2 (EasyPanel) + MySQL | | `GET /api/financial` | `routes/financial.ts` | Desk CRM MySQL (7 queries) | | `GET /api/mcps` | `routes/mcps.ts` | MCP Gateway (HTTP ping, cache 60s) | | `GET /api/n8n` | `routes/n8n.ts` | n8n REST API (cache 300s) | | `GET /api/paperclip` | `routes/paperclip.ts` | PostgreSQL Paperclip (com fallback) | | `GET /api/operations` | `routes/operations.ts` | Desk CRM MySQL (4 queries) | | `GET /api/ai` | `routes/ai.ts` | Dados estáticos (snapshot STK) | | `GET /api/beszel` | `routes/beszel.ts` | Beszel PocketBase API + MySQL | | `GET /api/sessions` | `routes/sessions.ts` | SQLite local (better-sqlite3) | ## Dependências - **MySQL-Pool**: Conexão ao Desk CRM (`176.9.3.158`) - **Variáveis de Ambiente**: `DB_*`, `HETZNER_TOKEN`, `WP_MONITOR_API_KEY`, `N8N_API_KEY`, `BESZEL_*`, `EASY_*`, `MCP_GATEWAY_*`, `OIDC_*`, `OBSERVABILIDADE_DB` - **Docker-Deploy**: Empacotado via `Dockerfile` → EasyPanel Swarm - **Observabilidade-Sessions**: Abre ligação SQLite para sessões Claude Code ## Consome de - Desk CRM (MySQL — `176.9.3.158:3306`) - Hetzner Cloud API (`api.hetzner.cloud/v1`) - MCP Gateway (`gateway.descomplicar.pt`) - n8n API (`automator.descomplicar.pt/api/v1`) - Paperclip PostgreSQL (container Docker) - Beszel PocketBase API - EasyPanel Server (SSH2 porta 22) - Sistema de ficheiros local (SQLite sessions.db) ## Fornece a - Todos os 8 painéis frontend (via fetch à API) - Dashboard-Engine (dados agregados para `App.tsx`) - Sistema de diagnóstico (`/api/diagnostic`)