docs(quick-260923-ku6): Drei Nachbesserungen aus dem Browser-Rundgang zu quick-260923-dhh (Proxmox-Modul) beheben

This commit is contained in:
2026-09-23 15:14:29 +02:00
parent f1bb7f7191
commit a9e0d5b1ae
3 changed files with 265 additions and 2 deletions
@@ -0,0 +1,108 @@
---
phase: quick
plan: 260923-ku6
type: quick
autonomous: true
requirements: []
---
# Quick Task 260923-ku6: Drei Nachbesserungen aus dem Browser-Rundgang (Proxmox-Modul)
## Objective
Drei im Browser-Rundgang zu Quick-Task 260923-dhh gefundene Fehler beheben, ohne den
Funktionsumfang sonst zu veraendern:
1. „Verbindung testen" prueft den gespeicherten Stand statt der Formularwerte.
2. Ein frisch angelegter, noch nie abgefragter Server zeigt faelschlich die Sammelmeldung
„Ein unerwarteter Fehler ist aufgetreten" statt eines ruhigen „noch keine Abfrage"-Zustands.
3. Die CSS-Klasse `uppercase` faerbt in der Modulseiten-Zeile die ganze Zeile (inkl. Adresse)
gross statt nur das Produktkuerzel.
## Context
- Quelle: menschlicher Browser-Rundgang zu `.planning/quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/260923-dhh-PLAN.md`.
- Betroffene Dateien: `apps/api/src/proxmox/proxmox.controller.ts`, `apps/api/src/proxmox/proxmox.service.ts`,
`apps/api/src/proxmox/dto/proxmox-server.dto.ts`, `apps/web/src/lib/proxmox-api.ts`,
`apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.tsx`,
`apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx`,
`apps/web/src/messages/de.json`, `apps/web/src/messages/en.json`.
## Tasks
### Task 1: Verbindungstest prueft Formularwerte statt gespeicherten Stand (Befund 1)
<task type="auto">
<files>
apps/api/src/proxmox/dto/proxmox-server.dto.ts
apps/api/src/proxmox/proxmox.service.ts
apps/api/src/proxmox/proxmox.controller.ts
apps/api/src/proxmox/proxmox.service.spec.ts
apps/web/src/lib/proxmox-api.ts
apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.tsx
apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.test.tsx
</files>
<action>
Backend: neues `TestProxmoxServerDto` (alle Felder optional, wie `UpdateProxmoxServerDto`).
`POST servers/:id/test` nimmt diesen Body entgegen und mischt ihn mit dem gespeicherten
Server: pro Feld gilt „im Formular gesendet und nicht leer -> Formularwert, sonst
gespeicherter Wert" (Geheimnisfelder: nicht gesendet/leer -> gespeicherter, verschluesselter
Wert bleibt bestehen und wird wie ueblich entschluesselt). Neue Route `POST servers/test`
(ohne `:id`) fuer die Neuanlage — testet ausschliesslich mit den Formularwerten, ohne
gespeicherten Fallback. Beide Routen rufen denselben privaten Merge-Baustein auf; dieser
wird per Unit-Test abgedeckt (leeres Geheimnisfeld -> gespeicherter Wert bleibt; gefuelltes
Geheimnisfeld -> neuer Wert greift; abgeschaltete Zertifikatspruefung im Formular wird
uebernommen). Zugangsdaten weiterhin nicht in Log/Antwort (bestehende Riegel unveraendert).
Frontend: `testServer`/neue `testDraftServer`-Funktion senden immer den vollstaendigen
aktuellen Formularstand. `ServerForm` zeigt den Testen-Knopf immer (nicht nur nach dem
Speichern) und waehlt je nach `savedServer` die passende Funktion.
</action>
<verify>cd apps/api && pnpm vitest run src/proxmox/proxmox.service.spec.ts && cd ../web && pnpm vitest run src/app/\(portal\)/modules/proxmox/settings/components/ServerForm.test.tsx</verify>
<done>Ein Test zeigt: gespeicherter Server mit im Formular abgeschalteter Zertifikatspruefung
-> Testergebnis beruecksichtigt die abgeschaltete Pruefung (nicht mehr `zertifikat`-Fehler).
Ein zweiter Test zeigt: leer gelassenes Geheimnisfeld nutzt weiterhin den gespeicherten Wert.
Der Testen-Knopf funktioniert auch ohne gespeicherten Server.</done>
</task>
### Task 2: Ruhiger Zustand fuer "noch nie abgefragt" (Befund 2)
<task type="auto">
<files>
apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx
apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx
apps/web/src/messages/de.json
apps/web/src/messages/en.json
</files>
<action>
Neuer Uebersetzungsschluessel `proxmox.card.notPolledYet` (DE/EN), der auf den Knopf
„Jetzt aktualisieren" verweist. In `ServerCard`: wenn `status.lastPolledAt === null` (noch
keine Abfrage gelaufen), erscheint dieser ruhige Hinweis statt des Fehlerblocks — auch wenn
`status.reachable` false ist (Zustand direkt nach dem Anlegen). Die bestehenden
Fehlermeldungen (inkl. `unbekannt`) bleiben fuer den Fall `lastPolledAt !== null &&
!reachable` unveraendert.
</action>
<verify>cd apps/web && pnpm vitest run src/app/\(portal\)/modules/proxmox/components/ServerCard.test.tsx</verify>
<done>Ein Test zeigt: Status mit `lastPolledAt: null, reachable: false, errorKind: null`
zeigt den ruhigen Hinweistext und NICHT die Meldung "Ein unerwarteter Fehler ist
aufgetreten". Bestehende Fehlermeldungs-Tests bleiben gruen.</done>
</task>
### Task 3: uppercase nur auf Produktkuerzel (Befund 3)
<task type="auto">
<files>
apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx
</files>
<action>
`uppercase` von der Zeile auf ein `<span>` um `server.productType` verschieben; die Adresse
bleibt unveraendert dargestellt.
</action>
<verify>cd apps/web && pnpm vitest run src/app/\(portal\)/modules/proxmox/components/ServerCard.test.tsx</verify>
<done>Adresse erscheint in der Modulseiten-Zeile nicht mehr grossgeschrieben, Produktkuerzel weiterhin schon.</done>
</task>
## Gesamtverifikation
Nach allen drei Aufgaben: `pnpm --filter api test`, `pnpm --filter web test`,
`pnpm type-check`, `pnpm lint`, `pnpm --filter web exec biome check .` (Warnungszahl exakt
53) muessen unveraendert/gruen sein, keine Container-Neubauten, keine Browser-Pruefung.
@@ -0,0 +1,154 @@
---
phase: quick
plan: 260923-ku6
subsystem: ui
tags: [nestjs, next.js, proxmox, class-validator, vitest, next-intl, biome]
requires:
- phase: 260923-dhh
provides: Proxmox-Modul (PVE/PBS/PMG anbinden, Verbindungstest, Modulseite)
provides:
- Verbindungstest prueft Formularwerte statt gespeicherten Stand (neue Route POST servers/test, TestProxmoxServerDto, resolveEffectiveTestServer-Merge)
- Ruhiger "noch nicht abgefragt"-Zustand auf der Modulseite statt Sammelfehlermeldung
- uppercase-Klasse nur noch auf dem Produktkuerzel, nicht mehr auf der Adresse
affects: [proxmox]
actuals:
tokens: 9700
tasks: 3
commits: 2
tech-stack:
added: []
patterns:
- "Formular-vs-gespeichert-Merge fuer Verbindungstests: normale Felder folgen dem Formular (auch geleert), Geheimnisfelder folgen der 'leer -> gespeicherten Wert behalten'-Regel, weil das Formular Geheimnisse beim Laden nie vorbefuellt"
key-files:
created: []
modified:
- apps/api/src/proxmox/dto/proxmox-server.dto.ts
- apps/api/src/proxmox/proxmox.controller.ts
- apps/api/src/proxmox/proxmox.service.ts
- apps/api/src/proxmox/proxmox.service.spec.ts
- apps/web/src/lib/proxmox-api.ts
- "apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.tsx"
- "apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.test.tsx"
- "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx"
- "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx"
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
key-decisions:
- "Verbindungstest-Route POST servers/:id/test nimmt jetzt einen optionalen Body (TestProxmoxServerDto) entgegen; neue Route POST servers/test (ohne :id) deckt die Neuanlage ab, ueberschneidet sich nicht mit servers/:id/test (unterschiedliche Segmentzahl)"
- "Geheimnisfelder behalten beim Test die 'leer -> gespeicherten Wert' Sonderregel, alle anderen Felder folgen strikt dem gesendeten Formularstand (auch wenn absichtlich geleert)"
- "Befund 2+3 in einem Commit, weil beide Aenderungen in derselben Datei (ServerCard.tsx) liegen"
requirements-completed: []
coverage:
- id: D1
description: "Verbindungstest prueft Formularwerte (Zertifikatspruefung, neues Geheimnis) statt des gespeicherten Stands; leer gelassenes Geheimnisfeld nutzt weiterhin den gespeicherten Wert; Test funktioniert auch bei der Neuanlage ohne gespeicherten Server"
verification:
- kind: unit
ref: "apps/api/src/proxmox/proxmox.service.spec.ts#Nachbesserung Befund 1: testConnection prueft die im Formular abgeschaltete Zertifikatspruefung..."
status: pass
- kind: unit
ref: "apps/api/src/proxmox/proxmox.service.spec.ts#Nachbesserung Befund 1: ein im Formular NEU eingetipptes Token-Geheimnis wird getestet..."
status: pass
- kind: unit
ref: "apps/api/src/proxmox/proxmox.service.spec.ts#Nachbesserung Befund 1: leer gelassenes Geheimnisfeld im Formular nutzt weiterhin das gespeicherte Token-Geheimnis"
status: pass
- kind: unit
ref: "apps/api/src/proxmox/proxmox.service.spec.ts#Nachbesserung Befund 1: testDraftConnection testet einen noch nicht gespeicherten Server..."
status: pass
- kind: unit
ref: "apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.test.tsx#Nachbesserung Befund 1: bei der Neuanlage ... steht der Testen-Knopf zur Verfuegung..."
status: pass
- kind: unit
ref: "apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.test.tsx#Nachbesserung Befund 1: der Test prueft die im Formular abgeschaltete Zertifikatspruefung..."
status: pass
human_judgment: true
rationale: "Browser-Pruefung des tatsaechlichen Verhaltens macht der Orchestrator danach (per Auftrag ausgeschlossen aus diesem Lauf)"
- id: D2
description: "Frisch angelegter, noch nie abgefragter Server zeigt einen ruhigen Hinweis statt der Sammelfehlermeldung 'Ein unerwarteter Fehler ist aufgetreten'"
verification:
- kind: unit
ref: "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx#Nachbesserung Befund 2: ein frisch angelegter, noch nie abgefragter Server..."
status: pass
human_judgment: true
rationale: "Browser-Pruefung des tatsaechlichen Verhaltens macht der Orchestrator danach (per Auftrag ausgeschlossen aus diesem Lauf)"
- id: D3
description: "Adresse in der Modulseiten-Zeile nicht mehr grossgeschrieben, nur noch das Produktkuerzel"
verification:
- kind: unit
ref: "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx#Nachbesserung Befund 3: die Adresse bleibt unveraendert dargestellt..."
status: pass
human_judgment: false
duration: 45min
completed: 2026-09-23
status: complete
---
# Quick Task 260923-ku6: Drei Nachbesserungen aus dem Browser-Rundgang (Proxmox-Modul) Summary
**Verbindungstest folgt jetzt dem Formular statt dem gespeicherten Server, ein frisch angelegter Server zeigt einen ruhigen "noch nicht abgefragt"-Hinweis statt einer falschen Fehlermeldung, und die Adresse in der Modulseiten-Zeile ist nicht mehr grossgeschrieben.**
## Performance
- **Duration:** ~45 min
- **Tasks:** 3
- **Files modified:** 11
## Accomplishments
- **Befund 1:** `POST servers/:id/test` prueft jetzt den aktuellen Formularstand (Zertifikatspruefung, Token-/Passwort-Geheimnis, Adresse, Zugangsart) statt blind des gespeicherten Servers; neue Route `POST servers/test` deckt denselben Test waehrend der Neuanlage ab, wo es noch keinen gespeicherten Server gibt. Geheimnisfelder behalten die Sonderregel "leer gelassen -> gespeicherten Wert weiterverwenden", weil `ServerForm` sie beim Laden nie aus der Datenbank vorbefuellt.
- **Befund 2:** Ein frisch angelegter, noch nie abgefragter Server (`status.lastPolledAt === null`) zeigt einen ruhigen Hinweistext, der auf "Jetzt aktualisieren" verweist, statt der Sammelmeldung "Ein unerwarteter Fehler ist aufgetreten". Echte Fehlermeldungen bleiben fuer bereits abgefragte, aber nicht erreichbare Server unveraendert.
- **Befund 3:** Die `uppercase`-Klasse sitzt jetzt nur noch auf dem Produktkuerzel (`<span>`), nicht mehr auf der ganzen Statuszeile — die Adresse erscheint wieder wie eingegeben.
## Task Commits
1. **Task 1: Verbindungstest prueft Formularwerte statt gespeicherten Stand (Befund 1)** - `710034c` (fix)
2. **Task 2+3: Ruhiger "noch nicht abgefragt"-Zustand und Adresse ohne Grossschreibung (Befund 2+3)** - `f1bb7f7` (fix)
_Beide Aufgaben von Befund 2 und 3 liegen in derselben Datei (`ServerCard.tsx`) und wurden deshalb in einem Commit zusammengefasst — Begruendung steht in der Commit-Nachricht._
## Files Created/Modified
- `apps/api/src/proxmox/dto/proxmox-server.dto.ts` - neues `TestProxmoxServerDto`
- `apps/api/src/proxmox/proxmox.controller.ts` - `test` nimmt jetzt einen Body entgegen, neue Route `testDraft` (`POST servers/test`)
- `apps/api/src/proxmox/proxmox.service.ts` - `resolveEffectiveTestServer`-Merge, `testConnection` mit `dto`-Parameter, neue `testDraftConnection`
- `apps/api/src/proxmox/proxmox.service.spec.ts` - 5 neue Tests fuer Befund 1
- `apps/web/src/lib/proxmox-api.ts` - `testServer` nimmt jetzt ein Payload, neue `testDraftServer`
- `apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.tsx` - Testen-Knopf immer sichtbar, sendet immer den Formularstand
- `apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.test.tsx` - alte "kein Knopf vor dem Speichern"-Erwartung durch das neue, gewuenschte Verhalten ersetzt, 2 neue Tests
- `apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx` - ruhiger "noch nicht abgefragt"-Zustand, `uppercase` nur auf dem Produktkuerzel
- `apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx` - 2 neue Tests
- `apps/web/src/messages/de.json`, `apps/web/src/messages/en.json` - neuer Schluessel `proxmox.card.notPolledYet`
## Decisions Made
- Geheimnisfelder (`tokenSecret`/`password`) folgen beim Testen weiterhin der bestehenden "leer -> gespeicherten Wert behalten"-Regel aus `updateServer`, weil `ServerForm` sie beim Laden absichtlich nie vorbefuellt (kein Klartext-Leak). Alle anderen Felder (`tokenId`, `username`, `baseUrl`, `authMethod`, `productType`, `tlsRejectUnauthorized`) folgen strikt dem gesendeten Formularwert, auch wenn er absichtlich geleert wurde — diese Felder sind beim Laden immer vorbefuellt, ein leeres Feld ist dort also eine bewusste Nutzeraktion.
- Neue Route `POST servers/test` statt eines Sonderwerts fuer `:id` (z. B. `new`), weil sie sich mit `servers/:id/test` nicht ueberschneidet (zwei vs. drei Segmente) und dadurch keine Routen-Reihenfolge-Abhaengigkeit entsteht.
- `buildTestPayload()` in `ServerForm.tsx` sendet bewusst kein `name`-Feld, weil `TestProxmoxServerDto` `@IsNotEmpty()` auf `name` erbt und ein waehrend der Neuanlage noch leeres Namensfeld sonst jeden Testklick mit 400 blockiert hätte.
## Deviations from Plan
None - plan executed exactly as written (PLAN.md `.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-PLAN.md`).
## Issues Encountered
- Die Aenderung an `ServerCard.tsx` (`status && status.lastPolledAt && !status.reachable`) loeste eine neue Biome-Warnung (`lint/complexity/useOptionalChain`) aus, die die geforderte exakte Warnungszahl (53) auf 54 angehoben haette. Behoben durch Umformulierung zu `status?.lastPolledAt && !status.reachable` (TypeScript narrowt `status` fuer den Rest des Ausdrucks korrekt nach) — Warnungszahl danach wieder exakt 53.
- Der bestehende Test "ohne gespeicherten Server (Neuanlage) gibt es keinen Verbindung-testen-Knopf" widersprach direkt der geforderten Korrektur aus Befund 1 (Testen soll bei der Neuanlage funktionieren) und wurde durch einen Test mit dem neuen, gewuenschten Verhalten ersetzt.
## User Setup Required
None - keine externe Konfiguration noetig.
## Next Phase Readiness
Alle drei Befunde behoben, alle Tore gruen (api 1316/1316, web 712/712, type-check 4/4, lint 5/5, Biome `apps/web` exakt 53 Warnungen). Browser-Pruefung der tatsaechlichen UI macht der Orchestrator im Anschluss, wie im Auftrag verlangt.
---
*Phase: quick-260923-ku6*
*Completed: 2026-09-23*