# #008 Hosts und Hostgruppen **Status:** erledigt **Meilenstein:** v0.1.0 **Labels:** backend, ui **Geschätzt:** 3 h **Tatsächlich:** 0,5 h ## Ziel Hosts und Hostgruppen anlegen, bearbeiten, archivieren; Kunden und Tags. ## Aufgaben - [x] Liste mit Status (erreichbar, letzter Abgleich, Drift) - [x] Formular: Name, Adresse, Port, Gruppen, Tags, Beschreibung, Kunde, Anmeldebenutzer (`sshkv`/`root`) - [x] Hostgruppen mit Mitgliedern - [x] Hostdetail-Gerüst ## Akzeptanzkriterien - [x] Leser sieht, Operator/Admin bearbeiten ## Abhängigkeiten #004 ## Notizen / Entscheidungen - **Schichtung:** Regeln (zod-Schemas, Status-Ableitung) framework-frei in `src/lib/hosts.ts`; Services `src/server/services/hosts.ts` / `hostgruppen.ts`, Lesemodelle `src/server/queries/hosts.ts`, Aktionen `src/server/actions/hosts.ts` / `hostgruppen.ts` (gemeinsame Hilfen in `actions/formular.ts`, ohne `"use server"`). Die Action prüft vorab für Feldmeldungen, der Service prüft erneut (Seed, Skripte, spätere Assistenten). - **Archivieren statt Löschen** (`archiviertAm`). Dabei fallen die Gruppenmitgliedschaften weg (im Protokoll festgehalten), damit Zuweisungen an Gruppen nie einen archivierten Host treffen. Archivierte Hosts sind schreibgeschützt und erscheinen in keiner Liste; der Name bleibt belegt, damit das Protokoll eindeutig bleibt. Wiederherstellen gibt es noch nicht. - **Hostgruppen löschen** bewusst noch nicht: `PublicVerwendung` hängt per Cascade an der Gruppe; das Löschen klärt #016 zusammen mit den Verwendungen. - **Kunde** per Name: unbekannter Name legt den Kunden an (`kunde.angelegt` im Protokoll), leer = kein Kunde. Gruppen- und Kundennamen erlauben Leerzeichen/Umlaute (reine Anzeige). - **Protokoll:** `host.angelegt`, `host.geaendert` (nur geänderte Felder als `{ vorher, nachher }`, ohne Änderung kein Eintrag), `host.archiviert`, `hostgruppe.angelegt`, `hostgruppe.geaendert` (Mitglieder als `hinzu`/`entfernt`), `kunde.angelegt`. Demo-Seed schreibt bewusst keine Einträge. - **Status in der Liste:** nicht erreichbar > Drift (auch bei offenen Abweichungen) > synchron > unbekannt. Host-Key: ein ausstehender Key geht vor einem vertrauten, damit ein geänderter Key nicht hinter „bestätigt“ verschwindet. - **Formulare** senden per `onSubmit` + `startTransition` statt `
`: sonst setzt React das Formular nach jeder Antwort zurück und Eingaben gingen bei Feldfehlern verloren. `Feld` hat dafür `fehler` bekommen; neu sind `Textbereich`, `Auswahlliste`, `Ankreuzfeld`, `Feldgruppe`. - **Mobil:** Hostliste unter `md` als Kartenliste statt Tabelle (Status und Host-Key ohne seitliches Wischen sichtbar); Gruppenliste zeigt die Beschreibung unter dem Namen. - **Platzhalter für Folge-Issues:** `src/app/(app)/hosts/[id]/HostKeyAktionen.tsx` (`hostId`, `darfEntscheiden`, `status: HostKeyZusammenfassung`, #009) im Kopf der Karte „Host-Key“ und `BootstrapAktionen.tsx` (`hostId`, `darfVerwalten`, `eingerichtet`, `hostKeyVertraut`, #010) unter der Info-Leiste – beide geben vorerst `null` zurück. - **Demo-Daten:** `SSHKV_SEED_DEMO=1 pnpm db:seed` legt 6 Hosts, 3 Gruppen und einen Kunden an (Upsert nach Name, idempotent). - **Screenshots:** `scripts/screenshots.ts` kennt `hosts` und `host-detail` (folgt dem ersten Host der Liste).