feat(PROJ-17): Admin Dashboard Systemauslastung immer anzeigen

- Systemauslastungs-Sektion wird immer gerendert (nicht nur bei Erfolg)
- Fehlermeldung wenn /api/admin/system/stats nicht erreichbar ist
- Feature-Status auf In Review gesetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-14 11:43:19 +01:00
parent a893084a88
commit d360c9a5ba
68 changed files with 11938 additions and 435 deletions
@@ -0,0 +1,185 @@
# PROJ-1: Nutzer-Authentifizierung & Rollen
## Status: In Progress
**Created:** 2026-03-12
**Last Updated:** 2026-03-12
## Dependencies
- PROJ-16 (LDAP / Active Directory Anbindung) — optionale Erweiterung des Login-Flows
## Rollen-Übersicht
| Rolle | Zugriff |
|-------|---------|
| `user` | Suche und Lesen eigener archivierter E-Mails |
| `auditor` | Alle E-Mails lesen und suchen (postfachübergreifend) + Audit-Log einsehen und exportieren keine Konfiguration |
| `admin` | Konfiguration, Nutzerverwaltung, Import-Quellen, Systemeinstellungen kein Zugriff auf E-Mails, kein Audit-Log |
## User Stories
- Als Admin möchte ich mich mit Benutzername/Passwort einloggen, damit nur autorisierte Personen Zugriff haben.
- Als Admin möchte ich neue Nutzer anlegen und ihnen eine Rolle zuweisen (`user`, `auditor`, `admin`).
- Als Auditor möchte ich den Audit-Log einsehen und als CSV exportieren, ohne Zugriff auf E-Mails oder Konfiguration zu haben.
- Als Nutzer möchte ich mich abmelden können, damit meine Session sicher beendet wird.
- Als Admin möchte ich Passwörter zurücksetzen können, damit gesperrte Nutzer wieder Zugang erhalten.
- Als System möchte ich Sessions nach Inaktivität automatisch beenden, damit unbefugter Zugriff verhindert wird.
## Acceptance Criteria
- [ ] Login-Seite mit E-Mail/Benutzername und Passwort-Formular
- [ ] Fehlermeldung bei falschen Zugangsdaten (kein Hinweis ob E-Mail oder Passwort falsch)
- [ ] Session-Token wird sicher gespeichert (httpOnly Cookie oder JWT)
- [ ] Sessions laufen nach konfigurierbarer Inaktivität ab (Standard: 8 Stunden)
- [ ] Drei Rollen: `user`, `auditor`, `admin` strikt getrennte Zugriffsrechte
- [ ] `auditor` hat Zugriff auf alle E-Mails (postfachübergreifend, auch fremde Postfächer) + Audit-Log keine Konfiguration
- [ ] `admin` hat ausschließlich Zugriff auf Konfiguration und Nutzerverwaltung kein Zugriff auf E-Mails und kein Zugriff auf Audit-Log
- [ ] Admin kann Nutzer anlegen, deaktivieren und löschen
- [ ] Admin kann Passwörter zurücksetzen (temporäres Passwort)
- [ ] Alle API-Endpunkte prüfen Authentifizierung und Rolle
- [ ] Logout löscht die Session serverseitig
## Edge Cases
- Login mit deaktiviertem Account → klare Fehlermeldung, kein Zugang
- Mehrfaches Fehllogin → Rate-Limiting oder Account-Sperre nach X Versuchen
- Session-Token abgelaufen → automatische Weiterleitung zur Login-Seite
- Erster Start: Zwei feste Default-User werden beim ersten Start automatisch angelegt:
- `admin@archivmail` / `archivmailrockz` (Rolle: `admin`)
- `auditor@archivmail` / `archivmailrockz` (Rolle: `auditor`)
- Passwörter sollten nach dem ersten Login geändert werden (Hinweis in der UI)
- Admin löscht sich selbst → verhindern wenn letzter Admin
## Technical Requirements
- Passwörter mit bcrypt gehasht (min. Cost 12)
- Alle Routen außer `/login` erfordern gültige Session
- Admin-Routen (`/admin/*`) nur für `admin`-Rolle
- Audit-Routen (`/audit/*`) und E-Mail-Suche/Ansicht nur für `auditor`- und `user`-Rolle
- `admin` erhält bei E-Mail-Endpunkten HTTP 403 keine Ausnahmen
- Keine Rolle vereint `admin` + `auditor` strikte Funktionstrennung
- Audit-Log-Eintrag bei Login, Logout, fehlgeschlagenem Login
---
<!-- Sections below are added by subsequent skills -->
## Tech Design (Solution Architect)
### Systemübersicht: Two-Tier Architektur
```
Browser (Next.js App) Go REST API Backend
│ │
│ POST /api/auth/login │
│ {email, password} │
│ ─────────────────────────────────► │
│ 1. Lokaler Account? → bcrypt verify
│ 2. Nicht gefunden + LDAP aktiv?
│ → LDAP-Bind (Service Account)
│ → User-DN suchen
│ → User-Bind mit Passwort
│ → AD-Gruppen → Rolle bestimmen
│ → UpsertLDAPUser in PostgreSQL
│ 3. Session-Token erstellen
│ Session in PostgreSQL speichern
│ ◄─────────────────────────────────
│ Set-Cookie: session=TOKEN │
│ (httpOnly, Secure, SameSite) │
│ │
│ GET /api/search?q=... │
│ Cookie: session=TOKEN │
│ ─────────────────────────────────► │
│ Session-Middleware: Token prüfen
│ Role-Middleware: Route erlaubt?
│ ◄─────────────────────────────────
│ JSON-Antwort │
```
> **LDAP ist vollständig optional.** Wenn `ldap.enabled: false` (Standard), verhält sich das System exakt wie ohne LDAP. Lokale Accounts funktionieren immer — auch wenn LDAP aktiviert ist (Fallback bei LDAP-Fehler).
### Komponentenstruktur
**Next.js Frontend:**
```
src/app/
├── /login ← Login-Seite (öffentlich)
├── /search ← Suche + E-Mail-Ansicht (user + auditor)
├── /audit ← Audit-Log (nur auditor)
└── /admin ← Admin-Bereich (nur admin)
src/components/
├── LoginForm ← E-Mail + Passwort, Fehlermeldungen
├── RoleGuard ← Schützt Routen clientseitig, redirect auf /login
└── PasswordChangePrompt ← Hinweis bei Default-Passwort
```
**Go Backend:**
```
HTTP-Server
├── POST /api/auth/login ← Session ausstellen
├── POST /api/auth/logout ← Session löschen
├── Session Middleware ← prüft Token bei allen /api/* Routen
├── Role Middleware
│ ├── /api/admin/* → nur `admin`
│ ├── /api/audit/* → nur `auditor`
│ └── /api/* → `user` + `auditor` (admin → 403)
├── Password Manager ← bcrypt Hash + Verify
├── User Store ← PostgreSQL users-Tabelle
└── Bootstrap ← Default-User beim ersten Start
```
### Datenmodell
**Tabelle `users`:**
| Feld | Beschreibung |
|------|-------------|
| `id` | Interne ID |
| `email` | Login-E-Mail (eindeutig) |
| `password_hash` | bcrypt-Hash (Cost 12) — NULL bei LDAP-Usern |
| `role` | `user` / `auditor` / `admin` |
| `source` | `local` oder `ldap` — Herkunft des Accounts |
| `active` | Deaktivierte Nutzer können sich nicht einloggen |
| `created_at` | Erstellungszeitpunkt |
| `last_login_at` | Letzter erfolgreicher Login |
**Tabelle `sessions`:**
| Feld | Beschreibung |
|------|-------------|
| `token` | Zufälliger 32-Byte-Token |
| `user_id` | Referenz auf `users` |
| `expires_at` | Ablaufzeitpunkt (rollierend, +8h bei Aktivität) |
| `last_active_at` | Wird bei jeder Anfrage aktualisiert |
### Technische Entscheidungen
| Entscheidung | Begründung |
|---|---|
| **Next.js Frontend + Go REST API** | Klare Trennung: Next.js rendert die UI, Go verwaltet Daten und Sicherheit. Kein Java. |
| **Session-Cookie (httpOnly)** | Next.js sendet Cookie automatisch mit kein manuelles Token-Handling im Frontend-Code nötig |
| **Server-side Sessions (nicht JWT)** | Logout und Admin-Deaktivierung wirken sofort JWT wäre bis Ablauf weiterhin gültig |
| **Role-Check im Go-Backend** | Sicherheits-kritische Prüfung liegt im Backend, nicht im Next.js-Client (der wäre manipulierbar) |
| **RoleGuard in Next.js zusätzlich** | Verhindert kurzes Aufblitzen falscher Seiten rein UX, kein Sicherheits-Feature |
| **bcrypt Cost 12** | Ausreichend langsam gegen Brute-Force |
| **LDAP als optionaler Fallback** | Login versucht erst lokalen Account, dann LDAP Reihenfolge garantiert, dass lokale Admins immer funktionieren |
| **LDAP-User in PostgreSQL gespiegelt** | Nach erstem Login landet LDAP-User in `users`-Tabelle (`source: ldap`) einheitliche Session-Verwaltung, kein Sonder-Code |
| **AD-Gruppen → Rollen-Mapping** | Rolle wird bei jedem Login aus AD-Gruppenmitgliedschaft neu bestimmt Rollen-Änderung in AD wirkt beim nächsten Login |
### Abhängigkeiten
**Go Backend:**
| Paket | Zweck |
|---|---|
| `golang.org/x/crypto/bcrypt` | Passwort-Hashing |
| `crypto/rand` | Sichere Token-Generierung (Stdlib) |
| `github.com/go-ldap/ldap/v3` | LDAP/AD-Authentifizierung (PROJ-16) |
**Next.js Frontend:**
| Paket | Zweck |
|---|---|
| `react-hook-form` + `zod` | Login-Formular-Validierung (bereits im Template) |
| `shadcn/ui` | UI-Komponenten (bereits installiert) |
## QA Test Results
_To be added by /qa_
## Deployment
_To be added by /deploy_