# PROJ-17: Admin Dashboard – Systemauslastung & Archiv-Übersicht ## Status: In Review **Created:** 2026-03-14 **Last Updated:** 2026-03-14 ## Dependencies - Requires: PROJ-1 (Authentifizierung) – nur Admins sehen das Dashboard - Requires: PROJ-5 (Speicherung) – erste/letzte Mail aus dem Archiv ## User Stories - Als Admin möchte ich die aktuelle CPU-Auslastung sehen, damit ich Engpässe erkennen kann. - Als Admin möchte ich die RAM-Auslastung (gesamt / verwendet / frei) sehen. - Als Admin möchte ich alle eingebundenen Festplatten/Partitionen mit Füllstand sehen (Balken). - Als Admin möchte ich die älteste und neueste archivierte Mail sehen (Datum, Von, Betreff), damit ich den Archivierungszeitraum auf einen Blick erkenne. ## Acceptance Criteria - [x] CPU: Load Average (1min / 5min / 15min) aus `/proc/loadavg` - [x] RAM: MemTotal, MemUsed, MemAvailable aus `/proc/meminfo`; Prozentbalken - [x] Disk: alle physischen Partitionen (keine tmpfs/proc/sysfs/devtmpfs/overlay) via `syscall.Statfs`; je Partition: Mountpoint, Gesamt, Belegt, Frei, Prozent - [x] Erste Mail im Archiv: Datum, Von, Betreff (älteste Datei im Store) - [x] Letzte Mail im Archiv: Datum, Von, Betreff (neueste Datei im Store) - [x] Endpoint: `GET /api/admin/system/stats` (Admin-only) - [x] Storage-Erweiterung: `store.FirstAndLastMail()` liefert Metadaten der ältesten und neuesten Mail ## API Response Schema ```json { "cpu": { "load1": 0.42, "load5": 0.38, "load15": 0.31, "num_cpu": 4 }, "ram": { "total_bytes": 8388608000, "used_bytes": 3221225472, "free_bytes": 5167382528, "used_pct": 38.4 }, "disks": [ { "mount": "/", "total_bytes": 53687091200, "used_bytes": 12884901888, "free_bytes": 40802189312, "used_pct": 24.0, "fstype": "ext4" } ], "archive": { "first_mail": { "id": "abc123", "date": "2024-01-15T08:00:00Z", "from": "...", "subject": "..." }, "last_mail": { "id": "def456", "date": "2026-03-14T10:08:00Z", "from": "...", "subject": "..." } } } ``` ## Technical Design ### Backend (`internal/api/server.go`) - Neuer Handler `handleSystemStats` - CPU: `/proc/loadavg` parsen → load1, load5, load15 + `runtime.NumCPU()` - RAM: `/proc/meminfo` parsen → MemTotal, MemFree, MemAvailable, Buffers, Cached - `used = total - available` - Disks: `/proc/mounts` lesen, für jeden Eintrag `syscall.Statfs()` aufrufen - Ausschließen: fstype in {tmpfs, proc, sysfs, devtmpfs, cgroup, cgroup2, overlay, squashfs, debugfs, tracefs, securityfs, pstore, efivarfs, bpf, hugetlbfs, mqueue, ramfs} - Erste/letzte Mail: `store.FirstAndLastMail()` → walk store dir, min/max ModTime ### Storage (`internal/storage/storage.go`) - Neue Methode `FirstAndLastMail() (*MailRef, *MailRef, error)` - `MailRef{ID, ModTime}` → ID wird an `handleSystemStats` übergeben, der dann via `mailparser.Parse()` From+Subject+Date extrahiert ### Frontend (`src/app/admin/page.tsx`) - Neue Kacheln im Dashboard-Tab: - **CPU-Auslastung**: Load Average mit `num_cpu` Kontext - **Arbeitsspeicher**: Fortschrittsbalken (used/total), Zahlen darunter - **Festplatten**: eine Karte pro Partition mit Balken + Zahlen - **Archivzeitraum**: erste und letzte Mail als kompakte Zeilen (Datum · Von · Betreff) ## Implementation Notes - **Backend:** `handleSystemStats` in `internal/api/server.go` — CPU via `/proc/loadavg`, RAM via `/proc/meminfo`, alle Disks via `/proc/mounts` + `syscall.Statfs`, Archiv-Zeitspanne via `store.FirstAndLastMail()` - **Storage:** `FirstAndLastMail()` + `MailRef` in `internal/storage/storage.go` — walkt Store-Verzeichnis, liefert älteste/neueste Mail per ModTime - **Route:** `GET /api/admin/system/stats` (Admin-only, Token-Auth) - **Frontend:** Dashboard-Tab in `src/app/admin/page.tsx` mit CPU, RAM, Disk-Partitionen und Archivzeitraum; Auto-Refresh alle 30 Sekunden - **Bereit für Test auf** `root@192.168.1.131`