docs initial

This commit is contained in:
2025-11-23 19:19:41 +00:00
parent adbf38c655
commit 9b25cb807a
14 changed files with 665 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
# Architektur
StackPulse folgt einer klassischen Client/Server-Architektur, bei der das Backend den Single-Source-of-Truth darstellt und das Frontend ausschließlich über wohldefinierte REST- und Socket.IO-Schnittstellen kommuniziert.
```text
┌────────────┐ HTTPS + WebSocket ┌───────────────┐ HTTPS ┌────────────────┐
│ Frontend │ ─────────────────────────▶ │ Backend │ ───────────────▶ │ Portainer API │
│ (React) │ ◀───── Auth-Cookie + JSON ─ │ (Express) │ ◀─────────────── │ Business Ed. │
└────────────┘ Redeploy Events └───────────────┘ (Axios Proxy) └────────────────┘
SQLite Datenbank
```
## Hauptschichten
- **Frontend** (Vite + Material Tailwind): stellt alle Views, Formulare, Tabellen und Echtzeit-Widgets bereit. Die `AuthProvider`-Komponente verwaltet Session, Permissions und Socket-Verbindungen.
- **Backend** (Express + better-sqlite3): aggregiert Daten aus Portainer, persistiert Benutzer/Gruppen/Logs, verwaltet Sessions und stößt Redeploy- sowie Wartungsprozesse an.
- **Persistenz** (SQLite): Datei `backend/data/stackpulse.db`, WAL-Modus aktiviert. Tabellen umfassen u. a. `users`, `groups`, `permissions`, `servers`, `server_api_keys`, `event_logs`, `settings` sowie Hilfstabellen für Tokens und Sicherheitspassphrasen.
## Datenflüsse
1. **Setup-Phase**: `/api/setup/*` nimmt Serverdaten entgegen, verschlüsselt API-Keys (`aes-256-gcm` via `PORTAINER_API_SECRET`) und erstellt Einträge in `servers`/`server_api_keys`.
2. **Authentication**: `/api/auth/login` erstellt Sessions (JWT-ähnliche Tokens in Cookies), `AuthProvider` ruft `/api/auth/session` zyklisch ab und speichert Berechtigungen.
3. **Stack-Übersicht**: Frontend ruft `/api/stacks` auf. Das Backend proxyt `Portainer /api/endpoints/:id/docker/stacks`, ergänzt Caching, interne Metadaten und liefert Redeploy-Status.
4. **Redeploy**: UI stößt `/api/stacks/:id/redeploy`, `/api/stacks/redeploy-selection` oder `/api/stacks/redeploy-all` an. Das Backend ruft Portainer-Endpoints, protokolliert Events und broadcastet Fortschritt via Socket.IO `redeployStatus`.
5. **Logging**: Jeder relevante Vorgang erzeugt Einträge in `event_logs` (siehe `logging/eventLogs.js`). Frontend filtert/paginiert über `/api/logs` und kann Exporte `/api/logs/export` herunterladen.
6. **Wartung**: `/api/maintenance/*` verwaltet Maintenance-Mode, SSH-Zugänge, Update-Skripte und serverseitige Settings (`db/settings.js`).
## Verzeichnis-Referenz
| Pfad | Inhalt |
|------|--------|
| `backend/index.js` | Herzstück der API inkl. Routing, Socket.IO, Redeploy, Setup, Auth. |
| `backend/auth/` | Superuser-Verwaltung, Passwort- und Tokenfunktionen, Sicherheitsphrasen. |
| `backend/db/` | SQLite-Initialisierung (`ensure.js`/`schemaEnsure.js`), Settings-Layer, DB-Blueprints. |
| `backend/logging/` | Event-Log Modellierung, Filter/Export/Delete. |
| `backend/groups/`, `backend/users/`, `backend/permissions/` | Domain-Logik für Benutzer- & Rechteverwaltung. |
| `backend/maintenance/` | Maintenance-Mode sowie SSH-/Update-Konfiguration. |
| `frontend/src/` | React-App (Layouts, Pages, Widgets, Provider). `routes.jsx` definiert Navigation & Permissions. |
| `scripts/` | Hilfsskripte (z.B. `start-dev.sh`). |
| `Dockerfile`, `docker-compose*.yml` | Build- & Deployment-Spezifikation. |
## Konfiguration & Secrets
- API-Keys und Passwörter werden verschlüsselt in SQLite abgelegt (`server_api_keys`, `settings`).
- Settings (Maintenance, Update-Skripte, SSH) nutzen `db/settings.js` mit JSON-Serialisierung.
- Das Backend erzwingt HTTPS-Requests Richtung Portainer (`https.Agent` mit deaktivierter Zertifikatsprüfung für interne Netze).
- Socket.IO lauscht auf demselben Port wie Express (`/socket.io`). CORS ist aktuell für alle Origins offen für produktive Deployments empfiehlt sich ein Reverse Proxy mit Authentifizierung.
## Skalierung & Grenzen
- SQLite eignet sich für Einzelinstanzen. Für höhere Last empfiehlt sich eine Umstellung auf Postgres/MySQL (der Code kapselt Zugriffe weitgehend in `db/*`).
- Redeploy-Operationen werden seriell behandelt (`redeployingStacks` + Status-Caching). Parallele Ausführung ist möglich, solange Portainer dies unterstützt.
- Logging wird ausschließlich serverseitig betrieben; Client-seitige Filterung erfolgt über Query-Parameter.
Die weiteren Kapitel vertiefen Backend- und Frontend-spezifische Details.
+112
View File
@@ -0,0 +1,112 @@
# Backend & API
Das Backend implementiert alle Anwendungsfälle über Express-Routen, Socket.IO für Echtzeit-Events und eine SQLite-Datenbank als Persistenzschicht. Dieser Abschnitt fasst die wichtigsten Module, Entitäten und Endpunkte zusammen.
## Laufzeit & Einstiegspunkte
- `backend/index.js` initialisiert Express, Socket.IO, lädt `.env`, sorgt für Schema-Validierung (`ensureDatabaseSchema`) und Default-Daten (`ensureSuperuserFromEnv`, `ensureDefaultsFromEnv`).
- Start via `npm start` (siehe `package.json`); Migrationen über `npm run migrate`.
- Datenbankdatei: `backend/data/stackpulse.db`, WAL-Modus aktiv.
## Module
| Modul | Pfad | Aufgabe |
|-------|------|---------|
| Auth/Superuser | `auth/superuser.js` | Registrieren/Verifizieren von Superusern, Login, Passwortvalidierung, Sicherheitsphrasen. |
| Users & Groups | `users/*`, `groups/*`, `permissions/*` | CRUD für Benutzer, Gruppen, Rechtezuweisung, Ableitung effektiver Berechtigungen. |
| Setup | `setup/index.js` | Verwaltung registrierter Portainer-Server, sichere Ablage der API-Keys, Setup-Status. |
| Logging | `logging/eventLogs.js` | Einheitliches Ereignislogging (Insert, Filter, Delete, Export). |
| Maintenance | `maintenance/state.js` + helper in `index.js` | Wartungsmodus, SSH-Konfiguration, Update-Skripte und Ausführung. |
| Portainer Proxy | Funktionen in `index.js` | Kommunikation mit Portainer (`axiosInstance` + dynamische `baseURL`), Environment-Erkennung und Redeploy-Strecke. |
## API-Überblick (Auszug)
### Setup & Server
| Methode | Route | Beschreibung |
|---------|-------|--------------|
| GET | `/api/setup/status` | Gibt zurück, ob Server/API-Key/Superuser vorhanden sind. |
| POST | `/api/setup/test-portainer` | Verifiziert URL + API-Key gegen Portainer. |
| POST | `/api/setup/portainer-stacks` | Listet Stacks (für Preview im Wizard). |
| POST | `/api/setup/complete` | Markiert Setup als abgeschlossen und hinterlegt Server/API-Key. |
| DELETE | `/api/setup/servers/:id` | Entfernt einen registrierten Portainer-Server. |
| PUT | `/api/setup/servers/:id/api-key` | Überschreibt API-Key. |
| PUT | `/api/setup/self-stack` | Speichert die ID des StackPulse-Stacks, damit dieser nicht redeployed wird.
### Authentifizierung
| Methode | Route | Beschreibung |
|---------|-------|--------------|
| POST | `/api/auth/login` | Username/Passwort-Login, setzt HTTP-only Cookie. |
| POST | `/api/auth/logout` | Session beenden & Cookie löschen. |
| GET | `/api/auth/session` | Liefert eingeloggten Benutzer + Permissions. |
| POST | `/api/auth/recover/verify` & `/reset` | Passwortreset über Sicherheitsphrase. |
| GET/POST/DELETE | `/api/auth/superuser/*` | Abfrage, Registrierung oder Entfernen des Superusers.
### Benutzer & Gruppen
| Methode | Route | Beschreibung |
|---------|-------|--------------|
| GET/POST | `/api/users` | Liste anlegen, neue Benutzer erstellen. |
| GET/PUT/DELETE | `/api/users/:id` | Details lesen, bearbeiten oder löschen. |
| PUT | `/api/users/:id/groups` | Gruppenmitgliedschaften aktualisieren. |
| PUT | `/api/users/:id/active` | Benutzer aktivieren/deaktivieren. |
| GET/POST | `/api/users/:id/security-phrase`, `/renew` | Sicherheitsphrase anzeigen bzw. neu generieren. |
| GET/POST | `/api/groups` | Gruppen auflisten oder neu anlegen. |
| PUT/DELETE | `/api/groups/:id` | Gruppe editieren oder entfernen. |
| GET/PUT | `/api/groups/:id/permissions` | Berechtigungen lesen/setzen.
### Stacks & Redeploy
| Methode | Route | Beschreibung |
|---------|-------|--------------|
| GET | `/api/stacks` | Aggregierte Liste inkl. Filter, Self-Stack-Blockade und Redeploy-Status. |
| PUT | `/api/stacks/:id/redeploy` | Redeploy eines einzelnen Stacks. |
| PUT | `/api/stacks/redeploy-selection` | Redeploy einer Liste übermittelter `stackIds`. |
| PUT | `/api/stacks/redeploy-all` | Redeploy aller Stacks (Permission `stacks-redeploy-all`). |
Das Backend veröffentlicht den Redeploy-Fortschritt parallel über Socket.IO (`redeployStatus` Event) und unterscheidet die Phasen `queued`, `started`, `success`, `error`, `info`.
### Logging & Wartung
| Methode | Route | Beschreibung |
|---------|-------|--------------|
| GET | `/api/logs` | Filterbare/Paginierbare Event-Logs. |
| DELETE | `/api/logs/:id` oder `/api/logs` | Einzelne oder gefilterte Logs löschen. |
| GET | `/api/logs/export` | CSV-Export anhand der Query-Filter. |
| GET/POST | `/api/maintenance/mode` | Status abfragen oder toggeln. |
| GET | `/api/maintenance/config` | Liefert Maintenance-Status, Update-Skript & SSH-Config. |
| PUT/DELETE | `/api/maintenance/ssh-config` | SSH-Credentials speichern/entfernen. |
| POST | `/api/maintenance/test-ssh` | Verbindungstest mit optionalem Override. |
| PUT/DELETE | `/api/maintenance/update-script` | Custom Update-Skript pflegen. |
| POST | `/api/maintenance/portainer-update` | Update-Kommando per SSH ausführen (mit Custom/Default-Skript). |
## Datenbank & Schema
- `ensureDatabaseSchema()` erzeugt Tabellen bei jedem Start, inklusive Default-Gruppen, Permissions, Settings, Server-Einträge und Trigger.
- Permissions werden anhand der Blueprint-Datei `backend/db/dbs` eingelesen. Jede Permission definiert Key, Label, Level (`full`, `read`, `none`) und Abhängigkeiten.
- Events werden in `event_logs` gespeichert. Relevante Felder:
- `category`, `event_type`, `action`, `status`, `severity`
- `entity_type`, `entity_id`, `entity_name`
- `actor_type`, `actor_id`, `actor_name`
- `context_type`, `context_id`, `context_label`
- `message`, `metadata (JSON)`
- Filter-Parameter (`ids`, `categories`, `eventTypes`, `status`, `stackIds`, Zeitfenster) werden in `buildEventLogFilter` zentral verarbeitet.
## Berechtigungssystem
- Jeder Benutzer gehört zu beliebig vielen Gruppen; die effektiven Rechte ergeben sich aus der höchsten Ausprägung pro Permission.
- Superuser erhalten alle Berechtigungen und können nicht über das UI entzogen werden.
- `PermissionGate` im Frontend spiegelt die gleichen Keys. Wichtigste Bereiche:
- `stacks-*` (Redeploy)
- `logs-*`
- `users-*` & `user-groups-*`
- `maintenance-*` (inkl. Unterrechte `maintenance-server-*`, `maintenance-ssh-update`, `maintenance-update`)
## Redeploy-Workflow
1. Eingehender Request wird mit `maintenanceGuard` geprüft (Maintenance-Modus blockiert optional Redeploys).
2. Das Backend ermittelt den zugehörigen Portainer-Endpoint (`resolvePortainerEnvironmentId`).
3. Der Redeploy wird über Portainer ausgeführt (`/api/stacks/:id/redeploy`), Log-Einträge werden erstellt.
4. `broadcastRedeployStatus()` aktualisiert das In-Memory-Tracking (`redeployingStacks`) und sendet Socket.IO Events.
5. Fehler führen zu `event_logs`-Einträgen mit `severity=error`, UI zeigt Toasts via `ToastProvider`.
## Wartungs- und Updatepfad
- `maintenance/state.js` persistiert Aktivierung & Nachricht im Setting `maintenance_mode`.
- SSH-Konfigurationen (Host, Port, User, Passwort, extra args) werden verschlüsselt gespeichert (`getPortainerSshConfig`).
- Update-Skripte lassen sich überschreiben, Standard-Skript liegt in `DEFAULT_PORTAINER_UPDATE_SCRIPT` (Bash-Befehle).
- Update-Status hält Laufzeiten, letzte Ergebnisse und Logauszüge in-memory & Settings bereit.
## Erweiterungstipps
- Neue API-Routen sollten `requirePermission(..)` nutzen, Logging via `logEvent()` hinzufügen und falls Portainer-Aufrufe stattfinden das `axiosInstance` verwenden.
- Einstellungen stets über `db/settings.js` verwalten, damit UI & CLI konsistent bleiben.
- Für breaking DB-Änderungen existiert kein Migrations-Framework erweitere `ensureDatabaseSchema` inkl. Versionsflag, um Idempotenz sicherzustellen.
+63
View File
@@ -0,0 +1,63 @@
# Frontend
Das Frontend basiert auf React 18, Vite und dem Material Tailwind Dashboard. Es nutzt Context Provider für Authentifizierung, Seitenstatus, Toaster und Wartungsinformationen.
## Build & Skripte
| Befehl | Beschreibung |
|--------|--------------|
| `npm run dev` | Startet den Vite Dev-Server (Port 5173, HMR aktiviert). |
| `npm run build` | Erstellt ein Production-Bundle (`frontend/dist`). Das Dockerfile kopiert dieses Paket ins Backend (`backend/public`). |
| `npm run preview` | Vorschau auf das gebaute Bundle.
## Projektstruktur
```
frontend/src
├── App.jsx # Entry-Point, registriert Layouts & Provider
├── components/ # AuthProvider, PermissionGate, Toast/Maintenance/PageProvider
├── layouts/ # Dashboard-Layout (Sidebar, Navbar) & Auth-Layout
├── pages/
│ ├── auth/ # SignIn, SignUp, ForgotPassword, SignOut
│ ├── dashboard/ # Stacks, Logs, Maintenance, Users, Usergroups, Detailseiten
│ └── setup/ # Setup-Wizard & Helper Screens
├── routes.jsx # zentrale Navigationsdefinition inkl. Permissions
├── widgets/, data/, configs/, assets/
└── tailwind.css # Tailwind Layer & Custom Styles
```
## Routing & Navigation
- `routes.jsx` beschreibt sowohl Dashboard- als auch Auth-Routen. Jede Dashboard-Seite besitzt optional ein `permission`-Objekt, das vom `PermissionGate` ausgewertet wird.
- Der Layout-Switch erfolgt über `layouts/index.jsx`, das wiederum Sidebar/Topbar-Komponenten aus dem Material Tailwind Dashboard nutzt.
- Auth-Routen (`/sign-in`, `/sign-up`, `/forgot-password`, `/logout`) werden im Auth-Layout ohne Sidebar dargestellt.
## State-Management & Contexts
| Provider | Aufgabe |
|----------|---------|
| `AuthProvider` | Speichert User, Permissions, Session-Status. Stellt `refreshSession`, `logout`, `hasPermission` bereit. |
| `PageProvider` | Zentrale UI-Zustände (z.B. Ladeanzeigen, modale Dialoge) für Dashboard-Komponenten. |
| `ToastProvider` | Globale Notifications (z.B. Redeploy-Erfolg/Fehler). |
| `MaintenanceProvider` | Cached Maintenance-Status, erkennt aktive Maintenance Modes und zeigt Hinweise. |
## Wichtige Seiten
- **Stacks (`pages/dashboard/stacks.jsx`)**: Hauptübersicht mit Tabellen, Suche, Filtern, Bulk- und Einzelredeploy. Bindet `socket.io-client` für Live-Updates (`redeployStatus`).
- **Logs (`pages/dashboard/logs.jsx`)**: Tabellenansicht mit Statusfarben, Filterchips, Export-/Delete-Aktionen. Nutzt axios-Queries gegen `/api/logs`.
- **Maintenance (`pages/dashboard/maintenance.jsx`)**: Formulare zur Verwaltung von Update-Skript, SSH-Konfiguration, Maintenance-Mode-Toggle und Portainer-Statusprüfung.
- **Users / Usergroups**: CRUD-Oberfläche für Benutzer, Gruppen, Berechtigungszuweisung inkl. Sicherheitsphrasen-Handling.
- **Setup (`pages/setup`)**: Schrittweiser Wizard (Server -> API-Key -> Superuser). Wird solange angezeigt, bis `/api/setup/status` vollständig ist.
## Datenzugriff
- HTTP-Anfragen erfolgen via `axios` (global konfiguriert in `frontend/src/components/AuthProvider` bzw. direkt in den Seiten). Cookies werden automatisch vom Browser beigesteuert (`credentials: 'include'`).
- Socket.IO wird nur im Stack-Dashboard verwendet; Verbindungsaufbau erfolgt in `stacks.jsx` (`io('/', { path: '/socket.io' })`).
- Fehlerbehandlung: Jede Seite zeigt Toasts und/oder Inline-Warnungen. Auth-Fehler leiten zur Loginseite um.
## Styling & Komponenten
- Tailwind Utility-Klassen liefert Material Tailwind bereits vordefiniert (Theme in `configs`).
- Custom-Komponenten wie Tabellen, Filterchips oder Formulare sind überwiegend in `widgets/` ausgelagert.
- Icons stammen aus `@heroicons/react`. Farben/Typografie folgen Creative Tim Vorgaben, können aber zentral in `frontend/src/configs` angepasst werden.
## Erweiterungshinweise
1. **Neue Seiten**: Route in `routes.jsx` ergänzen, optional `PermissionGate` konfigurieren und Seite unter `pages/dashboard` oder `pages/auth` anlegen.
2. **API-Anbindungen**: Verwende `axios` und achte auf `try/catch`, damit 401/403 sauber abgefangen werden. Bei kritischen Anforderungen `refreshSession` aufrufen.
3. **State teilen**: Nutze bestehende Provider bzw. erzeuge einen eigenen Context in `components/`.
4. **Deployment**: `npm run build` liefert ein Self-Contained Bundle. Das Backend dient anschließend als Static Host (`express.static`).
Damit bietet das Frontend eine anpassbare, klar strukturierte Oberfläche, die eng mit den Backend-Permissions verzahnt ist.
+103
View File
@@ -0,0 +1,103 @@
# Getting Started
Dieser Leitfaden hilft dir, StackPulse lokal oder als Container aufzusetzen und die ersten Schritte im UI abzuschließen.
## Voraussetzungen
- Node.js **>= 20** und npm für lokale Entwicklung
- Docker & Docker Compose (optional aber empfohlen für Deployment)
- Zugriff auf eine **Portainer Business Edition** samt API-Key
- Shell-Zugang zum Host, auf dem StackPulse laufen soll
## Repository & Abhängigkeiten
```bash
# Repository klonen
# git clone <repo-url>
cd stackpulse
# Skript ausführbar machen
chmod +x scripts/start-dev.sh
```
## Lokale Dev-Umgebung
Das Skript `scripts/start-dev.sh` richtet Backend und Frontend automatisch ein:
1. Backend: `npm install`, `npm run migrate` (erstellt/aktualisiert `backend/data/stackpulse.db`), `npm start`
2. Frontend: `npm install`, `npm run dev` (Port 5173) und ein einmaliges `npm run build`, um statische Assets ins Backend zu spiegeln
Nach erfolgreichem Start:
- Frontend dev server: http://localhost:5173
- Backend API & statische Assets: http://localhost:4001
Zum Stoppen STRG+C verwenden.
## Manuelles Starten
```bash
# Backend
cd backend
npm install
npm run migrate
PORTAINER_URL=https://portainer.local npm start
# Frontend in zweiter Shell
cd frontend
npm install
npm run dev
```
Das Backend liest Umgebungsvariablen beim Start. Alternativ kannst du eine `.env` neben `backend/index.js` anlegen.
## Zentrale Umgebungsvariablen
| Variable | Beschreibung |
|----------|--------------|
| `PORTAINER_URL` | Basis-URL zu deiner Portainer-Instanz (inkl. Protokoll). Kann später im Setup-UI überschrieben werden. |
| `PORTAINER_API_KEY` | API-Key für Portainer. Wird in der DB verschlüsselt abgelegt, sobald du ihn im Setup speicherst. |
| `PORTAINER_SERVER_NAME` | Optionaler Anzeigename für den Server während des Setups. |
| `PORTAINER_API_SECRET` | Überschreibt den Schlüssel, der zur Verschlüsselung des API-Keys verwendet wird. |
| `SUPERUSER_USERNAME`, `SUPERUSER_EMAIL`, `SUPERUSER_PASSWORD` | Legt einen Superuser automatisch beim Start an (falls nicht vorhanden). |
| `SELF_STACK_ID` | Stack-ID von StackPulse selbst. Wird genutzt, um eigene Redeploys zu blockieren. |
| `AUTH_COOKIE_NAME`, `AUTH_SESSION_TTL_MS`, `AUTH_COOKIE_SECURE` | Feintuning für die Session-Verwaltung der API. |
| `SECURITY_PHRASE_SECRET` | Seed für die Generierung kryptografischer Sicherheitsphrasen. |
| `PORTAINER_SSH_SECRET` | Secret für SSH-Passwortverschlüsselung (Wartungs-Update). |
| `DISPLAY` | Wird an Kindprozesse weitergereicht, wenn Portainer-Updates ausgelöst werden müssen (Default `:9999`). |
Weitere Einstellungen (SSH-Config, Update-Skripte) verwaltest du später direkt im Maintenance-Bereich des UI.
## Ersteinrichtung im UI
1. Öffne das Frontend (`/setup` führt dich automatisch durch den Wizard).
2. Lege den Portainer-Server und den zugehörigen API-Key an StackPulse testet die Verbindung per `/api/setup/test-portainer`.
3. Registriere einen Superuser oder verwende den per Umgebungsvariablen automatisch angelegten Account.
4. Nach erfolgreicher Einrichtung kannst du dich anmelden und erhältst Zugriff auf Dashboard, Logs, Benutzer & Wartung.
## Docker-Deployment
```yaml
# docker-compose.yml (Auszug)
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "4001:4001"
volumes:
- stackpulse_data:/app/backend/data
restart: unless-stopped
environment:
- PORTAINER_URL=https://portainer.example.com
- PORTAINER_API_KEY=xxxx
- SUPERUSER_USERNAME=admin
- SUPERUSER_EMAIL=admin@example.com
- SUPERUSER_PASSWORD=changeme
- SELF_STACK_ID=123
volumes:
stackpulse_data:
```
1. `docker compose up -d --build`
2. Das Frontend ist anschließend unter Port 4001 (via Backend `public/`) erreichbar.
3. Datenbank & Einstellungen liegen im benannten Volume `stackpulse_data`.
## Datenbank & Migration
- Datei: `backend/data/stackpulse.db`
- Migration: `npm run migrate` (führt `backend/db/ensure.js` aus und erzeugt Schema, Rechte, Defaults)
- Backup: Datei oder Volume regelmäßig sichern; enthält Benutzer, Logs und gespeicherte Secrets.
Damit bist du bereit für die tieferen Kapitel zu Architektur sowie Backend- und Frontend-Details.
+35
View File
@@ -0,0 +1,35 @@
# StackPulse
StackPulse ist eine eigenständige Web-Anwendung, die die Portainer Business Edition über deren API steuert und dadurch Redeploys, Wartungsskripte sowie das Berechtigungs- und Logging-Konzept zentralisiert. Die Lösung besteht aus einem Node.js/Express Backend, einem React-Frontend auf Basis von Material Tailwind sowie einer eingebetteten SQLite-Datenbank, die ohne zusätzliche Infrastruktur betrieben werden kann.
## Warum StackPulse?
- **Schneller Überblick** über sämtliche Stacks einer Portainer-Instanz inkl. Status, Filter und Suche
- **Redeploy-Orchestrierung** aus einem UI heraus einzelne Stacks, Auswahlen oder komplette Umgebungen
- **Auditierbare Historie** durch strukturierte Event-Logs mit Export-, Lösch- und Filterfunktionen
- **Feingranulare Rechteverwaltung** mit Gruppenrechten, Superuser-Handling und Sicherheitsphrasen
- **Wartungsautomatisierung** (SSH Update-Skripte, Maintenance-Mode) ohne direkten Portainer-Zugang
- **Bereitstellung als Docker-Image** sowie als lokale Dev-Umgebung via `scripts/start-dev.sh`
## Technische Eckdaten
| Baustein | Technologie | Beschreibung |
|-------------|-------------|--------------|
| Backend | Node.js 20, Express, Axios, Socket.IO, better-sqlite3 | Stellt REST-API, Authentifizierung, Rechte, Logging, Redeploy-Queue und Portainer-Proxy bereit. |
| Datenhaltung| SQLite (Datei `backend/data/stackpulse.db`) | Persistente Speicherung von Benutzern, Gruppen, Servern, API-Keys, Logs und Einstellungen. |
| Frontend | React 18, Vite, Material Tailwind Dashboard | Dashboard mit Auth-Flow, Stacks, Logs, Benutzer- und Wartungsansichten. |
| Container | Dockerfile + Compose | Multi-Stage Build für Frontend + Backend, Datenvolumen für SQLite. |
## Release-Status
- **v0.5 (aktuell)** vollständiges Auth/Berechtigungssystem, Benutzer- & Gruppenverwaltung, erweiterte Logs
- **v0.4** neues UI auf Basis des Material Tailwind Dashboards
- **v0.3** Such- & Filterfunktionen, Konfliktbehandlung für Stack-IDs, UI-Benachrichtigungen
- **v0.2** SQLite-Logging inkl. Export/Pagination, Redeploy-Selektor
- **v0.1** Grundstruktur, API-Anbindung, erstes Redeploy
Weitere geplante Features (Notifications, Monitoring, Multi-Server, Portainer CE) findest du in der [Roadmap im README](../README.md).
## Wie geht es weiter?
- [Getting Started](getting-started.md) erläutert Installation, Konfiguration und erste Schritte.
- [Architektur](architecture.md) beschreibt Aufbau, Verzeichnisse und Datenflüsse.
- [Backend](backend.md) fasst API, Datenbank und Sicherheitsschichten zusammen.
- [Frontend](frontend.md) dokumentiert Layout, Routen und Komponenten.
- [Operations & Wartung](operations.md) enthält Betriebshinweise und Troubleshooting.
+46
View File
@@ -0,0 +1,46 @@
# Operations & Wartung
Dieser Abschnitt deckt typische Aufgaben für Betriebsteams ab von Backups über Wartungsmodus bis zu Störungssuche.
## Laufender Betrieb
- **Services überwachen**: StackPulse stellt nur einen Prozess bereit (Node.js/Express). Nutze Systemd/Docker Healthchecks, indem du regelmäßig `/api/auth/session` (für Auth) oder `/api/maintenance/update-status` (für Backend + DB) abfragst.
- **Ports**: Standardmäßig lauscht nur Port 4001 (HTTP + Socket.IO). Hinter einem Reverse Proxy sollte TLS terminiert werden.
- **Protokolle**: Das Backend loggt ausführlich auf STDOUT/STDERR (`console.log`). Sammle diese via Docker-Logs oder Journal.
## Backups & Wiederherstellung
1. **Container-Setup**: Mount `backend/data` via benanntem Volume (siehe `docker-compose.yml`).
2. **Backup**: Stoppe kurz den Container oder nutze `sqlite3 stackpulse.db ".backup 'stackpulse.db.bak'"` innerhalb der laufenden Instanz.
3. **Restore**: Ersetze die Datei im Volume und starte die App neu. Beim ersten Start führt `ensureDatabaseSchema` automatisch eventuelle Nachmigrationen aus.
## Benutzer- & Rechteverwaltung
- Superuser können über `/api/auth/superuser/*` oder im UI registriert werden. Entfernen ist nur mit `maintenance-superuser-delete` möglich.
- Benutzerkonten lassen sich temporär deaktivieren (`/api/users/:id/active`). Die Historie bleibt erhalten.
- Sicherheitsphrasen sind notwendig für Passwort-Reset. Admins können neue Phrasen erzeugen (`/api/users/:id/security-phrase/renew`), müssen diese aber dem Benutzer sicher zustellen.
## Wartungsmodus & Updates
- Maintenance Mode aktivieren: `curl -X POST http://host:4001/api/maintenance/mode -H 'Content-Type: application/json' -d '{"active":true,"message":"Cluster Upgrade"}'` (Permission `maintenance-access`). Das UI informiert alle Nutzer und blockiert Redeploys.
- SSH-/Update-Setup: Hinterlege Host, Port, Benutzer, Passwort (optional) und zusätzliche SSH-Argumente. Passwörter werden verschlüsselt gespeichert (`PORTAINER_SSH_SECRET`).
- Update-Skript: Das Default-Skript (`DEFAULT_PORTAINER_UPDATE_SCRIPT`) führt `docker stop`, `docker run` etc. aus. Du kannst im UI oder via API ein eigenes Skript setzen wird erst aktualisiert, wenn kein Update läuft.
- Update anstoßen: `POST /api/maintenance/portainer-update` triggert die SSH-Kommandos. Status & Logausgaben können über `/api/maintenance/update-status` überwacht werden.
## Logs & Compliance
- Ereignislogs enthalten jede Redeploy-, Auth- und Verwaltungsaktion. Export über `GET /api/logs/export` (CSV) oder automatisiert mittels Cron (Query-Parameter übernehmen Filter).
- Datenbereinigung: Nutze `DELETE /api/logs/:id` oder `DELETE /api/logs?before=<ISO>` um alte Einträge zu entfernen. Achtung: Aktionen sind nicht reversibel.
- Für Offload kannst du per Script regelmäßig Exporte ziehen und anschließend löschen.
## Troubleshooting
| Symptom | Prüfschritte |
|---------|--------------|
| **Setup schlägt fehl (PORTAINER_URL_NOT_CONFIGURED)** | Stelle sicher, dass entweder `PORTAINER_URL` gesetzt ist oder im Setup-UI ein Server gespeichert wurde (`servers`-Tabelle prüfen). |
| **Redeploy hängt in `queued`** | `/api/maintenance/update-status` auf laufende Updates prüfen, `redeployingStacks` im Log verfolgen; ggf. Portainer-API erreichbar? |
| **Login nicht möglich** | Über `backend/logs` nach Auth-Fehlern suchen, Cookie-Konfiguration prüfen (`AUTH_COOKIE_SECURE` bei HTTP?). |
| **SSH-Test fehlgeschlagen** | `POST /api/maintenance/test-ssh` mit temporären Credentials testen, Container-Logs auf `SSH Test fehlgeschlagen` untersuchen. |
| **SQLite Locked** | Stelle sicher, dass kein paralleler Backup-Prozess läuft. WAL-Modus erlaubt mehrere Leser, blockiert aber bei langen Schreibtransaktionen (Check Logs auf `SQLITE_BUSY`). |
## Sicherheitsempfehlungen
- Setze `AUTH_COOKIE_SECURE=true` hinter TLS und konfiguriere einen Reverse Proxy (z.B. Traefik, Nginx).
- Isoliere das Admin-Interface durch VPN oder IP-Filter.
- Drehe API-Keys regelmäßig: `/api/setup/servers/:id/api-key` aktualisiert Schlüssel ohne Neuinstallation.
- Nutze dedizierte StackPulse-Benutzer in Portainer, damit Berechtigungen klar getrennt bleiben.
Mit diesen Richtlinien lässt sich StackPulse sicher betreiben und warten.
+41
View File
@@ -0,0 +1,41 @@
# Benutzergruppen & Rechte
Dieser Bereich verwaltet Rollenmodelle und bestimmt, welche Aktionen Benutzer:innen durchführen dürfen. Du benötigst `user-groups-access` zum Lesen sowie `user-groups-edit`/`user-groups-delete` für Änderungen.
## Gruppen anlegen
1. Button **Gruppe erstellen** wählen.
2. Pflichtfelder:
- **Name** (z.B. „Ops Team“)
- **Beschreibung** (Hilfestellung für Kolleg:innen)
3. Optional Tag-Farbe oder Icon setzen (für bessere Übersicht in der Benutzerliste).
4. Speichern die Gruppe erscheint sofort in der Übersicht.
## Gruppen bearbeiten
- Zeile anklicken, um das Detailpanel zu öffnen.
- Du kannst Name, Beschreibung und Zugehörige Benutzer (nur Anzeige) sehen.
- Zum Bearbeiten der Rechte klicke auf **Berechtigungen bearbeiten**.
## Rechte vergeben
Der Rechte-Dialog zeigt die gesamte Permissionstruktur in Kategorien (Stacks, Logs, Benutzer, Wartung etc.).
1. Wähle die gewünschte Kategorie aus.
2. Setze für jede Permission einen Level:
- **none** kein Zugriff
- **read** Zugriff auf Ansicht/Lesen
- **full** volle Bearbeitungsrechte
3. Abhängigkeiten werden automatisch hervorgehoben. Beispiel: Um `logs-delete` nutzen zu dürfen, muss `logs-access` mindestens `full` sein.
4. Speichern bestätigt die Anpassungen. StackPulse aktualisiert sofort die effektiven Rechte aller Benutzer in dieser Gruppe.
## Benutzer zu Gruppen hinzufügen
- Dies geschieht im Benutzer-Detailpanel (siehe [Benutzerverwaltung](users.md)).
- Die Liste zeigt alle vorhandenen Gruppen; ein Benutzer kann mehreren Gruppen angehören.
- Die effektiven Rechte sind die jeweils höchsten Levels aller Gruppen.
## Gruppen löschen
- Nur möglich, wenn keine Benutzer ausschließlich von dieser Gruppe abhängen (es erfolgt ein Warnhinweis).
- Löschen entfernt keine Benutzer, aber deren effektive Rechte können sich dadurch verringern.
## Best Practices
- Erstelle zunächst eine Basisgruppe (z.B. „Viewer“) mit `read`-Rechten für Stacks und Logs.
- Verwende separate Gruppen für sensible Aktionen wie Wartung oder Superuser-Verwaltung.
- Nutze sprechende Beschreibungen, damit Kolleg:innen sofort erkennen, wofür eine Gruppe gedacht ist.
+13
View File
@@ -0,0 +1,13 @@
# Benutzerhandbuch
Dieses Kapitel beschreibt die Bedienung von StackPulse aus Sicht von Administrator:innen und Operators. Es orientiert sich an den Seiten im Dashboard und erklärt für jeden Bereich typische Abläufe sowie die notwendigen Berechtigungen. Screenshots kannst du später ergänzen; die Texte nennen bereits alle Buttons, Eingabefelder und Statusanzeigen.
**Reihenfolge**
1. [Setup](setup.md) richtet Portainer-Anbindung und Superuser ein.
2. [Stacks](stacks.md) zeigt alle Stacks, Redeploy-Aktionen und Filter.
3. [Logs](logs.md) Nachvollziehbarkeit, Filter & Export.
4. [Wartung](maintenance.md) Maintenance-Mode, Updates und SSH-Konfiguration.
5. [Benutzer](users.md) Konten verwalten, Phrasen ausgeben, Passwörter setzen.
6. [Benutzergruppen & Rechte](groups.md) Rollen modellieren und Berechtigungen zuweisen.
Jede Seite nennt die erforderlichen Permissions. Sobald du dich anmeldest, führt dich StackPulse zunächst automatisch durch den Setup-Assistenten; danach landet man auf der Stacks-Übersicht.
+27
View File
@@ -0,0 +1,27 @@
# Logs-Seite
Die Logs-Seite dient der Nachvollziehbarkeit aller Aktionen (Redeploy, Login, Wartung, Benutzerverwaltung). Sie steht Benutzer:innen mit der Permission `logs-access` zur Verfügung.
## Überblick
- Filterleiste mit Suchfeld, Zeitspanne, Kategorie und Status.
- Tabelle mit Severity-Farben, Nachricht, Zeitstempel und Kontextinformationen.
- Aktionen oberhalb der Tabelle: **Exportieren** und **Löschen**.
## Filtern
1. **Zeitfenster:** Datumsfelder „Von“ und „Bis“ setzen. Standardmäßig zeigt StackPulse die letzten 24 Stunden.
2. **Kategorie/Status:** Dropdowns nutzen, um z.B. `redeploy` oder `wartung` auszuwählen.
3. **Freitext:** Suchfeld durchsucht `message`, `entity_name` und `metadata`.
4. **Erweiterte Filter:** Klick auf „Weitere Filter“ öffnet zusätzliche Optionen (Actor, Stack-ID, Severity).
## Export
- Button **CSV exportieren** klickst du erst, nachdem die Filter stehen. StackPulse erstellt eine CSV-Datei mit denselben Parametern.
- Der Download startet im Browser; in containerisierten Umgebungen kannst du denselben Endpoint (`/api/logs/export`) auch automatisiert aufrufen.
## Löschen
- Einzelne Logs: Papierkorb in der Zeile (Permission `logs-delete`).
- Batch-Löschung: Button **Gefilterte Einträge löschen**; es erscheint ein Sicherheitsdialog mit Zusammenfassung der aktiven Filter.
- Beachte, dass gelöschte Logs nicht wiederhergestellt werden können.
## Detailansicht
- Klick auf eine Tabellenzeile, um ein Seitenpanel mit vollständigem JSON (`metadata`), Kontext (Stack, Benutzer, Quelle) und ggf. Redeploy-Timings zu öffnen.
- Über **Stack öffnen** gelangst du direkt zur Stacks-Seite mit gesetztem Filter.
+43
View File
@@ -0,0 +1,43 @@
# Wartungsbereich
Der Wartungsbereich bündelt alle Funktionen rund um Maintenance-Mode, Serververwaltung, Update-Skripte und SSH-Verbindungen. Sichtbar für Benutzer:innen mit `maintenance-access` (Teilbereiche erfordern zusätzliche Unterrechte).
## Portainer-Status
- Klick auf **Status prüfen**, um eine Live-Abfrage gegen Portainer durchzuführen. Ergebnis zeigt API-Verfügbarkeit, Endpoint-IDs und Auth-Status.
- Häufige Fehler werden direkt erklärt (z.B. fehlender API-Key oder Netzwerkprobleme).
## Maintenance-Mode
1. Schalter **Wartungsmodus aktivieren** toggeln.
2. Optionale Nachricht eingeben (z.B. „Upgrade um 22:00 Uhr“); sie erscheint im gesamten UI als Banner.
3. Aktivieren/Deaktivieren protokolliert automatisch Events in den Logs.
## Server & API-Key verwalten
- Register „Server“ listet alle Portainer-Instanzen.
- Über **Server hinzufügen** kannst du Name + URL ergänzen und anschließend API-Key speichern.
- Buttons in der Tabelle:
- **API-Key aktualisieren** neues Token einsetzen.
- **Server löschen** nur möglich, wenn mindestens ein weiterer Server existiert oder du sofort neue Daten einträgst.
## Self-Stack ID
- Feld „Eigener Stack“ akzeptiert die Stack-ID, in der StackPulse selbst läuft.
- Nach dem Speichern sind Redeploy-Aktionen für diesen Stack im Dashboard deaktiviert.
## SSH-Konfiguration
Erforderliche Permission: `maintenance-ssh-update`.
1. Host, Port, Benutzername eintragen. Optional Passwort und zusätzliche SSH-Argumente (z.B. `-o StrictHostKeyChecking=no`).
2. Passwort wird verschlüsselt gespeichert; alternativ kannst du Public-Key-Auth nutzen und das Feld leer lassen.
3. **Verbindung testen**: StackPulse baut eine SSH-Verbindung auf und zeigt das Ergebnis in Echtzeit.
## Update-Skript
- Standard-Skript wird angezeigt und kann als Ausgangspunkt genutzt werden.
- Eigenes Skript: Inhalt in das Editorfeld kopieren und speichern. StackPulse prüft auf leere Zeilen und Basisbefehle.
- Skript zurücksetzen entfernt die benutzerdefinierte Variante und stellt den Default wieder her.
## Portainer-Update auslösen
1. Stelle sicher, dass Wartungsmodus aktiv ist und SSH-Konfiguration + Skript korrekt sind.
2. Klicke auf **Update starten**. Der aktuelle Fortschritt erscheint in einem Logpanel.
3. Der Button bleibt deaktiviert, solange ein Update läuft. Über **Status aktualisieren** kannst du den Fortschritt erneut abfragen.
## Fehlerbehandlung
- Bei SSH-Fehlern zeigt StackPulse die genaue Ausgabe an. Passe Host/Port/Benutzer oder Skript an.
- Falls das Update-Skript Probleme verursacht, kannst du es jederzeit stoppen, indem du Portainer manuell prüfst und ggf. das Skript anpasst.
+35
View File
@@ -0,0 +1,35 @@
# Setup-Assistent
Beim ersten Start erscheint automatisch der Setup-Bereich. Du erreichst ihn später jederzeit über `/setup`, solange nicht alle Schritte abgeschlossen sind.
## Voraussetzungen
- Portainer Business Edition mit gültigem API-Key
- Superuser-Zugangsdaten (entweder schon per Umgebungsvariablen gesetzt oder über diesen Assistenten festlegen)
## Schritt 1: Portainer-Server anlegen
1. Formularfelder **Server-URL** und optional **Name** ausfüllen.
- URL inkl. Protokoll (z.B. `https://portainer.example.com`).
- Bezeichnung dient ausschließlich als Anzeige im Dashboard.
2. Auf **Verbindung testen** klicken.
- Erfolgreich: grüner Hinweis, die Endpoints werden erkannt.
- Fehlgeschlagen: Fehlermeldung prüfen (häufig Zertifikats-/Firewall-Themen).
3. Mit **Speichern & Weiter** bestätigst du den Servereintrag. StackPulse legt ihn verschlüsselt in SQLite ab.
## Schritt 2: API-Key hinterlegen
1. API-Key im Feld **Portainer API Key** einfügen.
2. Optional kannst du über **Stacks laden** kontrollieren, ob Portainer Stacks zurückliefert.
3. Mit **Speichern** wird der Schlüssel verschlüsselt gespeichert. Du kannst ihn später im Maintenance-Bereich austauschen.
## Schritt 3: Superuser registrieren
1. Falls du `SUPERUSER_*` Variablen gesetzt hast, zeigt StackPulse an, dass bereits ein Superuser existiert du kannst direkt weiter.
2. Ansonsten Benutzername, E-Mail und Passwort vergeben. Das Passwort dient nur für diesen Account; weitere Benutzer folgen später.
3. Auf **Superuser anlegen** klicken. Nach Erfolg wird der Login-Button eingeblendet.
## Abschluss & Login
- Sobald alle drei Schritte abgeschlossen sind, erscheint die Schaltfläche **Zum Login**.
- Melde dich mit dem Superuser an. StackPulse legt im Hintergrund initiale Berechtigungen, Default-Gruppen und Sicherheitspassphrasen an.
## Setup wiederholen oder ändern
- Über das Dashboard → **Wartung** → Abschnitt *Serververwaltung* kannst du zusätzliche Portainer-Server hinzufügen oder entfernen.
- Superuser lässt sich im Bereich **Benutzer** löschen, sofern du `maintenance-superuser-delete` besitzt.
- Der Self-Stack (StackPulse-eigener Stack) kann in der Wartung gepflegt werden, damit er nicht versehentlich redeployed wird.
+36
View File
@@ -0,0 +1,36 @@
# Stacks-Seite
Die Stacks-Ansicht ist der Startpunkt nach dem Login und liefert einen Überblick über alle Stacks der angebundenen Portainer-Instanz.
## Aufbau
- **Header** mit Suchfeld, Filterchips für Status sowie Buttons für Redeploy-Aktionen.
- **Tabelle** mit Name, Endpoint, Status, letzte Aktion, Redeploy-Status und verfügbaren Buttons.
- **Live-Status**: Über Socket.IO wird jede Veränderung (queued/started/success/error) sofort eingeblendet.
## Filter & Suche
1. Verwende das Suchfeld oben rechts, um nach Namen oder IDs zu filtern.
2. Statuschips (z.B. „running“, „warning“) toggeln per Klick und lassen sich kombinieren.
3. Über die Spaltenköpfe kannst du sortieren; ein erneuter Klick kehrt die Reihenfolge um.
## Redeploy-Aktionen
| Aktion | Voraussetzung | Vorgehen |
|--------|---------------|----------|
| **Einzelner Stack** | Permission `stacks-redeploy-single` | Button **Redeploy** in der jeweiligen Zeile klicken und bestätigen. |
| **Mehrere Stacks** | `stacks-redeploy-selection` | Checkboxen der gewünschten Stacks aktivieren, anschließend **Redeploy Auswahl**. |
| **Alle Stacks** | `stacks-redeploy-all` | Button **Redeploy alle** auslösen. Nutze vorher Filter, um sicherzugehen, dass alle Stacks korrekt angezeigt werden. |
Während eines Redeploys erscheint pro Stack ein Fortschrittsbadge. Du kannst das Panel schließen; beim nächsten Besuch wird der aktuelle Status aus dem Backend gelesen.
## Redeploy-Status verstehen
- **Queued** Auftrag ist vorgemerkt.
- **Started** Portainer verarbeitet Redeploy.
- **Success** Vorgang erfolgreich abgeschlossen.
- **Error** Fehlerdetails findest du in der Logs-Seite.
- **Info** Informative Hinweise, etwa wenn Portainer einen Stack überspringt.
## Selbstschutz
- Falls du die Variable `SELF_STACK_ID` gesetzt hast, markiert StackPulse den eigenen Stack als „geschützt“. Redeploy-Buttons werden deaktiviert und mit einem Info-Tooltip versehen.
## Troubleshooting aus der Ansicht
- Klicke auf das Warnsymbol in der Tabellenzeile, um Fehlerdetails einzublenden.
- Nutze den Link „Zu Logs springen“, der direkt eine gefilterte Ansicht in der Log-Seite öffnet (Stack-ID ist vorausgewählt).
+39
View File
@@ -0,0 +1,39 @@
# Benutzerverwaltung
Die Benutzerseite ermöglicht das Anlegen, Bearbeiten und Deaktivieren von Konten. Du benötigst mindestens die Permission `users-access` (lesen) bzw. `users-edit`/`users-delete` für Änderungen.
## Benutzer anlegen
1. Button **Benutzer anlegen** klicken.
2. Formularfelder ausfüllen:
- Benutzername (eindeutig, wird für Login genutzt)
- Anzeigename (optional)
- E-Mail-Adresse
- Passwort (kann später geändert werden)
- Gruppen auswählen (siehe Abschnitt „Benutzergruppen“)
3. Optional: Benutzer sofort aktivieren/deaktivieren.
4. Mit **Speichern** bestätigen. Der Benutzer erscheint in der Tabelle und erhält automatisch eine Sicherheitspassphrase.
## Benutzer bearbeiten
- In der Tabelle auf eine Zeile klicken, um das Detailpanel zu öffnen.
- Du kannst Anzeigename, E-Mail, Passwort und Gruppen ändern.
- Änderungen an Gruppen erfordern `users-edit` sowie Gruppenrechte (`user-groups-access`).
## Konto deaktivieren/reaktivieren
- Toggle **Aktiv** im Detailpanel.
- Deaktivierte Konten können sich nicht mehr anmelden, bleiben aber in der Historie.
## Sicherheitspassphrase
1. Button **Sicherheitspassphrase anzeigen** im Detailpanel.
2. StackPulse zeigt einen QR-Code und den alphanumerischen Code. Dieser wird nur einmal angezeigt, bis du bestätigst, dass er heruntergeladen wurde.
3. Über **Neu generieren** kannst du eine neue Phrase erstellen (Permission `users-security-phrase`). Informiere den Benutzer über die neue Phrase und markiere anschließend „heruntergeladen“.
## Passwort zurücksetzen
- Admins können direkt im Detailpanel ein neues Passwort setzen.
- Benutzer:innen selbst nutzen die Auth-Seite „Passwort vergessen“: Sie geben Username + Sicherheitsphrase ein und definieren anschließend ein neues Passwort.
## Suche & Filter
- Nutze das Suchfeld, um nach Benutzername oder E-Mail zu suchen.
- Filterchips für Status (aktiv/inaktiv) erleichtern das Auffinden gesperrter Accounts.
## Massenaktionen
- Mehrfachauswahl (Checkboxen) erlaubt das gleichzeitige Aktivieren/Deaktivieren oder Löschen mehrerer Benutzer. Vorsicht: Löschen entfernt auch Audit-Verweise.