# RMM Frontend

React + Vite + TailwindCSS Web-Frontend fuer das OPNsense RMM System.

## Eckdaten

| | |
|---|---|
| **Server** | your-backend (Debian 13, Nginx) |
| **Tech** | React 18, Vite, TailwindCSS, Recharts, Zustand, lucide-react |
| **Theme** | Dark mit Orange-Akzent, komplett deutsch |
| **Auth** | JWT Login (8h Token) |
| **Default-Login** | `admin` / `YOUR_PASSWORD` |
| **Backend** | https://your-backend:8443 |

## Seiten

| Seite | Route | Beschreibung |
|-------|-------|-------------|
| Login | `/login` | JWT Login |
| Dashboard | `/` | Status-Kacheln, Agent-Liste, AgentPanel per Klick |
| Firewalls | `/agents` | Suchbare Tabelle, AgentPanel mit Tabs, Hinzufuegen/Loeschen |
| Tunnel | `/tunnels` | Globale Tunnel-Uebersicht ueber alle Firewalls |
| Firmware | `/firmware` | Multi-Plattform Upload, Agent-Update-Trigger |
| Kunden | `/customers` | CRUD Kundenverwaltung |
| Einstellungen | `/settings` | Benutzerverwaltung, Passwoerter aendern |

## AgentPanel Tabs

Das Side-Panel oeffnet sich per Klick auf eine Firewall (Dashboard oder Firewalls-Seite):

| Tab | Inhalt |
|-----|--------|
| Uebersicht | Hardware, OS, Uptime, CPU/RAM, Lizenz (Business Edition) |
| Interfaces | Netzwerk-Interfaces mit IP, MAC, Status, RX/TX |
| Dienste | Laufende Services mit Status-Badge |
| Tunnel | Quick-Buttons (WebGUI, SSH, Custom), aktive Tunnel |
| VPN | WireGuard-Instanzen mit Transfer-Statistiken |
| WireGuard | Peer-Management (CRUD), Client-Config mit Copy-Button |
| Routen | Routing-Tabelle |
| DHCP | Aktive Leases mit Suche (IP, MAC, Hostname) |
| Zertifikate | Karten-Layout mit Ablaufdatum und Fortschrittsbalken |
| Backups | Config-Backup erstellen, Liste, Download als XML |
| Agent | Version, Agent-ID, Update-Button, Remote-Befehle |

---

## API Endpoints

Alle Aufrufe gehen ueber den API Client (`src/api/client.js`).
Base-URL wird ueber `VITE_API_URL` oder Nginx-Proxy konfiguriert.
Auth: JWT Bearer Token im `Authorization` Header.

### Authentifizierung

```
POST   /api/v1/auth/login          Login (username, password) → JWT Token
GET    /api/v1/auth/me             Eigene Benutzerdaten
```

**Beispiel:**
```bash
# Login
curl -sk -X POST https://your-backend:8443/api/v1/auth/login \
  -d '{"username":"admin","password":"YOUR_PASSWORD"}'
# → {"token":"eyJhbG...","user":{"id":1,"username":"admin"}}

# Eigene Daten
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/auth/me
```

### Agents (Firewalls)

```
GET    /api/v1/agents              Alle Agents auflisten
GET    /api/v1/agents/{id}         Agent + Systemdaten abrufen
DELETE /api/v1/agents/{id}         Agent loeschen
POST   /api/v1/agents              Firewall pre-registrieren
GET    /api/v1/agents/{id}/events  Agent-Events (limit=N)
PUT    /api/v1/agents/{id}/customer  Kunden zuordnen
DELETE /api/v1/agents/{id}/customer  Kundenzuordnung entfernen
```

**Beispiele:**
```bash
# Alle Agents
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/agents

# Agent-Details mit Systemdaten
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee

# Firewall pre-registrieren
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents \
  -d '{"name":"OPN.intra.kunde.de","customer_id":1}'

# Agent loeschen
curl -sk -H "Authorization: Bearer <TOKEN>" -X DELETE \
  https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887

# Events (letzte 50)
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/events?limit=50"

# Kunden zuordnen
curl -sk -H "Authorization: Bearer <TOKEN>" -X PUT \
  https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/customer \
  -d '{"customer_id":1}'
```

### Kunden (Customers)

```
GET    /api/v1/customers           Alle Kunden
POST   /api/v1/customers           Neuen Kunden anlegen
PUT    /api/v1/customers/{id}      Kunden aktualisieren
DELETE /api/v1/customers/{id}      Kunden loeschen
GET    /api/v1/customers/{id}/agents  Agents eines Kunden
```

**Beispiele:**
```bash
# Kunden anlegen
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/customers \
  -d '{"number":"K05001","name":"Beispiel GmbH"}'

# Kunden aktualisieren
curl -sk -H "Authorization: Bearer <TOKEN>" -X PUT \
  https://your-backend:8443/api/v1/customers/1 \
  -d '{"number":"K05001","name":"Beispiel AG"}'

# Agents eines Kunden
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/customers/1/agents
```

### Benutzer (Users)

```
GET    /api/v1/users               Alle Benutzer
POST   /api/v1/users               Neuen Benutzer anlegen
PUT    /api/v1/users/{id}/password  Passwort aendern (min. 6 Zeichen)
DELETE /api/v1/users/{id}          Benutzer loeschen
```

**Beispiele:**
```bash
# Benutzer anlegen
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/users \
  -d '{"username":"operator","password":"Sicher!123"}'

# Passwort aendern
curl -sk -H "Authorization: Bearer <TOKEN>" -X PUT \
  https://your-backend:8443/api/v1/users/1/password \
  -d '{"password":"NeuesPasswort!123"}'
```

### Metriken (TimescaleDB)

```
GET    /api/v1/agents/{id}/metrics          Rohe Metriken
GET    /api/v1/agents/{id}/metrics/summary  Aggregierte Metriken
```

Verfuegbare Metriken: `cpu_usage`, `memory_used_percent`, `memory_used_bytes`, `memory_total_bytes`, `uptime_seconds`, `disk_used_percent`, `disk_used_bytes`, `interface_rx_bytes`, `interface_tx_bytes`, `gateway_rtt_ms`, `gateway_loss_percent`

**Beispiele:**
```bash
# CPU letzte 24h
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd.../metrics?metric=cpu_usage"

# RAM mit Zeitraum
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd.../metrics?metric=memory_used_percent&from=2026-03-01T00:00:00Z&to=2026-03-01T23:59:59Z"

# 5-Minuten-Durchschnitte
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd.../metrics/summary?metric=cpu_usage&bucket=5+minutes"
```

### Config-Backups

```
POST   /api/v1/agents/{id}/backup           Backup jetzt ausloesen
GET    /api/v1/agents/{id}/backups           Alle Backups auflisten
GET    /api/v1/agents/{id}/backups/{id}      Backup herunterladen (?format=xml)
GET    /api/v1/agents/{id}/backups/latest    Neuestes Backup
DELETE /api/v1/agents/{id}/backups/{id}      Backup loeschen
GET    /api/v1/agents/{id}/backups/diff      Diff (?a=ID&b=ID)
```

**Beispiele:**
```bash
# Backup ausloesen
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/6beb8dfd.../backup

# Backups auflisten
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/agents/6beb8dfd.../backups

# Als XML herunterladen
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd.../backups/latest?format=xml" \
  -o config-backup.xml

# Diff zwischen zwei Backups
curl -sk -H "Authorization: Bearer <TOKEN>" \
  "https://your-backend:8443/api/v1/agents/6beb8dfd.../backups/diff?a=1&b=3"
```

### Tunnel

```
POST   /api/v1/agents/{id}/tunnel           Tunnel oeffnen
GET    /api/v1/agents/{id}/tunnels          Aktive Tunnel auflisten
DELETE /api/v1/agents/{id}/tunnel/{tid}     Tunnel schliessen
```

**Beispiele:**
```bash
# SSH-Tunnel
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../tunnel \
  -d '{"target_host":"127.0.0.1","target_port":22}'
# → {"tunnel_id":"abc123","proxy_port":10000,...}
# Dann: ssh -p 10000 root@your-backend

# WebGUI-Tunnel (OPNsense Port 4444)
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../tunnel \
  -d '{"target_host":"127.0.0.1","target_port":4444}'
# Im Browser: https://your-backend:10001/

# PVE WebGUI-Tunnel (Proxmox Port 8006)
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/3f0a83a2.../tunnel \
  -d '{"target_host":"127.0.0.1","target_port":8006}'

# Aktive Tunnel
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/agents/e92e87a6.../tunnels

# Tunnel schliessen
curl -sk -H "Authorization: Bearer <TOKEN>" -X DELETE \
  https://your-backend:8443/api/v1/agents/e92e87a6.../tunnel/abc123
```

### WireGuard Peer-Management

```
GET    /api/v1/agents/{id}/wireguard/peers        Alle Peers auflisten
POST   /api/v1/agents/{id}/wireguard/peers        Neuen Peer anlegen
DELETE /api/v1/agents/{id}/wireguard/peers/{uuid}  Peer loeschen
```

**Beispiele:**
```bash
# Peer anlegen (Auto: Keypair, naechste freie IP, Endpoint)
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/6beb8dfd.../wireguard/peers \
  -d '{"name":"VPN_MUELLER","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}'
# → {peer_config: "[Interface]\nPrivateKey=...\n[Peer]\n...", ...}

# Alle Peers
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/agents/6beb8dfd.../wireguard/peers

# Peer loeschen
curl -sk -H "Authorization: Bearer <TOKEN>" -X DELETE \
  https://your-backend:8443/api/v1/agents/6beb8dfd.../wireguard/peers/89c10e2d-148e-11f1-a7af-7c5a1c6c7b73
```

### Remote-Befehle (Exec)

```
POST   /api/v1/agents/{id}/exec    Befehl ausfuehren
```

**Beispiel:**
```bash
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../exec \
  -d '{"command":"uptime","timeout":30}'
# → {"data":{"output":"10:30AM  up 45 days, ..."}, "status":"ok"}
```

### Updates

```
POST   /api/v1/agents/{id}/update-check   Verfuegbare Updates pruefen
POST   /api/v1/agents/{id}/update          Normales Update (Core + Packages)
POST   /api/v1/agents/{id}/major-update    Major-Upgrade (2-Phasen)
POST   /api/v1/agents/{id}/reboot          Reboot
```

**Beispiele:**
```bash
# Update-Check
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../update-check

# Update mit Reboot
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../update \
  -d '{"reboot":true}'

# Major-Update Phase 1
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../major-update \
  -d '{"version":"26.1","reboot":true}'
```

### Firmware / Agent-Update

```
GET    /api/v1/firmware                        Alle Firmware-Versionen
POST   /api/v1/firmware/upload?version=X&platform=Y  Binary hochladen
GET    /api/v1/firmware/download?platform=Y    Binary herunterladen (Updater)
POST   /api/v1/agents/{id}/request-update      Update-Flag setzen
DELETE /api/v1/agents/{id}/request-update      Update-Flag zuruecksetzen
POST   /api/v1/agents/request-update-all       Alle Agents updaten
```

**Beispiele:**
```bash
# Firmware-Info
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/firmware

# Firmware hochladen (FreeBSD)
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  "https://your-backend:8443/api/v1/firmware/upload?version=1.0.3&platform=freebsd" \
  --data-binary @build/rmm-agent

# Firmware hochladen (Linux)
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  "https://your-backend:8443/api/v1/firmware/upload?version=1.0.1&platform=linux" \
  --data-binary @build/rmm-agent-linux

# Update fuer einzelnen Agent anfordern
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/e92e87a6.../request-update

# Update fuer alle Agents
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
  https://your-backend:8443/api/v1/agents/request-update-all
```

### Hub-Status

```
GET    /api/v1/hub/status          WebSocket Hub Status
```

**Beispiel:**
```bash
curl -sk -H "Authorization: Bearer <TOKEN>" \
  https://your-backend:8443/api/v1/hub/status
# → {"connected_agents":3,"active_tunnels":1}
```

---

## Build & Deploy

```bash
cd frontend
npm install
npm run build                                              # ~330 KB JS, ~32 KB CSS

# Deploy
ssh root@your-backend 'rm -rf /var/www/html/assets/*'     # Alte Hashes loeschen!
scp -r dist/* root@your-backend:/var/www/html/
```

**Wichtig:** Vor Deploy immer `assets/` loeschen — Vite generiert Hash-basierte Dateinamen, alte Dateien bleiben sonst auf dem Server.

## Entwicklung

```bash
cd frontend
npm run dev     # Startet Vite Dev-Server mit Proxy zu Backend
```

Vite Proxy-Config (`vite.config.js`): `/api/` wird auf `https://your-backend:8443` weitergeleitet.

## Dateistruktur

```
frontend/
├── src/
│   ├── App.jsx              # Router + ProtectedRoute
│   ├── main.jsx             # Entry Point
│   ├── index.css            # TailwindCSS + Custom Styles
│   ├── api/client.js        # API Client (alle Endpoints)
│   ├── stores/auth.js       # Zustand Auth Store (JWT Token)
│   ├── layouts/AppLayout.jsx # Sidebar Navigation + Outlet
│   ├── components/
│   │   ├── AgentPanel.jsx   # Side Panel mit 11 Tabs
│   │   └── StatusBadge.jsx  # Online/Offline/Stale Badge
│   └── pages/
│       ├── Dashboard.jsx    # Status-Kacheln + Agent-Liste
│       ├── Agents.jsx       # Firewall-Tabelle + Pre-Registration
│       ├── AgentDetail.jsx  # Detail-Ansicht (full page, legacy)
│       ├── Tunnels.jsx      # Globale Tunnel-Uebersicht
│       ├── Firmware.jsx     # Multi-Plattform Firmware + Updates
│       ├── Customers.jsx    # Kunden CRUD
│       ├── SettingsPage.jsx # User-Management + Passwort
│       └── Login.jsx        # JWT Login
├── vite.config.js           # Vite Config mit API Proxy
├── tailwind.config.js
└── package.json
```
