feat: adicionar 5 novos painéis ao dashboard (MCPs, n8n, Paperclip, IA, Operações)
Expansão do dashboard de 3 para 8 páginas com dados reais do stack: - MCPs: monitorização de 33 MCPs no gateway com ping e estado online/offline - n8n: 14 workflows com último run, duração e falhas 24h - Paperclip: 16 agentes operacionais, routines e issues (PostgreSQL) - IA/Claude: visão das 3 camadas (189 skills, 72 agents, 39 MCPs, CARL) - Operações: tickets Desk CRM por departamento + cobertura PROCs 16 ficheiros novos (3042 linhas), 3 existentes editados. Nova dependência: pg (PostgreSQL client para Paperclip). Audit: 0 vulnerabilidades (npm audit fix aplicado). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
---
|
||||
title: PLAN Conductor — Expansão DashDescomplicar
|
||||
date: 2026-04-06
|
||||
type: plan
|
||||
status: active
|
||||
spec: SPEC-dashboard-expansion-q2-2026.md
|
||||
tags: [conductor, plan, dashboard, parallel]
|
||||
---
|
||||
|
||||
# Plano Conductor — Expansão DashDescomplicar
|
||||
|
||||
**Spec:** `docs/SPEC-dashboard-expansion-q2-2026.md`
|
||||
**Projecto:** `/media/ealmeida/Dados/Dev/DashDescomplicar/`
|
||||
**Método:** Conductor parallel sprints — agentes independentes por domínio
|
||||
|
||||
---
|
||||
|
||||
## Estratégia de paralelização
|
||||
|
||||
Cada painel (backend + frontend) é **independente** — ficheiros distintos, sem dependências cruzadas. A integração (Layout, App, server.ts) é feita no final por um único agente coordenador.
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Coordenador │
|
||||
│ (Sprint 4) │
|
||||
└──────┬──────┘
|
||||
┌──────────────┼──────────────┐
|
||||
Sprint 1 │ Sprint 3
|
||||
┌────┴────┐ Sprint 2 ┌────┴────┐
|
||||
│ │ │ │ │
|
||||
Agent A Agent B Agent C Agent D Agent E
|
||||
MCPs n8n Paperclip IA Operações
|
||||
```
|
||||
|
||||
**Agentes A-E correm em paralelo.** Agente F (coordenador) corre depois, integrando tudo.
|
||||
|
||||
---
|
||||
|
||||
## Pré-requisitos (executar antes do conductor)
|
||||
|
||||
1. Instalar `pg` (PostgreSQL client):
|
||||
```bash
|
||||
cd /media/ealmeida/Dados/Dev/DashDescomplicar && npm install pg @types/pg
|
||||
```
|
||||
|
||||
2. Verificar env vars disponíveis no EasyPanel (MCP_GATEWAY_TOKEN, N8N_API_KEY, PAPERCLIP_DB_*)
|
||||
|
||||
---
|
||||
|
||||
## Agent A — Painel MCPs
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** worktree
|
||||
**Ficheiros a criar:**
|
||||
- `api/services/mcps.ts`
|
||||
- `api/routes/mcps.ts`
|
||||
- `src/pages/McpMonitor.tsx`
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + TypeScript.
|
||||
|
||||
Lê a spec completa em docs/SPEC-dashboard-expansion-q2-2026.md, secção 4.1 (Painel MCPs).
|
||||
|
||||
Cria 3 ficheiros:
|
||||
|
||||
1. api/services/mcps.ts — Service que:
|
||||
- Tem lista hardcoded de 35 MCPs (nome, porta, categoria, enabled)
|
||||
- Faz ping paralelo (Promise.allSettled, timeout 5s) aos MCPs enabled via HTTP GET
|
||||
- Gateway URL: process.env.MCP_GATEWAY_URL || 'https://gateway.descomplicar.pt'
|
||||
- Bearer token: process.env.MCP_GATEWAY_TOKEN
|
||||
- Cache de 60 segundos (variável em memória com timestamp)
|
||||
- Retorna McpDashboard conforme spec
|
||||
|
||||
2. api/routes/mcps.ts — Router Express com GET /
|
||||
- Chama o service e retorna JSON
|
||||
- try/catch com 500 error handling (padrão dos outros routers no projecto)
|
||||
|
||||
3. src/pages/McpMonitor.tsx — Página React que:
|
||||
- Faz fetch a /api/mcps com useEffect
|
||||
- Mostra header com stats (total/online/offline/disabled)
|
||||
- Grid de cards agrupados por categoria (crm, infra, ai, tools, external)
|
||||
- Card com: nome, porta, status (cor), response_time
|
||||
- Botão refresh manual
|
||||
- Loading state e error state
|
||||
- Segue estilo visual do projecto: ler src/pages/Monitor.tsx como referência (dark theme, motion.div, lucide icons, containerVariants/itemVariants)
|
||||
|
||||
Lista dos MCPs para hardcoding:
|
||||
- CRM: desk-crm-v3 (3150), desk-project-minimal (3153)
|
||||
- Infra: ssh-unified (3192), filesystem (local), chrome-devtools (local)
|
||||
- AI: lightrag (3160), notebooklm (3190), context7 (3169), replicate (3176), memory-supabase (3151)
|
||||
- Tools: mcp-time (3155), deepl (3188), pexels (3175), vimeo (3177), drawio (3184)
|
||||
- External: google-workspace (3156), google-analytics (3164), gsc (3165), youtube (3166), youtube-research (3167), moloni (3158), n8n (3171), gitea (3162), stitch (external), design-systems (external)
|
||||
- Gateway: authentik (3191), spaceship (3189), puppeteer (3193), lighthouse (3194)
|
||||
- Locais (disabled ping): filesystem, chrome-devtools
|
||||
- MCPs em .mcp.json: carl-mcp (local, porta variável), reonic (3187)
|
||||
|
||||
Não alteres nenhum ficheiro existente. Apenas cria os 3 novos.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent B — Painel n8n
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** worktree
|
||||
**Ficheiros a criar:**
|
||||
- `api/services/n8n.ts`
|
||||
- `api/routes/n8n.ts`
|
||||
- `src/pages/N8nMonitor.tsx`
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + TypeScript.
|
||||
|
||||
Lê a spec completa em docs/SPEC-dashboard-expansion-q2-2026.md, secção 4.2 (Painel n8n).
|
||||
|
||||
Cria 3 ficheiros:
|
||||
|
||||
1. api/services/n8n.ts — Service que:
|
||||
- Chama API REST n8n: GET /workflows e GET /executions?limit=50
|
||||
- URL base: process.env.N8N_API_URL || 'https://automator.descomplicar.pt/api/v1'
|
||||
- Auth: header X-N8N-API-KEY com process.env.N8N_API_KEY
|
||||
- Cache de 300 segundos
|
||||
- Retorna N8nDashboard conforme spec (total, active, failed_24h, workflows com last_execution)
|
||||
|
||||
2. api/routes/n8n.ts — Router Express com GET /
|
||||
- try/catch com 500 error handling
|
||||
|
||||
3. src/pages/N8nMonitor.tsx — Página React que:
|
||||
- Faz fetch a /api/n8n
|
||||
- Stats cards: total workflows, activos, falhas 24h (destaque vermelho se >0)
|
||||
- Tabela com: nome, activo (badge), último run (data + status com cor), duração
|
||||
- Filtro toggle: activos/todos
|
||||
- Segue estilo visual: ler src/pages/Financial.tsx como referência
|
||||
|
||||
Não alteres nenhum ficheiro existente. Apenas cria os 3 novos.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent C — Painel Paperclip
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** worktree
|
||||
**Ficheiros a criar:**
|
||||
- `api/services/paperclip-db.ts`
|
||||
- `api/services/paperclip.ts`
|
||||
- `api/routes/paperclip.ts`
|
||||
- `src/pages/Paperclip.tsx`
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + TypeScript.
|
||||
|
||||
Lê a spec completa em docs/SPEC-dashboard-expansion-q2-2026.md, secção 4.3 (Painel Paperclip).
|
||||
|
||||
O pacote `pg` já foi instalado (npm install pg @types/pg).
|
||||
|
||||
Cria 4 ficheiros:
|
||||
|
||||
1. api/services/paperclip-db.ts — Pool PostgreSQL:
|
||||
- Host: process.env.PAPERCLIP_DB_HOST || 'clip.descomplicar.pt'
|
||||
- Port: process.env.PAPERCLIP_DB_PORT || 54329
|
||||
- Database: process.env.PAPERCLIP_DB_NAME || 'paperclip'
|
||||
- User/Pass: process.env.PAPERCLIP_DB_USER, process.env.PAPERCLIP_DB_PASS
|
||||
- Pool com max 5 conexões
|
||||
- Validação de credenciais obrigatória (throw se não definidas)
|
||||
- Export default pool
|
||||
|
||||
2. api/services/paperclip.ts — Queries:
|
||||
- getAgents(): SELECT id, name, role, status, last_heartbeat, total_runs FROM agents WHERE status != 'archived'
|
||||
- getRoutines(): SELECT id, name, cron, active, last_run, last_status FROM routines
|
||||
- getIssueStats(): COUNT por estado (open, in_progress, closed últimos 7 dias)
|
||||
- Retorna PaperclipDashboard conforme spec
|
||||
- NOTA: os nomes exactos das tabelas e colunas podem variar — usar nomes razoáveis e documentar com comentário que podem precisar de ajuste
|
||||
|
||||
3. api/routes/paperclip.ts — Router Express com GET /
|
||||
- try/catch, se BD inacessível retornar dados fallback (zeros)
|
||||
|
||||
4. src/pages/Paperclip.tsx — Página React:
|
||||
- Stats cards: agentes activos/idle/error, routines activas
|
||||
- Grid de cards para agentes, agrupados por role (C-Level, Director, Specialist)
|
||||
- Cor do card por status: active=verde, idle=amarelo, error=vermelho
|
||||
- Tabela de routines: nome, cron, activa, último run, status
|
||||
- Segue estilo visual do projecto
|
||||
|
||||
Não alteres nenhum ficheiro existente. Apenas cria os 4 novos.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent D — Painel IA / Claude Code
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** worktree
|
||||
**Ficheiros a criar:**
|
||||
- `api/services/ai.ts`
|
||||
- `api/routes/ai.ts`
|
||||
- `src/pages/AiOverview.tsx`
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + TypeScript.
|
||||
|
||||
Lê a spec completa em docs/SPEC-dashboard-expansion-q2-2026.md, secção 4.4 (Painel Claude Code / IA).
|
||||
|
||||
Cria 3 ficheiros:
|
||||
|
||||
1. api/services/ai.ts — Service que:
|
||||
- Retorna dados maioritariamente estáticos (actualizados manualmente)
|
||||
- Dados reais do stack (fonte: STK-Estado-Actual.md de 04-04-2026):
|
||||
- Skills: 189 total (31 directas + 158 plugins)
|
||||
- Agents CC: 72 (18 directos + 54 plugins)
|
||||
- MCPs: 39 (10 enabled, 29 disabled, 33 gateway, 2 locais)
|
||||
- Hooks: 26 ficheiros, 9 activos
|
||||
- Plugins: 14 Descomplicar + 6 oficiais + 3 terceiros, 6 activos
|
||||
- CARL: 7 domínios, ~45 regras
|
||||
- Paperclip: 16 operacionais
|
||||
- n8n: 14 workflows
|
||||
- NotebookLM: 58 notebooks
|
||||
- Cache infinito (dados estáticos)
|
||||
|
||||
2. api/routes/ai.ts — Router Express com GET /
|
||||
|
||||
3. src/pages/AiOverview.tsx — Página React:
|
||||
- Layout de "stack overview" com 3 secções:
|
||||
a) Camada 1 (Claude Code): cards para skills, agents, MCPs, hooks, plugins
|
||||
b) Camada 2 (n8n): card simples com contagem workflows
|
||||
c) Camada 3 (Paperclip): card simples com contagem agentes
|
||||
- Card grande central: "3 Camadas de Execução" com diagrama visual (CSS, não SVG)
|
||||
- Secção CARL: 7 domínios listados (GLOBAL, CRM, DEVELOPMENT, WORDPRESS, HUB, INFRASTRUCTURE, QUALITY, SKILLS)
|
||||
- Tons roxos/violeta para diferenciar das outras páginas
|
||||
- Segue estilo visual do projecto
|
||||
|
||||
Não alteres nenhum ficheiro existente. Apenas cria os 3 novos.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent E — Painel Operações
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** worktree
|
||||
**Ficheiros a criar:**
|
||||
- `api/services/operations.ts`
|
||||
- `api/routes/operations.ts`
|
||||
- `src/pages/Operations.tsx`
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + TypeScript.
|
||||
|
||||
Lê a spec em docs/SPEC-dashboard-expansion-q2-2026.md, secção 4.5 (Painel Operações).
|
||||
|
||||
A BD MySQL (Desk CRM) já tem conexão configurada em api/db.ts (export default pool mysql2/promise).
|
||||
|
||||
Cria 3 ficheiros:
|
||||
|
||||
1. api/services/operations.ts — Service que:
|
||||
- Queries ao MySQL (Desk CRM):
|
||||
a) Tickets abertos: SELECT COUNT(*) FROM tbltickets WHERE status IN ('Open','In Progress','Answered')
|
||||
b) Tickets alta prioridade: WHERE priority IN (2,3)
|
||||
c) Tickets por departamento: JOIN tbldepartments GROUP BY department
|
||||
d) Tempo médio resposta: AVG(TIMESTAMPDIFF(HOUR, date, lastreply)) dos tickets com resposta
|
||||
- Dados estáticos PROCs:
|
||||
- 48 procedimentos, 8 departamentos
|
||||
- Cobertura por dept: D1(5), D2(3), D3(3), D4(1), D5(5), D6(8), D7(18), Cross(5)
|
||||
- import db from '../db.js'
|
||||
|
||||
2. api/routes/operations.ts — Router Express com GET /
|
||||
|
||||
3. src/pages/Operations.tsx — Página React:
|
||||
- Stats cards: tickets abertos, alta prioridade, tempo médio resposta
|
||||
- Gráfico barras horizontal (recharts BarChart): tickets por departamento
|
||||
- Tabela cobertura PROCs: departamento, número PROCs, % cobertura
|
||||
- Segue estilo visual: ler src/pages/Financial.tsx como referência (usa recharts)
|
||||
|
||||
Não alteres nenhum ficheiro existente. Apenas cria os 3 novos.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent F — Coordenador / Integração (executa após A-E)
|
||||
|
||||
**Tipo:** `javascript-fullstack-specialist`
|
||||
**Isolation:** nenhum (merge directo)
|
||||
**Ficheiros a alterar:**
|
||||
- `src/components/Layout.tsx`
|
||||
- `src/App.tsx` (secção de routing)
|
||||
- `api/server.ts` (registar routers)
|
||||
|
||||
**Prompt:**
|
||||
|
||||
```
|
||||
Estás a trabalhar no projecto DashDescomplicar (/media/ealmeida/Dados/Dev/DashDescomplicar/).
|
||||
|
||||
Os seguintes ficheiros novos já foram criados por agentes anteriores:
|
||||
- api/routes/mcps.ts, api/services/mcps.ts, src/pages/McpMonitor.tsx
|
||||
- api/routes/n8n.ts, api/services/n8n.ts, src/pages/N8nMonitor.tsx
|
||||
- api/routes/paperclip.ts, api/services/paperclip.ts, api/services/paperclip-db.ts, src/pages/Paperclip.tsx
|
||||
- api/routes/ai.ts, api/services/ai.ts, src/pages/AiOverview.tsx
|
||||
- api/routes/operations.ts, api/services/operations.ts, src/pages/Operations.tsx
|
||||
|
||||
Faz a integração:
|
||||
|
||||
1. src/components/Layout.tsx — Adicionar 5 itens ao array NAV_ITEMS:
|
||||
- { to: '/mcps', label: 'MCPs', icon: Network }
|
||||
- { to: '/n8n', label: 'Automações', icon: Workflow }
|
||||
- { to: '/paperclip', label: 'Paperclip', icon: Bot }
|
||||
- { to: '/ai', label: 'IA / Claude', icon: Brain }
|
||||
- { to: '/operations', label: 'Operações', icon: ClipboardList }
|
||||
Adicionar os imports de ícones do lucide-react: Network, Workflow, Bot, Brain, ClipboardList
|
||||
NOTA: verificar se 'Workflow' existe em lucide-react, se não usar 'GitBranch' ou 'Repeat'
|
||||
|
||||
2. src/App.tsx — Na secção de routing (BrowserRouter/Routes), adicionar:
|
||||
- import McpMonitor from './pages/McpMonitor'
|
||||
- import N8nMonitor from './pages/N8nMonitor'
|
||||
- import Paperclip from './pages/Paperclip'
|
||||
- import AiOverview from './pages/AiOverview'
|
||||
- import Operations from './pages/Operations'
|
||||
E as respectivas <Route> dentro do <Route element={<Layout />}>
|
||||
|
||||
3. api/server.ts — Adicionar imports e app.use:
|
||||
- import mcpsRouter from './routes/mcps.js'
|
||||
- import n8nRouter from './routes/n8n.js'
|
||||
- import paperclipRouter from './routes/paperclip.js'
|
||||
- import aiRouter from './routes/ai.js'
|
||||
- import operationsRouter from './routes/operations.js'
|
||||
- app.use('/api/mcps', mcpsRouter)
|
||||
- app.use('/api/n8n', n8nRouter)
|
||||
- app.use('/api/paperclip', paperclipRouter)
|
||||
- app.use('/api/ai', aiRouter)
|
||||
- app.use('/api/operations', operationsRouter)
|
||||
|
||||
Lê cada ficheiro antes de editar. Mantém o estilo existente. Não alteres mais nada.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sequência de execução
|
||||
|
||||
```
|
||||
Fase 1 (paralelo): Agent A + Agent B + Agent C + Agent D + Agent E
|
||||
↓ todos concluídos
|
||||
Fase 2 (sequencial): Merge worktrees → main
|
||||
↓
|
||||
Fase 3 (sequencial): Agent F (integração)
|
||||
↓
|
||||
Fase 4 (validação): npm run build + teste manual
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comando conductor
|
||||
|
||||
```bash
|
||||
# Fase 1 — lançar 5 agentes em paralelo (worktree isolation)
|
||||
# Usar: Agent tool com isolation: "worktree" e run_in_background: true
|
||||
|
||||
# Fase 2 — após todos concluírem, merge dos worktrees
|
||||
# git merge <branch-agent-a> --no-edit
|
||||
# git merge <branch-agent-b> --no-edit
|
||||
# ...
|
||||
|
||||
# Fase 3 — Agent F integração
|
||||
# Sem worktree, directo no main
|
||||
|
||||
# Fase 4 — validar
|
||||
# npm run build
|
||||
# npm run dev (testar manualmente)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist de validação final
|
||||
|
||||
- [ ] `npm run build` sem erros
|
||||
- [ ] Todas as 8 páginas navegáveis na sidebar
|
||||
- [ ] GET /api/mcps retorna dados
|
||||
- [ ] GET /api/n8n retorna dados (ou erro claro se API key não configurada)
|
||||
- [ ] GET /api/paperclip retorna dados (ou fallback zeros se BD inacessível)
|
||||
- [ ] GET /api/ai retorna dados estáticos
|
||||
- [ ] GET /api/operations retorna dados do Desk CRM
|
||||
- [ ] Mobile: sidebar colapsa correctamente com 8 itens
|
||||
- [ ] Zero erros na consola do browser
|
||||
@@ -0,0 +1,473 @@
|
||||
---
|
||||
title: SPEC — Expansão DashDescomplicar Q2 2026
|
||||
date: 2026-04-06
|
||||
type: spec
|
||||
status: active
|
||||
desk_project: 65
|
||||
tags: [dashboard, expansion, mcps, paperclip, n8n, claude-code]
|
||||
---
|
||||
|
||||
# SPEC — Expansão DashDescomplicar Q2 2026
|
||||
|
||||
## 1. Contexto
|
||||
|
||||
O DashDescomplicar é o painel de gestão interno da Descomplicar®. Stack: React 19 + Vite + Tailwind CSS 4 + Express 4 + MySQL (Desk CRM BD). Deploy em EasyPanel via Dockerfile.
|
||||
|
||||
### Estado actual (3 páginas)
|
||||
|
||||
| Página | Rotas API | Dados |
|
||||
|--------|-----------|-------|
|
||||
| **Dashboard** (App.tsx) | `/api/dashboard` | Tarefas (urgente/alta/vencidas/em teste), leads (contactar/followup/proposta), projectos, billing 360, calendário Google, timesheet |
|
||||
| **Monitor** | `/api/monitor`, `/api/hetzner`, `/api/server-metrics`, `/api/wp-monitor`, `/api/diagnostic` | Servidores Hetzner (CPU/rede/disco), serviços HTTP (11 URLs), EasyPanel containers, sites WordPress (CWP) |
|
||||
| **Financeiro** | `/api/financial` | Vendas/despesas mês e ano, lucro, categorias, evolução mensal 12 meses |
|
||||
|
||||
### O que falta (referência: plano-migracao-mcps-gateway-auth.md, Fase 5)
|
||||
|
||||
Novos painéis para reflectir o stack completo: MCPs (33 no gateway), n8n (14 workflows), Paperclip (16 agentes operacionais), Claude Code/IA (189 skills, 72 agents, 9 hooks), LightRAG (knowledge graph), Desk CRM expandido (tickets, SLAs), e Operações (worklogs, PROCs, calendário).
|
||||
|
||||
### Auth
|
||||
|
||||
OIDC com Authentik **já implementado no frontend** (react-oidc-context, AuthWrapper.tsx, config.ts). Backend tem placeholder (`OIDC_ENABLED=true`). Falta activar em produção.
|
||||
|
||||
---
|
||||
|
||||
## 2. Objectivos
|
||||
|
||||
1. Expandir o dashboard de 3 para 8 páginas
|
||||
2. Cada novo painel usa dados reais via API (gateway MCPs, BD MySQL, APIs HTTP)
|
||||
3. Manter a consistência visual (dark theme, Tailwind, framer-motion, lucide-react)
|
||||
4. Zero dependências novas — usar as existentes (recharts, framer-motion, lucide)
|
||||
5. Cada painel é independente — pode ser implementado e testado isoladamente
|
||||
|
||||
---
|
||||
|
||||
## 3. Arquitectura de dados (fontes por painel)
|
||||
|
||||
```
|
||||
Express API (porta 3001)
|
||||
├── /api/dashboard → MySQL (Desk CRM) + Google Calendar API [EXISTE]
|
||||
├── /api/monitor → MySQL (tbl_eal_monitoring) + Hetzner API [EXISTE]
|
||||
├── /api/financial → MySQL (Desk CRM invoices/expenses) [EXISTE]
|
||||
├── /api/mcps → HTTP GET gateway.descomplicar.pt/health + per-MCP ping [NOVO]
|
||||
├── /api/n8n → HTTP GET automator.descomplicar.pt/api/v1 (API key) [NOVO]
|
||||
├── /api/paperclip → PostgreSQL clip.descomplicar.pt (porta 54329) [NOVO]
|
||||
├── /api/ai → Ficheiros locais + MySQL (stats) [NOVO]
|
||||
└── /api/operations → MySQL (Desk CRM) + Google Calendar [NOVO]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Especificação por painel
|
||||
|
||||
### 4.1 Painel MCPs (nova página `/mcps`)
|
||||
|
||||
**Objectivo:** Ver todos os 33+2 MCPs com estado online/offline em tempo real.
|
||||
|
||||
**Rota API:** `GET /api/mcps`
|
||||
|
||||
**Fonte de dados:**
|
||||
- Gateway health: `GET https://gateway.descomplicar.pt/health` (sem auth, já existe)
|
||||
- Per-MCP ping: `GET https://gateway.descomplicar.pt/v1/<nome>/mcp` com Bearer token (resposta 200 = online)
|
||||
- Lista estática dos MCPs com metadados (nome, porta, categoria, enabled/disabled)
|
||||
|
||||
**Dados retornados:**
|
||||
```typescript
|
||||
interface McpStatus {
|
||||
name: string // "desk-crm-v3"
|
||||
port: number // 3150
|
||||
category: string // "crm" | "infra" | "ai" | "tools" | "external"
|
||||
enabled: boolean // true/false em claude.json
|
||||
status: 'online' | 'offline' | 'disabled' | 'unknown'
|
||||
response_time_ms: number | null
|
||||
last_check: string // ISO timestamp
|
||||
tools_count?: number // número de tools (se conhecido)
|
||||
}
|
||||
|
||||
interface McpDashboard {
|
||||
gateway_status: 'online' | 'offline'
|
||||
total: number
|
||||
online: number
|
||||
offline: number
|
||||
disabled: number
|
||||
mcps: McpStatus[]
|
||||
auth: {
|
||||
method: string // "dual-layer: IP whitelist + Bearer token"
|
||||
token_expires: string | null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UI (página McpMonitor.tsx):**
|
||||
- Header com stats gerais (total/online/offline/disabled)
|
||||
- Grid de cards por MCP, agrupados por categoria
|
||||
- Indicador de cor: verde (online), vermelho (offline), cinza (disabled)
|
||||
- Response time badge em cada card
|
||||
- Filtros: por categoria, por estado
|
||||
- Botão refresh manual
|
||||
|
||||
**Implementação backend (api/services/mcps.ts):**
|
||||
- Lista hardcoded de MCPs com metadados (extraída de port-map.json e claude.json)
|
||||
- Ping paralelo a cada MCP enabled (Promise.allSettled com timeout 5s)
|
||||
- Cache de 60 segundos (evitar spam ao gateway)
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Painel n8n (nova página `/n8n`)
|
||||
|
||||
**Objectivo:** Ver 14 workflows operacionais com estado, último run, próximo run.
|
||||
|
||||
**Rota API:** `GET /api/n8n`
|
||||
|
||||
**Fonte de dados:**
|
||||
- n8n API REST: `https://automator.descomplicar.pt/api/v1/workflows` (API key em env)
|
||||
- n8n API REST: `https://automator.descomplicar.pt/api/v1/executions?limit=50`
|
||||
|
||||
**Dados retornados:**
|
||||
```typescript
|
||||
interface N8nWorkflow {
|
||||
id: string
|
||||
name: string
|
||||
active: boolean
|
||||
last_execution: {
|
||||
status: 'success' | 'error' | 'running' | null
|
||||
started_at: string | null
|
||||
finished_at: string | null
|
||||
duration_ms: number | null
|
||||
} | null
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
interface N8nDashboard {
|
||||
total: number
|
||||
active: number
|
||||
inactive: number
|
||||
failed_24h: number
|
||||
workflows: N8nWorkflow[]
|
||||
last_updated: string
|
||||
}
|
||||
```
|
||||
|
||||
**UI (página N8nMonitor.tsx):**
|
||||
- Stats cards: total/activos/falhas 24h
|
||||
- Tabela de workflows: nome, activo, último run (com cor: verde/vermelho), duração
|
||||
- Filtro: activos/todos
|
||||
- Alerta visual se algum workflow falhou nas últimas 24h
|
||||
|
||||
**Env vars necessárias:**
|
||||
- `N8N_API_URL` (default: `https://automator.descomplicar.pt/api/v1`)
|
||||
- `N8N_API_KEY`
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Painel Paperclip (nova página `/paperclip`)
|
||||
|
||||
**Objectivo:** Ver os 16 agentes operacionais, routines, e issues.
|
||||
|
||||
**Rota API:** `GET /api/paperclip`
|
||||
|
||||
**Fonte de dados:**
|
||||
- PostgreSQL do Paperclip: `clip.descomplicar.pt:54329` (credenciais em env)
|
||||
- Tabelas: `agents`, `agent_runs`, `routines`, `routine_executions`, `issues`
|
||||
|
||||
**Dados retornados:**
|
||||
```typescript
|
||||
interface PaperclipAgent {
|
||||
id: string
|
||||
name: string
|
||||
role: string // "CEO", "CTO", "Director", "Specialist"
|
||||
status: 'active' | 'idle' | 'error' | 'archived'
|
||||
last_heartbeat: string | null
|
||||
last_run: string | null
|
||||
total_runs: number
|
||||
}
|
||||
|
||||
interface PaperclipRoutine {
|
||||
id: string
|
||||
name: string
|
||||
cron: string
|
||||
active: boolean
|
||||
last_run: string | null
|
||||
last_status: 'success' | 'error' | null
|
||||
next_run: string | null
|
||||
}
|
||||
|
||||
interface PaperclipDashboard {
|
||||
agents: {
|
||||
total: number
|
||||
active: number
|
||||
idle: number
|
||||
error: number
|
||||
list: PaperclipAgent[]
|
||||
}
|
||||
routines: {
|
||||
total: number
|
||||
active: number
|
||||
list: PaperclipRoutine[]
|
||||
}
|
||||
issues: {
|
||||
open: number
|
||||
in_progress: number
|
||||
closed_7d: number
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UI (página Paperclip.tsx):**
|
||||
- Stats cards: agentes activos/idle/error, routines activas
|
||||
- Grid de cards para agentes (agrupados por role/nível hierárquico)
|
||||
- Tabela de routines com cron, último/próximo run
|
||||
- Contador de issues (open/in-progress/closed)
|
||||
|
||||
**Env vars necessárias:**
|
||||
- `PAPERCLIP_DB_HOST` (default: clip.descomplicar.pt)
|
||||
- `PAPERCLIP_DB_PORT` (default: 54329)
|
||||
- `PAPERCLIP_DB_NAME`
|
||||
- `PAPERCLIP_DB_USER`
|
||||
- `PAPERCLIP_DB_PASS`
|
||||
|
||||
**Dependência adicional:** `pg` (PostgreSQL client para Node.js) — **única nova dependência no projecto**
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Painel Claude Code / IA (nova página `/ai`)
|
||||
|
||||
**Objectivo:** Ver skills top, agents, MCPs activos, e CARL.
|
||||
|
||||
**Rota API:** `GET /api/ai`
|
||||
|
||||
**Fonte de dados:**
|
||||
- Contagens estáticas derivadas do STK-Estado-Actual.md (actualizar periodicamente)
|
||||
- CARL config: leitura de `/media/ealmeida/Dados/.carl/carl.json` (se acessível via EasyPanel volume mount, senão estático)
|
||||
- Hooks: contagem de ficheiros em `~/.claude/hooks/`
|
||||
|
||||
**Dados retornados:**
|
||||
```typescript
|
||||
interface AiDashboard {
|
||||
skills: {
|
||||
total: number // 189
|
||||
directas: number // 31
|
||||
plugins: number // 158
|
||||
top_10: string[] // nomes das 10 mais usadas
|
||||
}
|
||||
agents: {
|
||||
total: number // 72
|
||||
directos: number // 18
|
||||
plugins: number // 54
|
||||
}
|
||||
mcps: {
|
||||
total: number // 39
|
||||
enabled: number // 10
|
||||
gateway: number // 33
|
||||
local: number // 2
|
||||
}
|
||||
hooks: {
|
||||
total_files: number // 26
|
||||
active: number // 9
|
||||
}
|
||||
carl: {
|
||||
domains: number // 7
|
||||
rules: number // ~45
|
||||
decisions: number
|
||||
}
|
||||
plugins: {
|
||||
total: number // 14 descomplicar + 6 oficiais + 3 terceiros
|
||||
active: number // 6
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UI (página AiOverview.tsx):**
|
||||
- Cards grandes com métricas (skills, agents, MCPs, hooks, plugins)
|
||||
- Secção CARL: domínios com contagem de regras
|
||||
- Sem interactividade complexa — é um painel informativo/snapshot
|
||||
|
||||
**Nota:** Este painel é maioritariamente estático. Os dados mudam raramente (quando se adicionam skills/agents). Actualização via endpoint manual ou ficheiro JSON servido estáticamente.
|
||||
|
||||
---
|
||||
|
||||
### 4.5 Painel Operações (nova página `/operations`)
|
||||
|
||||
**Objectivo:** Visão operacional — tickets, SLAs, procedimentos.
|
||||
|
||||
**Rota API:** `GET /api/operations`
|
||||
|
||||
**Fonte de dados:**
|
||||
- MySQL (Desk CRM): tickets abertos, por prioridade, SLAs
|
||||
- Contagens estáticas: PROCs (48), departamentos (7)
|
||||
|
||||
**Dados retornados:**
|
||||
```typescript
|
||||
interface OperationsDashboard {
|
||||
tickets: {
|
||||
open: number
|
||||
high_priority: number
|
||||
avg_response_hours: number
|
||||
by_department: { dept: string; count: number }[]
|
||||
}
|
||||
procedures: {
|
||||
total: number // 48
|
||||
departments: number // 7 (D1-D7)
|
||||
coverage: { dept: string; procs: number; pct: number }[]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UI (página Operations.tsx):**
|
||||
- Cards: tickets abertos, alta prioridade, tempo médio resposta
|
||||
- Gráfico barras: tickets por departamento
|
||||
- Tabela cobertura PROCs por departamento
|
||||
|
||||
---
|
||||
|
||||
## 5. Alterações ao código existente
|
||||
|
||||
### 5.1 Layout.tsx — adicionar itens de navegação
|
||||
|
||||
```typescript
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ to: '/', label: 'Dashboard', icon: LayoutDashboard },
|
||||
{ to: '/monitor', label: 'Monitor', icon: Activity },
|
||||
{ to: '/financial', label: 'Financeiro', icon: CreditCard },
|
||||
// NOVOS:
|
||||
{ to: '/mcps', label: 'MCPs', icon: Network },
|
||||
{ to: '/n8n', label: 'Automações', icon: Workflow },
|
||||
{ to: '/paperclip', label: 'Paperclip', icon: Bot },
|
||||
{ to: '/ai', label: 'IA / Claude', icon: Brain },
|
||||
{ to: '/operations', label: 'Operações', icon: ClipboardList },
|
||||
]
|
||||
```
|
||||
|
||||
### 5.2 App.tsx — adicionar rotas
|
||||
|
||||
Novas rotas no React Router para cada página.
|
||||
|
||||
### 5.3 server.ts — registar novas rotas API
|
||||
|
||||
```typescript
|
||||
import mcpsRouter from './routes/mcps.js'
|
||||
import n8nRouter from './routes/n8n.js'
|
||||
import paperclipRouter from './routes/paperclip.js'
|
||||
import aiRouter from './routes/ai.js'
|
||||
import operationsRouter from './routes/operations.js'
|
||||
|
||||
app.use('/api/mcps', mcpsRouter)
|
||||
app.use('/api/n8n', n8nRouter)
|
||||
app.use('/api/paperclip', paperclipRouter)
|
||||
app.use('/api/ai', aiRouter)
|
||||
app.use('/api/operations', operationsRouter)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Ficheiros a criar (por sprint)
|
||||
|
||||
### Sprint 1 — MCPs + n8n (estimativa: 8-10h)
|
||||
```
|
||||
api/routes/mcps.ts # Rota GET /api/mcps
|
||||
api/services/mcps.ts # Ping gateway, lista MCPs, cache
|
||||
api/routes/n8n.ts # Rota GET /api/n8n
|
||||
api/services/n8n.ts # Chamadas API n8n
|
||||
src/pages/McpMonitor.tsx # Página frontend MCPs
|
||||
src/pages/N8nMonitor.tsx # Página frontend n8n
|
||||
```
|
||||
|
||||
### Sprint 2 — Paperclip (estimativa: 6-8h)
|
||||
```
|
||||
api/services/paperclip-db.ts # Conexão PostgreSQL Paperclip
|
||||
api/routes/paperclip.ts # Rota GET /api/paperclip
|
||||
api/services/paperclip.ts # Queries aos agentes/routines/issues
|
||||
src/pages/Paperclip.tsx # Página frontend Paperclip
|
||||
```
|
||||
|
||||
### Sprint 3 — IA + Operações (estimativa: 4-6h)
|
||||
```
|
||||
api/routes/ai.ts # Rota GET /api/ai
|
||||
api/services/ai.ts # Dados estáticos/contagens IA
|
||||
api/routes/operations.ts # Rota GET /api/operations
|
||||
api/services/operations.ts # Queries tickets + PROCs
|
||||
src/pages/AiOverview.tsx # Página frontend IA
|
||||
src/pages/Operations.tsx # Página frontend Operações
|
||||
```
|
||||
|
||||
### Sprint 4 — Integração + polish (estimativa: 2-3h)
|
||||
```
|
||||
# Alterações a ficheiros existentes:
|
||||
src/components/Layout.tsx # Adicionar 5 itens nav
|
||||
src/App.tsx # Adicionar 5 rotas (no routing section)
|
||||
api/server.ts # Registar 5 routers novos
|
||||
.env.example # Novas env vars documentadas
|
||||
README.md # Actualizar documentação
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Env vars novas necessárias
|
||||
|
||||
```env
|
||||
# MCPs Gateway
|
||||
MCP_GATEWAY_URL=https://gateway.descomplicar.pt
|
||||
MCP_GATEWAY_TOKEN=<authentik-bearer-token>
|
||||
|
||||
# n8n
|
||||
N8N_API_URL=https://automator.descomplicar.pt/api/v1
|
||||
N8N_API_KEY=<n8n-api-key>
|
||||
|
||||
# Paperclip PostgreSQL
|
||||
PAPERCLIP_DB_HOST=clip.descomplicar.pt
|
||||
PAPERCLIP_DB_PORT=54329
|
||||
PAPERCLIP_DB_NAME=paperclip
|
||||
PAPERCLIP_DB_USER=<user>
|
||||
PAPERCLIP_DB_PASS=<pass>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Dependências
|
||||
|
||||
| Pacote | Razão | Sprint |
|
||||
|--------|-------|--------|
|
||||
| `pg` | PostgreSQL client (Paperclip BD) | Sprint 2 |
|
||||
|
||||
Todas as outras dependências já existem no projecto (recharts, framer-motion, lucide-react, express, mysql2, zod).
|
||||
|
||||
---
|
||||
|
||||
## 9. Padrões a seguir (consistência)
|
||||
|
||||
- **Backend:** Router Express separado por domínio. Service file com queries. Async/await com try/catch.
|
||||
- **Frontend:** Página como componente único com useState/useEffect/useCallback. motion.div com containerVariants/itemVariants. Cards com gradientes e lucide icons.
|
||||
- **Estilo:** Dark theme (bg-zinc-950, borders white/10, text zinc-400/white). Gradientes brand-500/violet-600. Rounded-2xl nos cards.
|
||||
- **Error handling:** try/catch no backend → 500 JSON. Frontend → estado de loading/error com retry.
|
||||
- **Cache:** Backend cache simples com timestamp (60s para MCPs, 300s para n8n).
|
||||
|
||||
---
|
||||
|
||||
## 10. Riscos e mitigações
|
||||
|
||||
| Risco | Mitigação |
|
||||
|-------|-----------|
|
||||
| n8n API key expirar | Documentar no .env.example, alertar na UI |
|
||||
| Paperclip BD inacessível do EasyPanel | Verificar rede Docker Swarm, fallback com dados estáticos |
|
||||
| Gateway health check lento (33 MCPs) | Promise.allSettled com timeout 5s + cache 60s |
|
||||
| Página MCPs demasiado pesada | Ping apenas MCPs enabled (10), disabled mostrados como cinza sem ping |
|
||||
|
||||
---
|
||||
|
||||
## 11. Critérios de aceitação
|
||||
|
||||
- [ ] Todas as 8 páginas carregam sem erros
|
||||
- [ ] Cada API retorna dados reais (não mocks)
|
||||
- [ ] Navegação sidebar mostra todas as 8 páginas
|
||||
- [ ] Mobile responsive (sidebar colapsável funciona com 8 itens)
|
||||
- [ ] Build de produção compila sem erros (`npm run build`)
|
||||
- [ ] Zero vulnerabilidades de segurança (`npm audit`)
|
||||
|
||||
---
|
||||
|
||||
## 12. Fora de escopo
|
||||
|
||||
- Auth OIDC em produção (já implementado, activar separadamente)
|
||||
- LightRAG painel visual com grafo D3.js (fase futura, complexidade alta)
|
||||
- Painel Desk CRM expandido com Kanban (já tem dados no Dashboard principal)
|
||||
- Botões de acção (enable/disable MCP, restart workflow) — apenas visualização
|
||||
- Testes unitários (existem mas não são prioritários para esta expansão)
|
||||
Reference in New Issue
Block a user