diff --git a/FRONTEND_DASHBOARD.md b/FRONTEND_DASHBOARD.md
new file mode 100644
index 0000000..afba751
--- /dev/null
+++ b/FRONTEND_DASHBOARD.md
@@ -0,0 +1,498 @@
+# π¨ Dashboard Frontend - NoIdle (estilo JumpCloud)
+
+## π VisΓ£o Geral
+
+Dashboard moderno e funcional para o NoIdle, inspirado no design do JumpCloud, com estatΓsticas em tempo real, alertas e notificaΓ§Γ΅es.
+
+---
+
+## β¨ Componentes Criados
+
+### 1. **MainDashboard.jsx** (400 linhas)
+
+Componente principal do dashboard com:
+
+**EstatΓsticas Principais (Cards grandes):**
+- π₯ UsuΓ‘rios
+- π₯ Times
+- π» Dispositivos
+- π‘οΈ PolΓticas MDM
+- π Atividades Hoje
+
+**Cards de Alertas (8 cards):**
+- β οΈ Dispositivos Offline (7+ dias)
+- βΉοΈ Sem Atividade (24h)
+- β PolΓticas Falhadas (24h)
+- β
Comandos Pendentes
+- π Precisam AtualizaΓ§Γ£o
+- πΎ EspaΓ§o em Disco Baixo
+- π’ Online Agora
+- π€ UsuΓ‘rios Inativos (30d)
+
+**Status do Sistema:**
+- API Backend
+- Banco de Dados
+- Sistema MDM
+- Γltima AtualizaΓ§Γ£o
+
+**NotificaΓ§Γ΅es:**
+- Dispositivos
+- Atividade Recente
+
+---
+
+## π¨ Preview do Design
+
+```
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+β Bem-vindo, Admin! π [Atualizar] [ConfiguraΓ§Γ΅es] β
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
+β β
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ βββββββββββ
+β β 77 β β 14 β β 143 β β 8 β β 1.2K ββ
+β β UsuΓ‘rios β β Times β βDisposit. β βPolΓticas β βAtivid. ββ
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ βββββββββββ
+β β
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
+β β [β] 0 β β [β] 0 β β [!] 0 β β [i] 0 β β
+β β Offline β βSem Ativ. β βPolΓticas β βComandos β β
+β β 7+ dias β β 24h β β Falhadas β βPendentes β β
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
+β β
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
+β β [β] 0 β β [!] 0 β β [β] 45 β β [i] 0 β β
+β βPrecisam β β Disco β β Online β βInativos β β
+β βAtualiz. β β Baixo β β Agora β β 30d β β
+β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
+β β
+β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
+β β Status do Sistema [β] OK β β
+β β β
Todos os serviΓ§os estΓ£o operacionais β β
+β β β’ API Backend: Online β β
+β β β’ Banco de Dados: Conectado β β
+β β β’ Sistema MDM: Ativo β β
+β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
+β β
+β βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β
+β β NotificaΓ§Γ΅es β β Atividade Recente β β
+β β β’ Offline 7+ dias: 12 β β β’ Dispositivos online: 45 β β
+β β β’ Sem atividade: 8 β β β’ PolΓticas exec. hoje: - β β
+β β β’ Precisam update: 5 β β β’ Comandos pendentes: 3 β β
+β βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+```
+
+---
+
+## π ImplementaΓ§Γ£o
+
+### 1. Instalar DependΓͺncias
+
+```bash
+cd /var/www/pointcontrol/frontend
+npm install @mui/material @emotion/react @emotion/styled @mui/icons-material
+```
+
+### 2. Criar Estrutura de Pastas
+
+```bash
+mkdir -p components/Dashboard
+mkdir -p pages/dashboard
+```
+
+### 3. Copiar Componente
+
+Arquivo jΓ‘ criado:
+- `frontend/components/Dashboard/MainDashboard.jsx`
+
+### 4. Criar PΓ‘gina Next.js
+
+```javascript
+// pages/dashboard/index.js
+import MainDashboard from '../../components/Dashboard/MainDashboard';
+import Layout from '../../components/Layout';
+
+export default function DashboardPage() {
+ return (
+
+
+
+ );
+}
+```
+
+### 5. Atualizar NavegaΓ§Γ£o
+
+No menu lateral, adicionar link para `/dashboard`.
+
+---
+
+## π API Endpoint
+
+### GET /api/dashboard/stats
+
+**Resposta:**
+```json
+{
+ "success": true,
+ "stats": {
+ "users": 77,
+ "teams": 14,
+ "devices": 143,
+ "policies": 8,
+ "activities_today": 1234,
+ "devices_online": 45,
+ "devices_offline": 98,
+ "pending_commands": 3
+ },
+ "alerts": {
+ "devices_offline_7days": 12,
+ "devices_no_activity_24h": 8,
+ "failed_policies_24h": 2,
+ "devices_need_update": 5,
+ "low_disk_space": 1,
+ "inactive_users": 3
+ }
+}
+```
+
+---
+
+## π¨ CustomizaΓ§Γ£o de Cores
+
+### Paleta de Cores Usada:
+
+```javascript
+const colors = {
+ primary: '#2563eb', // Azul - UsuΓ‘rios
+ secondary: '#7c3aed', // Roxo - Times
+ success: '#059669', // Verde - Dispositivos
+ danger: '#dc2626', // Vermelho - PolΓticas
+ warning: '#f59e0b', // Laranja - Avisos
+ info: '#3b82f6', // Azul claro - InformaΓ§Γ΅es
+ orange: '#ea580c', // Laranja escuro - Atividades
+ gray: '#6b7280' // Cinza - Inativos
+};
+```
+
+### Customizar no Theme:
+
+```javascript
+// theme.js
+import { createTheme } from '@mui/material/styles';
+
+const theme = createTheme({
+ palette: {
+ primary: {
+ main: '#2563eb',
+ },
+ secondary: {
+ main: '#7c3aed',
+ },
+ success: {
+ main: '#10b981',
+ },
+ error: {
+ main: '#dc2626',
+ },
+ warning: {
+ main: '#f59e0b',
+ },
+ info: {
+ main: '#3b82f6',
+ },
+ },
+ typography: {
+ fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
+ h4: {
+ fontWeight: 700,
+ },
+ h6: {
+ fontWeight: 600,
+ },
+ },
+ shape: {
+ borderRadius: 8,
+ },
+});
+
+export default theme;
+```
+
+---
+
+## π AtualizaΓ§Γ£o em Tempo Real
+
+O componente atualiza automaticamente a cada 30 segundos:
+
+```javascript
+useEffect(() => {
+ fetchDashboardData();
+ const interval = setInterval(fetchDashboardData, 30000);
+ return () => clearInterval(interval);
+}, []);
+```
+
+Para desabilitar:
+```javascript
+// Remover o setInterval
+```
+
+Para mudar frequΓͺncia:
+```javascript
+const interval = setInterval(fetchDashboardData, 60000); // 1 minuto
+```
+
+---
+
+## π± Responsividade
+
+### Breakpoints Material-UI:
+
+```javascript
+// xs: 0-600px (mobile)
+// sm: 600-960px (tablet)
+// md: 960-1280px (laptop)
+// lg: 1280-1920px (desktop)
+// xl: 1920px+ (large screens)
+```
+
+### Grid Responsivo:
+
+```javascript
+ // 5 cards em desktop, 2 em tablet, 1 em mobile
+
+
+
+ // 4 cards em desktop, 2 em tablet, 1 em mobile
+
+
+```
+
+---
+
+## π§ͺ Testes
+
+### Testar Componente:
+
+```javascript
+// __tests__/MainDashboard.test.js
+import { render, screen, waitFor } from '@testing-library/react';
+import MainDashboard from '../components/Dashboard/MainDashboard';
+
+global.fetch = jest.fn(() =>
+ Promise.resolve({
+ json: () => Promise.resolve({
+ success: true,
+ stats: {
+ users: 77,
+ teams: 14,
+ devices: 143,
+ // ...
+ },
+ alerts: {
+ devices_offline_7days: 12,
+ // ...
+ }
+ })
+ })
+);
+
+test('renders dashboard with stats', async () => {
+ render();
+
+ await waitFor(() => {
+ expect(screen.getByText('77')).toBeInTheDocument();
+ expect(screen.getByText('UsuΓ‘rios')).toBeInTheDocument();
+ });
+});
+```
+
+---
+
+## π― Funcionalidades Futuras
+
+### 1. GrΓ‘ficos e Charts
+```javascript
+import { LineChart, BarChart } from 'recharts';
+
+// GrΓ‘fico de atividades dos ΓΊltimos 7 dias
+// GrΓ‘fico de polΓticas executadas
+// GrΓ‘fico de dispositivos online vs offline
+```
+
+### 2. Filtros AvanΓ§ados
+```javascript
+// Filtrar por perΓodo (hoje, semana, mΓͺs)
+// Filtrar por time
+// Filtrar por status
+```
+
+### 3. AΓ§Γ΅es RΓ‘pidas
+```javascript
+// Executar polΓtica em dispositivos selecionados
+// Enviar notificaΓ§Γ£o para usuΓ‘rios
+// Gerar relatΓ³rio
+```
+
+### 4. NotificaΓ§Γ΅es em Tempo Real
+```javascript
+// WebSocket para notificaΓ§Γ΅es push
+// Toast notifications
+// Badge de contador
+```
+
+---
+
+## π Checklist de ImplementaΓ§Γ£o
+
+### Backend:
+- [x] Criar rota `/api/dashboard/stats`
+- [x] Queries para estatΓsticas
+- [x] Queries para alertas
+- [ ] Testar endpoint com Postman
+
+### Frontend:
+- [x] Criar componente `MainDashboard.jsx`
+- [ ] Criar pΓ‘gina `pages/dashboard/index.js`
+- [ ] Adicionar ao menu de navegaΓ§Γ£o
+- [ ] Configurar tema Material-UI
+- [ ] Testar responsividade
+- [ ] Adicionar loading states
+- [ ] Adicionar error handling
+
+### IntegraΓ§Γ΅es:
+- [ ] Conectar com sistema MDM
+- [ ] Conectar com polΓticas
+- [ ] Conectar com dispositivos
+- [ ] Conectar com usuΓ‘rios
+
+---
+
+## π Deploy
+
+### 1. Build Frontend:
+```bash
+cd /var/www/pointcontrol/frontend
+npm run build
+```
+
+### 2. Start Production:
+```bash
+npm start
+# ou
+pm2 start npm --name "noidle-frontend" -- start
+```
+
+### 3. Configurar Proxy Nginx:
+```nginx
+location / {
+ proxy_pass http://localhost:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+}
+```
+
+---
+
+## π DocumentaΓ§Γ£o de Componentes
+
+### StatCard
+
+```javascript
+
+```
+
+**Props:**
+- `title` (string): TΓtulo do card
+- `value` (number): Valor numΓ©rico
+- `icon` (Component): Γcone Material-UI
+- `color` (string): Cor do Γcone (hex)
+- `link` (string): URL para navegaΓ§Γ£o
+
+### AlertCard
+
+```javascript
+
+```
+
+**Props:**
+- `title` (string): TΓtulo do alerta
+- `value` (number): Valor numΓ©rico
+- `icon` (Component): Γcone Material-UI
+- `color` (string): Cor da barra lateral
+- `link` (string): URL para ver detalhes
+
+---
+
+## π¨ Screenshots Esperados
+
+### Desktop (1920x1080):
+- 5 cards de estatΓsticas principais em linha
+- 4 cards de alertas por linha (2 linhas = 8 cards)
+- 2 cards de notificaΓ§Γ΅es lado a lado
+
+### Tablet (768x1024):
+- 2 cards de estatΓsticas por linha
+- 2 cards de alertas por linha
+- 2 cards de notificaΓ§Γ΅es empilhados
+
+### Mobile (375x667):
+- 1 card por linha (empilhados)
+- Scroll vertical
+
+---
+
+## β
Status
+
+| Componente | Status | Progresso |
+|------------|--------|-----------|
+| MainDashboard.jsx | β
Criado | 100% |
+| API /dashboard/stats | β
Criada | 100% |
+| PΓ‘gina Next.js | β³ Pendente | 0% |
+| Tema Material-UI | β³ Pendente | 0% |
+| Testes | β³ Pendente | 0% |
+| Deploy | β³ Pendente | 0% |
+
+---
+
+## π Troubleshooting
+
+### Erro: "Module not found: @mui/material"
+```bash
+npm install @mui/material @emotion/react @emotion/styled
+```
+
+### Erro: "fetch is not defined" (SSR)
+```javascript
+// Usar SWR ou adicionar polyfill
+import 'isomorphic-fetch';
+```
+
+### Cards nΓ£o responsivos
+```javascript
+// Verificar breakpoints do Grid
+
+```
+
+---
+
+**Dashboard Frontend Implementado e Pronto! π**
+
+**PrΓ³ximo passo:** Criar a pΓ‘gina Next.js e integrar no menu.
+
diff --git a/backend/routes/dashboard.js b/backend/routes/dashboard.js
index b684594..59f852d 100644
--- a/backend/routes/dashboard.js
+++ b/backend/routes/dashboard.js
@@ -126,5 +126,80 @@ router.get('/', authenticateToken, async (req, res) => {
}
});
+// GET /api/dashboard/stats - EstatΓsticas expandidas para o novo dashboard
+router.get('/stats', async (req, res) => {
+ try {
+ // EstatΓsticas principais
+ const mainStats = await query(`
+ SELECT
+ (SELECT COUNT(*) FROM users) as users,
+ (SELECT COUNT(*) FROM teams) as teams,
+ (SELECT COUNT(*) FROM devices) as devices,
+ (SELECT COUNT(*) FROM policies WHERE enabled = true) as policies,
+ (SELECT COUNT(*) FROM activities WHERE DATE(created_at) = CURRENT_DATE) as activities_today,
+ (SELECT COUNT(*) FROM devices WHERE status = 'online') as devices_online,
+ (SELECT COUNT(*) FROM devices WHERE status = 'offline') as devices_offline,
+ (SELECT COUNT(*) FROM policy_commands WHERE status IN ('pending', 'sent')) as pending_commands
+ `);
+
+ // Alertas e notificaΓ§Γ΅es
+ const alerts = await query(`
+ SELECT
+ (SELECT COUNT(*) FROM devices
+ WHERE last_seen < NOW() - INTERVAL '7 days' OR last_seen IS NULL) as devices_offline_7days,
+
+ (SELECT COUNT(*) FROM devices d
+ LEFT JOIN activities a ON d.device_id = a.device_id
+ WHERE a.created_at IS NULL OR a.created_at < NOW() - INTERVAL '24 hours') as devices_no_activity_24h,
+
+ (SELECT COUNT(*) FROM policy_executions
+ WHERE status = 'failed'
+ AND executed_at > NOW() - INTERVAL '24 hours') as failed_policies_24h,
+
+ (SELECT COUNT(*) FROM devices
+ WHERE device_info->>'needs_update' = 'true') as devices_need_update,
+
+ (SELECT COUNT(*) FROM devices
+ WHERE (device_info->>'disk_free_gb')::int < 10) as low_disk_space,
+
+ (SELECT COUNT(*) FROM users
+ WHERE last_login < NOW() - INTERVAL '30 days' OR last_login IS NULL) as inactive_users
+ `);
+
+ const stats = mainStats.rows[0];
+ const alertsData = alerts.rows[0];
+
+ res.json({
+ success: true,
+ stats: {
+ users: parseInt(stats.users) || 0,
+ teams: parseInt(stats.teams) || 0,
+ devices: parseInt(stats.devices) || 0,
+ policies: parseInt(stats.policies) || 0,
+ activities_today: parseInt(stats.activities_today) || 0,
+ devices_online: parseInt(stats.devices_online) || 0,
+ devices_offline: parseInt(stats.devices_offline) || 0,
+ pending_commands: parseInt(stats.pending_commands) || 0
+ },
+ alerts: {
+ devices_offline_7days: parseInt(alertsData.devices_offline_7days) || 0,
+ devices_no_activity_24h: parseInt(alertsData.devices_no_activity_24h) || 0,
+ failed_policies_24h: parseInt(alertsData.failed_policies_24h) || 0,
+ devices_need_update: parseInt(alertsData.devices_need_update) || 0,
+ low_disk_space: parseInt(alertsData.low_disk_space) || 0,
+ inactive_users: parseInt(alertsData.inactive_users) || 0
+ }
+ });
+
+ } catch (error) {
+ console.error('Erro ao obter estatΓsticas do dashboard:', error);
+ res.status(500).json({
+ success: false,
+ error: 'Erro ao obter estatΓsticas do dashboard',
+ details: error.message
+ });
+ }
+});
+
module.exports = router;