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>
15 KiB
title, date, type, status, desk_project, tags
| title | date | type | status | desk_project | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| SPEC — Expansão DashDescomplicar Q2 2026 | 2026-04-06 | spec | active | 65 |
|
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
- Expandir o dashboard de 3 para 8 páginas
- Cada novo painel usa dados reais via API (gateway MCPs, BD MySQL, APIs HTTP)
- Manter a consistência visual (dark theme, Tailwind, framer-motion, lucide-react)
- Zero dependências novas — usar as existentes (recharts, framer-motion, lucide)
- 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>/mcpcom Bearer token (resposta 200 = online) - Lista estática dos MCPs com metadados (nome, porta, categoria, enabled/disabled)
Dados retornados:
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:
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:
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_NAMEPAPERCLIP_DB_USERPAPERCLIP_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:
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:
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
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
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
# 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)