Audit-Log, Import/Export, eigenes Profil & anpassbare Navigation

- Änderungslog: audit_log-Tabelle + last_modified_by/at an Devices und
  Switches; log_action()/touch_record() in allen Verwaltungsrouten
  (Devices, Switches, Zugangsdaten, Benutzer, Gruppen, Settings) verdrahtet.
  Neue Admin-Seite "Änderungslog" unter /logs/aenderungen. PoE-Neustarts
  werden bewusst nicht geloggt.
- Verschlüsseltes Import/Export für Devices/Switches/Zugangsdaten unter
  Settings, passphrasenbasiert (PBKDF2 + Fernet), für Umzug auf neue
  Umgebungen. Referenziert Zugangsdaten/Switche über Name/Hostname statt
  interner ID für stabilen Re-Import.
- Eigenes Profil: Klick auf den Namen in der Sidebar öffnet ein Modal zum
  Ändern von Vor-/Nachname, eigenem Passwort (mit Prüfung des aktuellen
  Passworts) und Profilbild-Upload (Anzeige in Sidebar + Änderungslog).
- Anpassbare Navigation: Reihenfolge der Sidebar-Punkte ist unter Settings
  per Auf-/Ab-Buttons konfigurierbar (settings.nav_order); "Devices"/
  "Users"/"Settings" umbenannt zu "Geräte"/"Benutzer"/"Einstellungen";
  "Live-Log" und "Änderungslog" zu aufklappbarer "Logs"-Gruppe
  zusammengefasst. Jeder Benutzer sieht weiterhin nur, wofür er berechtigt
  ist.
- create_db.py mit allen Schema-Erweiterungen synchronisiert (audit_log,
  last_modified_by/at, avatar_filename) für Frischinstallationen.
- venv-Umgebung im WSL neu aufgesetzt (war fälschlich unter dem
  Erstellungspfad venv-linux verankert und daher nicht aktivierbar).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 14:27:46 +02:00
co-authored by Claude Sonnet 5
parent fa6bb2935f
commit a7a23b7c12
13 changed files with 828 additions and 63 deletions
+75
View File
@@ -168,6 +168,60 @@ button { font-family: inherit; }
margin: 10px 8px;
}
/* Nav-Gruppe mit Untermenü (z.B. "Logs" -> Live-Log / Änderungslog) */
.nav-group-toggle {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
padding: 10px 12px;
border: none;
background: none;
color: var(--text-dim);
font-weight: 550;
font-size: 13.5px;
font-family: inherit;
border-radius: var(--radius-sm);
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.nav-group-toggle svg { width: 18px; height: 18px; flex-shrink: 0; opacity: 0.85; }
.nav-group-toggle:hover { background: var(--bg-card-hover); color: var(--text); }
.nav-group-toggle .nav-chevron { margin-left: auto; width: 14px; height: 14px; transition: transform 0.15s ease; opacity: 0.6; }
.nav-group.expanded .nav-group-toggle .nav-chevron { transform: rotate(90deg); }
.nav-group.active-group .nav-group-toggle { color: var(--accent-strong); }
.nav-group-children {
display: none;
flex-direction: column;
gap: 2px;
padding-left: 30px;
margin-top: 2px;
}
.nav-group.expanded .nav-group-children { display: flex; }
.nav-group-children .nav-item { font-size: 13px; padding: 8px 12px; }
/* Navbar-Reihenfolge (Settings) */
.nav-order-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 6px;
margin-bottom: 16px;
}
.nav-order-list li {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
background: var(--bg-card);
border: 1px solid var(--border-soft);
border-radius: var(--radius-sm);
font-size: 13.5px;
font-weight: 550;
}
.nav-order-list .nav-order-actions { display: flex; gap: 4px; }
.nav-order-list .icon-btn { width: 28px; height: 28px; }
.sidebar-footer {
padding: 14px 12px 18px;
border-top: 1px solid var(--border-soft);
@@ -421,6 +475,25 @@ button { font-family: inherit; }
.pill.disabled { background: var(--muted-dim); color: var(--muted); }
.pill.admin { background: var(--accent-dim); color: var(--accent-strong); }
.pill.user { background: var(--muted-dim); color: var(--text-dim); }
.pill.action-pill { background: var(--muted-dim); color: var(--text-dim); }
.pill.action-pill::before { display: none; }
.pill.action-pill svg { width: 13px; height: 13px; }
.avatar-sm {
display: inline-flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
border-radius: 50%;
object-fit: cover;
background: var(--muted-dim);
color: var(--text-dim);
font-size: 11.5px;
font-weight: 700;
flex-shrink: 0;
}
.avatar-placeholder { text-transform: uppercase; }
.timer-pill {
display: inline-flex;
@@ -503,6 +576,7 @@ button { font-family: inherit; }
.device-card[data-status="online"]::before { background: var(--success); }
.device-card[data-status="offline"]::before { background: var(--danger); }
.device-card[data-status="unbekannt"]::before { background: var(--warning); }
.device-card[data-status="disabled"]::before { background: var(--muted); }
.device-card .dc-top {
display: flex;
@@ -521,6 +595,7 @@ button { font-family: inherit; }
}
.device-card[data-status="online"] .dc-icon { background: var(--success-dim); color: var(--success); }
.device-card[data-status="offline"] .dc-icon { background: var(--danger-dim); color: var(--danger); }
.device-card[data-status="disabled"] .dc-icon { background: var(--muted-dim); color: var(--muted); }
.device-card .dc-icon svg { width: 17px; height: 17px; }
.device-card .dc-name {