From a9e0d5b1ae1bb2c1d6dd2f1d4626028ab857dd7d Mon Sep 17 00:00:00 2001 From: Schalli Date: Wed, 23 Sep 2026 15:14:29 +0200 Subject: [PATCH] docs(quick-260923-ku6): Drei Nachbesserungen aus dem Browser-Rundgang zu quick-260923-dhh (Proxmox-Modul) beheben --- .planning/STATE.md | 5 +- .../260923-ku6-PLAN.md | 108 ++++++++++++ .../260923-ku6-SUMMARY.md | 154 ++++++++++++++++++ 3 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 .planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-PLAN.md create mode 100644 .planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index b4d8005..5a0737b 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,9 +5,9 @@ current_phase: 18 current_phase_name: desktop-client-fertigstellen status: verified stopped_at: "22.09.2026: 1.3.0 freigegeben; danach quick-260922-hk4 — Bilderrahmen-Bilder liegen jetzt im Dateibereich (user-files) statt in der Datenbank, Umzug laeuft automatisch beim Start, Selbstheilung aus der alten data-Spalte eingebaut; im Browser nachgewiesen. NAECHSTER SCHRITT, vom Nutzer noch nicht bestaetigt: (1) einmaliges Aufraeumen, damit ein Modul seine Dashboard-Kachel selbst mitbringt (heute sieben Hartkodierungen je Kachel; Katalog zeigt auch Kacheln gesperrter Module; gesperrte Kachel bleibt leer statt zu erklaeren) — das Geruest WIDGET_MODULE_MAP existiert und ist leer; (2) danach das Proxmox-Modul (PVE/PBS/PMG) und seine Kachel. Offen beim Nutzer: Live-Server auf 1.3.0 ziehen, neuen Client per Browser installieren." -last_updated: "2026-09-23T08:40:00.000Z" +last_updated: "2026-09-23T15:12:00.000Z" last_activity: 2026-09-23 -last_activity_desc: Quick 260923-ad9 — Dashboard-Reiter (mehrere Dashboards je Benutzer, Ziehen sortiert, erster ist Standard); davor Freigabe 1.3.1 +last_activity_desc: Quick 260923-ku6 — drei Nachbesserungen aus dem Browser-Rundgang zu 260923-dhh (Proxmox-Modul): Verbindungstest prueft jetzt das Formular statt des gespeicherten Stands, ruhiger "noch nicht abgefragt"-Zustand statt Fehlermeldung, Adresse nicht mehr grossgeschrieben; davor Quick 260923-ad9 — Dashboard-Reiter (mehrere Dashboards je Benutzer, Ziehen sortiert, erster ist Standard); davor Freigabe 1.3.1 state_head: 4d485432c003a6caf68f6d85aff7de0bd27794e2 progress: total_phases: 18 @@ -465,6 +465,7 @@ Gerettet aus `.continue-here.md`. Relevant fuer die noch offenen Live-Tests. | 260922-m1h | **Ein Modul bringt seine Dashboard-Kachel jetzt selbst mit (Vorarbeit fuer Proxmox).** Bestandsaufnahme (lesend) hatte ergeben: ein neuer Widget-Typ war an SIEBEN Stellen hartkodiert (Union-Typ, Constraints, Registry, eigene `wireXWidget()` je Typ, Aufruf in page.tsx, zweite Liste im Katalogfenster, `@IsIn` im API-DTO); die Verbindung Kachel↔Modul existierte als `WIDGET_MODULE_MAP` in `dashboard.service.ts` (filtert fail-closed), war aber nie befuellt; der Katalog zeigte jedem alle Kacheln, auch die gesperrter Module. Umbau: `WIDGET_TYPES`/`WidgetType`/`WIDGET_MODULE_SLUGS` in `packages/shared` als EINE Quelle (API validiert per `@IsIn` gegen genau sie), ein generisches `registerWidget()` statt neun Funktionen, Katalog leitet seine Liste aus der Registry ab und filtert ueber `/modules/active` (fail-closed bei Fehler, reine Funktion `visibleWidgetTypes`), nicht verfuegbare Kachel zeigt `widgets.unavailable` statt leer zu bleiben. Deckungsgleichheits-Test faengt kuenftig jede vergessene Stelle. **Befund des Executors, geprueft statt vermutet:** `apps/web` hatte KEINE Abhaengigkeit auf `@tessera/shared` (frueher bewusst) — vor der Umsetzung nachgemessen, dass Bau und Produktions-Abbild das tragen (node:24-alpine strippt die Typen nativ); Folgeregel „nur loeschbare Syntax in shared“ steht als Warnung in der Datei. Verhalten der neun Kacheln unveraendert, im Browser bestaetigt (Reihenfolge, Anlegen, Entfernen, keine rohen Schluessel). Bewusst offen: der Einstellungs-Zweig je Typ in `widget-settings-panel.tsx` und die Live-Aktualisierung des Katalogs. **Zahlen:** api 1188 → 1202, web 640 → 659, type-check 4/4, lint 5/5 (74/53 wie Basis). | 2026-09-22 | 56c07c3,8be0725 | [260922-m1h-dashboard-widgets-ein-modul-bringt-seine](./quick/260922-m1h-dashboard-widgets-ein-modul-bringt-seine/) | | 260922-vdk | **Dashboard-Raster misst seine Breite auch aus dem Leerzustand heraus.** Meldung des Nutzers aus dem **Linux-Client**: rechts neben dem Kalender freie Flaeche, in die sich keine Kachel schieben laesst — „als ob es keinen Anker gibt“. Aus dem Bildschirmfoto zurueckgerechnet (Spaltenbreite 51,5 px, Platzhalter auf Spalte 13 = letzte moegliche, Rasterende bei x=1459 bei ~1660 px Inhaltsbreite): das Raster rechnete mit **1200 px** statt mit der echten Breite, rechts blieben ~460 px totes Feld. Ursache: die Breitenmessung hing in `useEffect(..., [])` mit `if (!containerRef.current) return` — haengt `DashboardGrid` mit NULL Kacheln ein, rendert der fruehe Ruecksprung in den Leerzustand den gemessenen `
` gar nicht, der Effekt bricht ab und laeuft nie wieder, auch nicht wenn spaeter die erste Kachel entsteht. `width` blieb die ganze Sitzung auf dem Startwert 1200; react-grid-layout vergleicht strikt (`width > breakpoint`), 1200 ist damit `md` (20 Spalten, 51,6 px) statt `lg`. Fix: Ref-Rueckruf `measureRef` statt Einmal-Effekt — folgt dem Knoten ueber den Wechsel Leerzustand ↔ gefuellt, misst synchron in der Commit-Phase, haengt den ResizeObserver dort an; Fenster-Horcher als zusaetzliches Netz; `applyWidth` verwirft 0 und nicht endliche Werte. **Verhalten sonst unveraendert** — belegte Plaetze bleiben gesperrt, nichts weicht aus (Ansage des Nutzers). **Geprueft im echten Client**, nicht im Browser: `Tessera-1.3.0.AppImage` auf `DISPLAY=:10` ueber den WebKit-Remote-Inspektor gesteuert. Gleicher Fehlerfall vorher/nachher: Kachel 469 px → **389 px** bei 1000 px Bereich, Ziehen endet jetzt bei 603 px = `1000 − 8 − 389`, exakt der rechte Rand. **Messfalle notiert:** im Client gegen `style.width`/`style.transform` messen, nie gegen `getBoundingClientRect()` — bei Fenster im Hintergrund friert WebKitGTK die Animationsuhr ein und der `width`-Uebergang bleibt auf dem alten Wert stehen. **Zahlen:** web 659 → 661 Tests, type-check 4/4, lint 5/5, Biome web 53 Warnungen unveraendert. | 2026-09-22 | d9f2af3,cf67c8a | [260922-vdk-dashboard-raster-misst-seine-breite-nich](./quick/260922-vdk-dashboard-raster-misst-seine-breite-nich/) | | 260923-ad9 | **Dashboard-Reiter: mehrere Dashboards je Benutzer.** Wunsch des Nutzers (23.09.): mehrere Dashboards als Reiter, per Ziehen sortierbar, der erste ist der Standard und wird beim Oeffnen geladen; „als Favorit festlegen“ = nach vorn ziehen, kein zusaetzliches Kennzeichen. Umsetzung in 5 Schritten: neues Modell `Dashboard` (userId, tenantId, name, position) mit RLS wie die Nachbartabellen; `WidgetInstance.dashboardId` und `DashboardLayout.dashboardId @unique` — Kacheln und Anordnung haengen jetzt am Reiter statt am Benutzer. Handgeschriebene Migration `20260923120000_dashboard_tabs` haengt den Bestand um: Bestandsuebernahme VOR `NOT NULL`/Fremdschluessel, danach 0 verwaiste Kacheln, 0 verwaiste Anordnungen, je Benutzer genau ein Reiter auf Position 0. Fuenf Endpunkte unter `/dashboard/tabs`; `assertOwnedDashboard` laeuft als erstes in JEDEM Lese- und Schreibweg und antwortet fuer „gibt es nicht“, „Kollege“ und „fremder Mandant“ identisch (kein Orakel) — acht eigene Tests dafuer. Umsortieren und Loeschen je EINE Transaktion nach dem Muster `FavoritesService.reorder`. Riegel: 20 Reiter, 40 Zeichen, 20 Kennungen je Anfrage. Ziehen per Pointer-Ereignissen ohne neue Abhaengigkeit (Muster xframe-Ausschnitt), ausserhalb des Bearbeitungsmodus moeglich, weil „nach vorn ziehen“ das Festlegen des Standards IST; Umbenennen und Loeschen bleiben im Bearbeitungsmodus, Loeschen mit `alertdialog`-Rueckfrage. **Raster unangetastet** (`FREE_PLACEMENT_COMPACTOR`/`preventCollision` und die Breitenmessung aus 260922-vdk) — vom Verifizierer per `git diff` nachgewiesen. **Rundgang mit zwoelf Punkten bestanden** (Bestand 5 Kacheln erhalten, Reiter leer angelegt, Kacheln je Reiter getrennt, Ziehen ordnet um, nach Neuladen kommt der erste Reiter, Umbenennen, Loeschen mit Rueckfrage, letzter Reiter ohne Loeschknopf, Kachelbreite 531 px bei 1625 px Bereich). **Kleiner Befund, offen:** die Knopf-Beschriftungen nennen den betroffenen Reiter nicht (nur das Bestaetigungsfenster tut es). **Zahlen:** api 1202 → 1240 Tests, web 661 → 693, type-check 4/4, lint 5/5 mit 53 Warnungen unveraendert, `migrate diff` ohne Unterschied. | 2026-09-23 | 9c51823,df7a5e7,d34f682,05feaa3,58ce88e | [260923-ad9-dashboard-reiter-mehrere-dashboards-je-b](./quick/260923-ad9-dashboard-reiter-mehrere-dashboards-je-b/) | +| 260923-ku6 | **Drei Nachbesserungen aus dem Browser-Rundgang zu 260923-dhh (Proxmox-Modul).** Befund 1 (wichtig): „Verbindung testen" pruefte den gespeicherten Server statt des Formulars — im Formular abgeschaltete Zertifikatspruefung oder ein neu eingetipptes Geheimnis griffen erst nach dem Speichern. Fix: neues `TestProxmoxServerDto` + Merge-Baustein `resolveEffectiveTestServer` in `ProxmoxService`, neue Route `POST servers/test` fuer die Neuanlage (noch kein gespeicherter Server), Geheimnisfelder behalten die bestehende „leer gelassen -> gespeicherten Wert weiterverwenden"-Regel. Befund 2 (wichtig): ein frisch angelegter, nie abgefragter Server zeigte faelschlich „Ein unerwarteter Fehler ist aufgetreten" statt eines ruhigen Hinweises — behoben ueber `status.lastPolledAt === null`. Befund 3 (kosmetisch): `uppercase` faerbte die ganze Statuszeile inkl. Adresse gross — jetzt nur noch das Produktkuerzel. **Zahlen:** api 1311 → 1316, web 708 → 712, type-check 4/4, lint 5/5, Biome web 53 Warnungen unveraendert. | 2026-09-23 | 710034c,f1bb7f7 | [260923-ku6-drei-nachbesserungen-aus-dem-browser-run](./quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/) | ## Deferred Items diff --git a/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-PLAN.md b/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-PLAN.md new file mode 100644 index 0000000..dec8d7a --- /dev/null +++ b/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-PLAN.md @@ -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) + + + +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 + + +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. + +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 +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. + + +### Task 2: Ruhiger Zustand fuer "noch nie abgefragt" (Befund 2) + + + +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 + + +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. + +cd apps/web && pnpm vitest run src/app/\(portal\)/modules/proxmox/components/ServerCard.test.tsx +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. + + +### Task 3: uppercase nur auf Produktkuerzel (Befund 3) + + + +apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx + + +`uppercase` von der Zeile auf ein `` um `server.productType` verschieben; die Adresse +bleibt unveraendert dargestellt. + +cd apps/web && pnpm vitest run src/app/\(portal\)/modules/proxmox/components/ServerCard.test.tsx +Adresse erscheint in der Modulseiten-Zeile nicht mehr grossgeschrieben, Produktkuerzel weiterhin schon. + + +## 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. diff --git a/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-SUMMARY.md b/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-SUMMARY.md new file mode 100644 index 0000000..e65a313 --- /dev/null +++ b/.planning/quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/260923-ku6-SUMMARY.md @@ -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 (``), 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*