docs: BACKEND.md vollständiges DB-Schema mit allen Feldern + jwt_secret in config
This commit is contained in:
parent
48ac353d28
commit
9bebf85a6d
297
docs/BACKEND.md
297
docs/BACKEND.md
@ -82,7 +82,8 @@ listen_addr: ":8443"
|
||||
tls_cert: "certs/server.crt"
|
||||
tls_key: "certs/server.key"
|
||||
api_keys:
|
||||
- "SICHERER_API_KEY"
|
||||
- "SICHERER_API_KEY" # beliebig lang, wird in X-API-Key Header mitgegeben
|
||||
jwt_secret: "LANGER_ZUFAELLIGER_STRING" # fuer Frontend-Login (JWT-Signierung)
|
||||
|
||||
database:
|
||||
host: "127.0.0.1"
|
||||
@ -93,6 +94,12 @@ database:
|
||||
sslmode: "disable" # "require" wenn PG ueber Netz
|
||||
```
|
||||
|
||||
Zufälligen JWT-Secret generieren:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
Alternativ per Environment-Variablen: `RMM_LISTEN_ADDR`, `RMM_TLS_CERT`, `RMM_TLS_KEY`, `RMM_DB_HOST`, `RMM_DB_PASSWORD`.
|
||||
|
||||
## 6. Backend deployen und starten
|
||||
@ -141,27 +148,285 @@ Beim ersten Start:
|
||||
- Retention Policy (90 Tage) und Compression Policy (nach 7 Tagen) werden automatisch gesetzt
|
||||
- Default-Admin `admin` / `YOUR_PASSWORD` wird erstellt
|
||||
|
||||
## Datenbank-Schema (automatisch)
|
||||
## Datenbank-Schema (vollständig)
|
||||
|
||||
| Tabelle | Typ | Beschreibung |
|
||||
|---------|-----|-------------|
|
||||
| `agents` | Relational | Agent-Registry (ID, Name, Hostname, IP, Version, Heartbeat, customer_id, update_requested) |
|
||||
| `system_data` | Relational | Letzte Systemdaten pro Agent (JSONB) |
|
||||
| `config_backups` | Relational | OPNsense Config-Backups (dedupliziert per SHA256) |
|
||||
| `agent_events` | Relational | Online/Offline/Connected Events |
|
||||
| `customers` | Relational | Kundenstammdaten (Nummer, Name) |
|
||||
| `users` | Relational | Benutzer (Username, bcrypt-Hash, Display-Name) |
|
||||
| `agent_firmware` | Relational | Agent-Binaries pro Plattform+Version (BYTEA, SHA256) |
|
||||
| `metrics` | TimescaleDB Hypertable | Time-Series Metriken (CPU, RAM, Disk, Network, Gateway) |
|
||||
Alle Tabellen werden beim Backend-Start **automatisch angelegt** (Auto-Migration inkl. ALTER TABLE für neue Spalten). Kein manuelles Schema-Setup nötig.
|
||||
|
||||
### TimescaleDB Policies
|
||||
---
|
||||
|
||||
- **Retention**: Rohdaten werden nach 90 Tagen automatisch geloescht
|
||||
- **Compression**: Daten aelter als 7 Tage werden komprimiert (segmentby: agent_id+metric)
|
||||
### `agents` — Agent-Registry
|
||||
|
||||
```sql
|
||||
CREATE TABLE agents (
|
||||
id TEXT PRIMARY KEY, -- UUID des Agents (persistent)
|
||||
name TEXT NOT NULL, -- Anzeigename (z.B. "OPN.intra.kunde.de")
|
||||
hostname TEXT NOT NULL, -- Hostname der Firewall
|
||||
ip TEXT NOT NULL, -- IP-Adresse des Agents
|
||||
opnsense_version TEXT NOT NULL DEFAULT '', -- OPNsense-Version (z.B. "25.1.1")
|
||||
agent_version TEXT NOT NULL DEFAULT '', -- Agent-Binary-Version (z.B. "1.0.3")
|
||||
platform TEXT NOT NULL DEFAULT 'freebsd', -- Plattform: "freebsd", "linux"
|
||||
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Erstregistrierung
|
||||
last_heartbeat TIMESTAMPTZ, -- Letzter Heartbeat
|
||||
customer_id INTEGER REFERENCES customers(id), -- Kundenzuordnung (nullable)
|
||||
update_requested BOOLEAN NOT NULL DEFAULT FALSE -- Update-Flag fuer Updater-Daemon
|
||||
);
|
||||
CREATE INDEX idx_agents_customer ON agents(customer_id);
|
||||
```
|
||||
|
||||
**Status-Berechnung** (kein DB-Feld, dynamisch im Backend):
|
||||
|
||||
| Status | Bedingung |
|
||||
|--------|-----------|
|
||||
| `online` | `last_heartbeat` < 2 Minuten |
|
||||
| `stale` | `last_heartbeat` < 5 Minuten |
|
||||
| `offline` | `last_heartbeat` > 5 Minuten |
|
||||
| `unknown` | `last_heartbeat` ist NULL |
|
||||
|
||||
---
|
||||
|
||||
### `customers` — Kundenstammdaten
|
||||
|
||||
```sql
|
||||
CREATE TABLE customers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
number TEXT NOT NULL UNIQUE, -- RMM-Kundennummer (z.B. "K05068")
|
||||
name TEXT NOT NULL, -- Kundenname
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `users` — Benutzer (Frontend-Login)
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL, -- bcrypt-Hash
|
||||
display_name TEXT NOT NULL DEFAULT '',
|
||||
role TEXT NOT NULL DEFAULT 'admin', -- aktuell nur "admin"
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_login TIMESTAMPTZ -- nullable
|
||||
);
|
||||
```
|
||||
|
||||
Standard-Admin wird beim ersten Start angelegt: `admin` / `Start!123` (sofort ändern).
|
||||
|
||||
---
|
||||
|
||||
### `system_data` — Aktueller Systemzustand pro Agent
|
||||
|
||||
```sql
|
||||
CREATE TABLE system_data (
|
||||
agent_id TEXT PRIMARY KEY REFERENCES agents(id) ON DELETE CASCADE,
|
||||
data_json JSONB NOT NULL, -- Vollständiger Heartbeat-Payload des Agents
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `config_backups` — Versionierte OPNsense-Configs
|
||||
|
||||
```sql
|
||||
CREATE TABLE config_backups (
|
||||
id SERIAL PRIMARY KEY,
|
||||
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
||||
hash TEXT NOT NULL, -- SHA256 der config.xml (Deduplizierung)
|
||||
size INTEGER NOT NULL, -- Grösse in Bytes
|
||||
config_xml TEXT NOT NULL, -- Vollständige config.xml
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX idx_config_backups_agent ON config_backups(agent_id, created_at DESC);
|
||||
CREATE INDEX idx_config_backups_hash ON config_backups(agent_id, hash);
|
||||
```
|
||||
|
||||
Deduplizierung: gleicher SHA256 → kein neuer Eintrag.
|
||||
|
||||
---
|
||||
|
||||
### `agent_events` — Online/Offline-Ereignisse
|
||||
|
||||
```sql
|
||||
CREATE TABLE agent_events (
|
||||
id SERIAL PRIMARY KEY,
|
||||
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
||||
event_type TEXT NOT NULL, -- "online", "offline", "stale", "connected", "disconnected"
|
||||
message TEXT, -- optionale Zusatzinfo
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX idx_agent_events_agent ON agent_events(agent_id, created_at DESC);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `agent_firmware` — Agent-Binaries pro Plattform
|
||||
|
||||
```sql
|
||||
CREATE TABLE agent_firmware (
|
||||
version TEXT NOT NULL, -- z.B. "1.0.3"
|
||||
platform TEXT NOT NULL DEFAULT 'freebsd', -- "freebsd", "linux", "windows"
|
||||
hash TEXT NOT NULL, -- SHA256 des Binaries
|
||||
binary_data BYTEA NOT NULL, -- Das Binary selbst
|
||||
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (version, platform)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `tasks` — Task-Scheduler (geplante Aufgaben)
|
||||
|
||||
```sql
|
||||
CREATE TABLE tasks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
||||
name TEXT DEFAULT '', -- Anzeigename der Aufgabe
|
||||
action TEXT NOT NULL, -- "update", "backup", "reboot", ...
|
||||
status TEXT NOT NULL DEFAULT 'scheduled', -- "scheduled","running","completed","failed"
|
||||
schedule_type TEXT DEFAULT 'once', -- "once", "daily", "weekly", "monthly"
|
||||
schedule_time TEXT DEFAULT '02:00', -- Uhrzeit (HH:MM)
|
||||
schedule_weekday INT, -- 0=So, 1=Mo, ... 6=Sa (nur bei "weekly")
|
||||
schedule_monthday INT, -- 1-31 (nur bei "monthly")
|
||||
reboot BOOLEAN DEFAULT FALSE, -- Nach Update neu starten
|
||||
health_check BOOLEAN DEFAULT FALSE, -- Nach Aufgabe Erreichbarkeit prüfen
|
||||
health_check_timeout INT DEFAULT 600, -- Sekunden bis Timeout des Health-Checks
|
||||
active BOOLEAN DEFAULT TRUE, -- Recurring: aktiv/inaktiv
|
||||
scheduled_at TIMESTAMPTZ NOT NULL, -- Nächste/erste Ausführung (once)
|
||||
started_at TIMESTAMPTZ, -- Tatsächlicher Start
|
||||
finished_at TIMESTAMPTZ, -- Ende der Ausführung
|
||||
last_run TIMESTAMPTZ, -- Letzter Lauf (recurring)
|
||||
next_run TIMESTAMPTZ, -- Nächster Lauf (recurring)
|
||||
run_count INT DEFAULT 0, -- Anzahl Ausführungen (recurring)
|
||||
result JSONB, -- Ergebnis-Payload
|
||||
webhook_url TEXT, -- URL für Webhook nach Abschluss
|
||||
webhook_sent BOOLEAN DEFAULT FALSE,
|
||||
webhook_response TEXT, -- HTTP-Response des Webhooks
|
||||
created_by TEXT, -- Username des Erstellers
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX idx_tasks_status_scheduled ON tasks(status, scheduled_at);
|
||||
CREATE INDEX idx_tasks_active_next_run ON tasks(active, next_run) WHERE active = TRUE;
|
||||
```
|
||||
|
||||
**Webhook-Payload** (gesendetes JSON bei `webhook_url` gesetzt):
|
||||
|
||||
```json
|
||||
{
|
||||
"customer_id": "K05068",
|
||||
"hostname": "opnsense.kunde.de",
|
||||
"opnsense_version": "25.1.1",
|
||||
"timestamp": "2026-03-06T08:00:00Z",
|
||||
"trigger": "update_completed",
|
||||
"reachable": true,
|
||||
"update_status": "completed"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `api_keys` — API-Keys (zusätzlich zu config.yaml)
|
||||
|
||||
```sql
|
||||
CREATE TABLE api_keys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_used TIMESTAMPTZ
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `installers` — OPNsense Plugin-Pakete
|
||||
|
||||
```sql
|
||||
CREATE TABLE installers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
platform TEXT NOT NULL UNIQUE, -- "freebsd", "linux"
|
||||
filename TEXT NOT NULL,
|
||||
data BYTEA NOT NULL, -- ZIP-Paket (install.sh + Plugin)
|
||||
sha256 TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `audit_log` — Audit-Protokoll
|
||||
|
||||
```sql
|
||||
CREATE TABLE audit_log (
|
||||
id SERIAL PRIMARY KEY,
|
||||
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
user_name TEXT NOT NULL,
|
||||
action TEXT NOT NULL, -- z.B. "login", "delete_agent", "update_customer"
|
||||
target_type TEXT, -- z.B. "agent", "customer", "user"
|
||||
target_id TEXT,
|
||||
target_name TEXT,
|
||||
details TEXT,
|
||||
source_ip TEXT
|
||||
);
|
||||
CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp DESC);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `system_settings` — Backend-Einstellungen (Key/Value)
|
||||
|
||||
```sql
|
||||
CREATE TABLE system_settings (
|
||||
key TEXT PRIMARY KEY, -- "backend_url_internal", "backend_url_external", "api_key"
|
||||
value TEXT NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `metrics` — TimescaleDB Hypertable (Zeitreihen)
|
||||
|
||||
```sql
|
||||
CREATE TABLE metrics (
|
||||
time TIMESTAMPTZ NOT NULL,
|
||||
agent_id TEXT NOT NULL,
|
||||
metric TEXT NOT NULL, -- Name der Metrik
|
||||
value DOUBLE PRECISION NOT NULL,
|
||||
tags JSONB -- z.B. {"interface":"igb0"}
|
||||
);
|
||||
-- In Hypertable umwandeln:
|
||||
SELECT create_hypertable('metrics', 'time', if_not_exists => TRUE);
|
||||
CREATE INDEX idx_metrics_agent_metric ON metrics(agent_id, metric, time DESC);
|
||||
```
|
||||
|
||||
**Verfügbare Metriken:**
|
||||
|
||||
| Metrik | Einheit | Tags |
|
||||
|--------|---------|------|
|
||||
| `cpu_usage` | Prozent | — |
|
||||
| `memory_used_percent` | Prozent | — |
|
||||
| `memory_used_bytes` | Bytes | — |
|
||||
| `memory_total_bytes` | Bytes | — |
|
||||
| `uptime_seconds` | Sekunden | — |
|
||||
| `disk_used_percent` | Prozent | `{"mountpoint":"/","dataset":"zroot/ROOT"}` |
|
||||
| `disk_used_bytes` | Bytes | `{"mountpoint":"/"}` |
|
||||
| `interface_rx_bytes` | Bytes | `{"interface":"igb0"}` |
|
||||
| `interface_tx_bytes` | Bytes | `{"interface":"igb0"}` |
|
||||
| `gateway_rtt_ms` | Millisekunden | `{"gateway":"WAN_GW"}` |
|
||||
| `gateway_loss_percent` | Prozent | `{"gateway":"WAN_GW"}` |
|
||||
|
||||
**TimescaleDB Policies** (automatisch gesetzt):
|
||||
- **Retention**: Rohdaten nach 90 Tagen gelöscht
|
||||
- **Compression**: Daten älter als 7 Tage komprimiert (`segmentby: agent_id, metric`)
|
||||
|
||||
---
|
||||
|
||||
### DB-Funktionen
|
||||
|
||||
- `GetAgentByName`: Sucht Agent nach Name — verwendet fuer Pre-Registration Matching bei Agent-Registrierung
|
||||
- **`GetAgentByName`**: Sucht Agent nach Name — für Pre-Registration Matching (Agent registriert sich, Backend findet vorregistrierten Platzhalter mit `hostname="(ausstehend)"`).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user