docs(quick-260923-le6): Proxmox-Abnahmebefunde behoben (PMG-Teilsumme, Aktualisieren nur fuer Admins)
Uebergabe-Notizen der pausierten Sitzung entfernt, die Arbeit ist wieder aufgenommen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,149 +0,0 @@
|
|||||||
---
|
|
||||||
context: default
|
|
||||||
phase: null
|
|
||||||
task: null
|
|
||||||
total_tasks: null
|
|
||||||
status: paused
|
|
||||||
last_updated: 2026-09-23T13:15:42.473Z
|
|
||||||
---
|
|
||||||
|
|
||||||
<current_state>
|
|
||||||
Kein laufender Meilenstein; die Arbeit laeuft als Quick-Tasks. **Version 1.3.1 ist am
|
|
||||||
23.09. freigegeben** (Tag `v1.3.1` auf `ad004b2`, Abbilder `live` + `v1.3.1`, Gitea-Release
|
|
||||||
mit beiden Desktop-Paketen).
|
|
||||||
|
|
||||||
**14 Commits liegen lokal und sind NICHT gepusht.** Arbeitsbaum sauber. Der lokale Stack
|
|
||||||
laeuft mit dem Proxmox-Stand (web, api, db neu gebaut).
|
|
||||||
|
|
||||||
Unterbrochen wurde NICHT mitten in einer Aufgabe: das Proxmox-Modul ist vollstaendig gebaut,
|
|
||||||
geprueft und die drei Befunde aus dem Rundgang sind behoben. Offen ist EIN Befund aus der
|
|
||||||
Abnahme (siehe Restarbeit) und der Push.
|
|
||||||
</current_state>
|
|
||||||
|
|
||||||
<completed_work>
|
|
||||||
|
|
||||||
Diese Sitzung (22.09. abends bis 23.09. nachmittags):
|
|
||||||
|
|
||||||
- **quick-260922-vdk** — Dashboard-Raster misst seine Breite auch aus dem Leerzustand heraus.
|
|
||||||
Meldung kam aus dem **Linux-Client**; Ursache war ein `useEffect(..., [])`, das den
|
|
||||||
ResizeObserver nie anhaengte, wenn das Dashboard beim Einhaengen leer war. Breite blieb auf
|
|
||||||
dem Startwert 1200 -> rechts ein toter Streifen. Im echten AppImage gegengemessen.
|
|
||||||
- **Platte aufgeraeumt** — 3,6 GB frei -> 66 GB. Nur Wegwerf-Sachen (Docker-Build-Cache 27,9 GB,
|
|
||||||
58 verwaiste Image-Schichten 43,3 GB, verwaiste CI-Volumes).
|
|
||||||
- **Freigabe 1.3.1** — CHANGELOG abgeschlossen, `live` vorgezogen, Tag gepusht.
|
|
||||||
- **quick-260923-ad9** — Dashboard-Reiter: mehrere Dashboards je Benutzer, per Ziehen sortierbar,
|
|
||||||
der erste ist der Standard. Bestand wandert per Migration in den ersten Reiter.
|
|
||||||
- **quick-260923-dhh** — Proxmox-Modul (PVE/PBS/PMG), nur beobachten, sieben Aufgaben.
|
|
||||||
- **quick-260923-ku6** — drei Befunde aus dem Proxmox-Rundgang behoben.
|
|
||||||
|
|
||||||
Jeder Punkt wurde im Browser bzw. im echten Client geprueft; die Protokolle stehen in den
|
|
||||||
jeweiligen SUMMARY.md unter `.planning/quick/`.
|
|
||||||
</completed_work>
|
|
||||||
|
|
||||||
<remaining_work>
|
|
||||||
|
|
||||||
1. **Offener Befund der Abnahme (zuerst):** `sumOrNull` in
|
|
||||||
`apps/api/src/proxmox/proxmox-normalize.ts` liefert bei EINEM fehlenden Teilwert die halbe
|
|
||||||
Summe statt `null` — also einen stillen Falschwert genau dort, wo die Feldnamen am
|
|
||||||
schlechtesten belegt sind (PMG, Annahme A5). Ein Test fuer „nur eine Haelfte vorhanden“
|
|
||||||
fehlt bisher ganz.
|
|
||||||
2. **Kleinbefund:** „Jetzt aktualisieren“ auf der Proxmox-Modulseite wird allen mit
|
|
||||||
Modulzugriff gezeigt; der Endpunkt verlangt aber ADMIN/SUPER_ADMIN. Bei anderen passiert
|
|
||||||
beim Klick nichts.
|
|
||||||
3. **Push** (14 Commits) und CI abwarten.
|
|
||||||
4. **Proxmox-Dashboard-Kachel** als eigener kleiner Auftrag ueber den Weg aus 260922-m1h
|
|
||||||
(`WIDGET_TYPES` + `WIDGET_MODULE_SLUGS` + `registerWidget`).
|
|
||||||
5. **Freigabe 1.4.0**, sobald Reiter und Proxmox auf alpha bestaetigt sind (neue Funktionen,
|
|
||||||
also Minor, nicht Patch).
|
|
||||||
</remaining_work>
|
|
||||||
|
|
||||||
<decisions_made>
|
|
||||||
|
|
||||||
- **Proxmox: nur beobachten.** Einzige nicht-lesende Anfrage ist die Ticket-Anmeldung; sie liegt
|
|
||||||
an genau einer Stelle und `proxmox-nur-lesen.spec.ts` zaehlt sie gegen eine benannte Konstante.
|
|
||||||
- **Keine SSRF-Adresssperre** — Proxmox steht per Definition im internen Netz, eine Sperre wuerde
|
|
||||||
jede echte Adresse blockieren. Schutz ist, dass nur ein Administrator Adressen eintraegt.
|
|
||||||
- **PMG nur Benutzer/Passwort** (Recherche A1, Forenbeleg). Faellt beim Test auf, wenn es doch
|
|
||||||
Token kann — dann nachruesten.
|
|
||||||
- **Zertifikats-Ausnahme je Serverzeile**, niemals global.
|
|
||||||
- **Dashboard-Reiter:** der erste Reiter ist der Standard; „als Favorit festlegen“ heisst nach
|
|
||||||
vorn ziehen. Kein zusaetzliches Kennzeichen.
|
|
||||||
- **Dashboard-Raster:** belegter Platz bleibt gesperrt, nichts weicht aus. Nutzeransage 22.09.
|
|
||||||
- **KEIN Umbau der Proxmox-Modulseite.** Der Nutzer hat den Wunsch nach mehr Detailgrad und
|
|
||||||
Statusfarben am 23.09. ausdruecklich zurueckgezogen („vergiss das letzte, was ich geschrieben
|
|
||||||
habe“). **Nicht von selbst wieder aufgreifen.**
|
|
||||||
</decisions_made>
|
|
||||||
|
|
||||||
<blockers>
|
|
||||||
- Die Proxmox-Feldnamen bei PBS und PMG sind nicht aus erster Quelle belegt (A2/A3/A5). Nur der
|
|
||||||
Test des Nutzers auf alpha gegen echte Server klaert das. Die Auswertung ist deshalb nachsichtig
|
|
||||||
gebaut, und jede Feldnamenliste liegt als EINE benannte Konstante in `proxmox-normalize.ts`.
|
|
||||||
- Live steht moeglicherweise noch auf 1.3.0: der Nutzer hat gezogen, bevor die `live`-Abbilder
|
|
||||||
fertig waren (Tag-Lauf war zuerst rot). Ein zweiter `pull` steht aus, unbestaetigt.
|
|
||||||
</blockers>
|
|
||||||
|
|
||||||
## Required Reading (in order)
|
|
||||||
|
|
||||||
1. `.planning/quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/260923-dhh-VERIFICATION.md`
|
|
||||||
— der offene Befund steht dort mit Reproduktion.
|
|
||||||
2. `.planning/quick/260923-dhh-.../260923-dhh-RESEARCH.md` — Annahmen-Log A1…A5, die einzige
|
|
||||||
Stelle, an der steht, was an der Proxmox-Anbindung belegt und was abgeleitet ist.
|
|
||||||
3. `.planning/quick/260923-ku6-.../260923-ku6-SUMMARY.md` — die Merge-Regel des Verbindungstests
|
|
||||||
(Formular vs. gespeichert, Geheimnisfelder).
|
|
||||||
4. `.planning/STATE.md` — Abschnitt „Current Position“ und die letzten Zeilen der Quick-Tabelle.
|
|
||||||
|
|
||||||
## Critical Anti-Patterns (do NOT repeat these)
|
|
||||||
|
|
||||||
- [ANTI-PATTERN]: Im Desktop-Client gegen `getBoundingClientRect()`/`getComputedStyle()` messen →
|
|
||||||
260922-vdk: die Werte blieben auf dem ALTEN Stand, obwohl `style.width` bereits richtig war.
|
|
||||||
WebKitGTK friert die Animationsuhr ein, wenn das Fenster im Hintergrund liegt, und die
|
|
||||||
`width`-Uebergangsanimation bleibt stehen. **Mitigation:** im Client gegen die GESETZTEN Werte
|
|
||||||
messen (`style.width`, `style.transform`) oder gegen die React-Eigenschaften aus dem Fiber.
|
|
||||||
- [ANTI-PATTERN]: Ein Bestaetigungsfenster nur ueber `[role="dialog"]` suchen → der Loeschen-Dialog
|
|
||||||
der Reiter traegt `role="alertdialog"`; die Pruefung sah „es passiert nichts“, obwohl das Fenster
|
|
||||||
offen war. **Mitigation:** auf beide Rollen abfragen.
|
|
||||||
- [ANTI-PATTERN]: Nach dem Tag sofort auf dem Server `pull` ausfuehren → eine Freigabe loest DREI
|
|
||||||
Pipelines aus; faellt der Tag-Lauf um (bei 1.3.1: ein flackernder Test mit 5-Sekunden-Grenze),
|
|
||||||
werden Abbild-Bau und Desktop-Pakete UEBERSPRUNGEN, und `pull` holt still den alten Stand.
|
|
||||||
**Mitigation:** erst pruefen, dass die Abbilder `live`/`beta` einen neuen Zeitstempel tragen,
|
|
||||||
dann ziehen. Todo zum flackernden Test liegt unter `.planning/todos/pending/`.
|
|
||||||
- [ANTI-PATTERN]: Eine Vermutung ueber die Ursache aus einem Bildausschnitt ableiten → beim
|
|
||||||
Raster-Fehler fuehrte der erste Verdacht („eine Nachbarkachel blockiert“) in die Irre; erst das
|
|
||||||
volle Fenster und das Rueckrechnen der Spaltenbreite (51,5 px, letzte Spalte 13) haben die echte
|
|
||||||
Ursache gezeigt. **Mitigation:** bei Bildbefunden das GANZE Fenster anfordern, nicht den
|
|
||||||
Ausschnitt, und die Geometrie nachrechnen.
|
|
||||||
|
|
||||||
## Infrastructure State
|
|
||||||
|
|
||||||
- **Lokaler Stack:** `docker compose` mit web, api, db, gebaut auf dem Proxmox-Stand.
|
|
||||||
`up` allein baut NICHT neu. DB ohne Host-Port — Prisma vom Host ueber die Container-IP
|
|
||||||
(`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' tessera-ctl-db-1`,
|
|
||||||
`tessera:tessera_dev`).
|
|
||||||
- **Proxmox-Nachbau:** Node-Skript mit selbstsigniertem Zertifikat im Scratchpad
|
|
||||||
(`scratchpad/fake-proxmox.mjs`, Port 8006, aus dem api-Container ueber `172.21.0.1` erreichbar).
|
|
||||||
Laeuft noch; `/tmp` ueberlebt keinen Neustart, das Skript ist aber schnell neu gebaut.
|
|
||||||
Endpunkte: `/api2/json/cluster/resources`, `/status/datastore-usage`,
|
|
||||||
`/admin/datastore/{name}/snapshots`, `/statistics/mail`, `POST /access/ticket`.
|
|
||||||
- **Lokale Testdaten (duerfen weg):** zwei Proxmox-Server in der DB („Nachbau PVE“ und
|
|
||||||
„Nachbau kaputth“, letzterer absichtlich unerreichbar), Proxmox im Marktplatz aktiviert,
|
|
||||||
im Admin-Dashboard ein Reiter „Dashboard“ mit 5 Kacheln.
|
|
||||||
- **alpha** (`alpha.tessera.ctl.de`): Stand 1.3.1-Beta; Reiter und Proxmox fehlen dort noch,
|
|
||||||
weil nicht gepusht.
|
|
||||||
- **Live** (`tessera.ctl.de`): 1.3.1 freigegeben; ob der Server sie wirklich zieht, ist offen.
|
|
||||||
|
|
||||||
<context>
|
|
||||||
Der rote Faden: erst ein gemeldeter Fehler aus dem Linux-Client (Kachel liess sich nicht ganz
|
|
||||||
nach rechts ziehen), der sich als Breitenmessung entpuppte; dann Freigabe; dann zwei Wuensche des
|
|
||||||
Nutzers nacheinander — Dashboard-Reiter und das Proxmox-Modul. Beim Proxmox-Modul ist die
|
|
||||||
Besonderheit, dass hier KEIN echter Server steht: deshalb wurde ein Nachbau gebaut, die Auswertung
|
|
||||||
bewusst nachsichtig ausgelegt und jede Feldnamenliste an genau eine Stelle gelegt, damit der
|
|
||||||
Nutzer sie nach seinem Test auf alpha in einem Griff korrigieren kann.
|
|
||||||
</context>
|
|
||||||
|
|
||||||
<next_action>
|
|
||||||
Start with: den offenen Befund der Abnahme beheben — `sumOrNull` in
|
|
||||||
`apps/api/src/proxmox/proxmox-normalize.ts` muss `null` liefern, sobald EIN Teilwert fehlt
|
|
||||||
(heute `(a ?? 0) + (b ?? 0)`), plus ein Test fuer „nur eine Haelfte vorhanden“. Gleich mit
|
|
||||||
erledigen: „Jetzt aktualisieren“ nur fuer ADMIN/SUPER_ADMIN anzeigen. Danach Tore laufen lassen,
|
|
||||||
committen, die 14 Commits pushen und die CI abwarten.
|
|
||||||
</next_action>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.0",
|
|
||||||
"timestamp": "2026-09-23T13:15:42.473Z",
|
|
||||||
"phase": null,
|
|
||||||
"phase_name": "kein laufender Meilenstein — Quick-Tasks; zuletzt Proxmox-Modul",
|
|
||||||
"phase_dir": null,
|
|
||||||
"plan": null,
|
|
||||||
"task": null,
|
|
||||||
"total_tasks": null,
|
|
||||||
"status": "paused",
|
|
||||||
"completed_tasks": [
|
|
||||||
{"id": 1, "name": "quick-260922-vdk Dashboard-Raster misst seine Breite auch aus dem Leerzustand", "status": "done", "commit": "d9f2af3,cf67c8a,39b1f74"},
|
|
||||||
{"id": 2, "name": "Freigabe 1.3.1 (CHANGELOG, live-Zweig, Tag v1.3.1, Gitea-Release, Desktop-Pakete)", "status": "done", "commit": "ad004b2 (Tag v1.3.1)"},
|
|
||||||
{"id": 3, "name": "Todo notiert: flackernder Test tenant-selector blockierte die Freigabe", "status": "done", "commit": "fcad460"},
|
|
||||||
{"id": 4, "name": "quick-260923-ad9 Dashboard-Reiter (mehrere Dashboards, Ziehen sortiert, erster ist Standard)", "status": "done", "commit": "9c51823,df7a5e7,d34f682,05feaa3,58ce88e,0094a60"},
|
|
||||||
{"id": 5, "name": "quick-260923-dhh Proxmox-Modul PVE/PBS/PMG, nur beobachten", "status": "done", "commit": "3a1bfd9,4f8a368,998aba9,fccaf8d,723cf68,06fcdc0,3091b04"},
|
|
||||||
{"id": 6, "name": "quick-260923-ku6 drei Befunde aus dem Proxmox-Rundgang behoben", "status": "done", "commit": "710034c,f1bb7f7,a9e0d5b"},
|
|
||||||
{"id": 7, "name": "Platte aufgeraeumt (Docker-Build-Cache, verwaiste Images, CI-Volumes)", "status": "done", "commit": null}
|
|
||||||
],
|
|
||||||
"remaining_tasks": [
|
|
||||||
{"id": 8, "name": "OFFENER BEFUND der Abnahme: sumOrNull in normalizePmg liefert bei EINEM fehlenden Teilwert die halbe Summe statt null (stiller Falschwert)", "status": "not_started"},
|
|
||||||
{"id": 9, "name": "Kleinbefund: 'Jetzt aktualisieren' wird allen mit Modulzugriff gezeigt, der Endpunkt verlangt aber ADMIN — Klick bleibt bei anderen wirkungslos", "status": "not_started"},
|
|
||||||
{"id": 10, "name": "Push (14 Commits liegen lokal) und CI abwarten", "status": "not_started"},
|
|
||||||
{"id": 11, "name": "Proxmox-Dashboard-Kachel als eigener Auftrag (Weg aus quick-260922-m1h)", "status": "not_started"},
|
|
||||||
{"id": 12, "name": "Freigabe 1.4.0, wenn Reiter und Proxmox auf alpha bestaetigt sind", "status": "not_started"}
|
|
||||||
],
|
|
||||||
"blockers": [
|
|
||||||
{"description": "Proxmox-Feldnamen bei PBS und PMG sind nicht aus erster Quelle belegt (Annahmen A2/A3/A5) — nur der Test des Nutzers gegen echte Server klaert das", "type": "external", "workaround": "Auswertung ist nachsichtig gebaut: fehlendes/anders benanntes Feld -> 'unbekannt', nie Absturz. Feldnamenlisten liegen je als EINE benannte Konstante in proxmox-normalize.ts"},
|
|
||||||
{"description": "Der Nutzer prueft Proxmox selbst auf alpha gegen seine echten Server; hier gibt es keinen echten PVE/PBS/PMG", "type": "human_action", "workaround": "Lokal laeuft ein selbst gebauter Nachbau (HTTPS, selbstsigniert) im Scratchpad — siehe context_notes"}
|
|
||||||
],
|
|
||||||
"async_jobs": [],
|
|
||||||
"human_actions_pending": [
|
|
||||||
{"action": "Live-Server auf 1.3.1 ziehen und in der Seitenleiste 'v1.3.1 · Live' pruefen", "context": "Der Nutzer hat am 23.09. zu frueh gezogen (der Tag-Lauf war wegen eines flackernden Tests rot, die live-Abbilder entstanden erst um 07:37/07:38 nach dem Neustart). Er meldete danach '1.3.0' — ein zweiter pull steht aus, unbestaetigt.", "blocking": false},
|
|
||||||
{"action": "Nach dem Push: alpha ziehen und die Dashboard-Reiter ausprobieren", "context": "Reiter liegen seit 0094a60 in der Beta, CI war gruen. Datenbankaenderung laeuft beim API-Start automatisch mit.", "blocking": false},
|
|
||||||
{"action": "Proxmox auf alpha einrichten: Server anlegen (Adresse, Token oder Benutzer/Passwort), Zertifikats-Ausnahme setzen, 'Verbindung testen'", "context": "Erst dieser Test klaert die offenen Feldnamen-Annahmen. Nur-Lese-Rolle: PVE PVEAuditor; bei PBS und PMG die jeweils lesende Rolle.", "blocking": false}
|
|
||||||
],
|
|
||||||
"decisions": [
|
|
||||||
{"decision": "Proxmox: nur beobachten, keine Eingriffe — einzige nicht-lesende Anfrage ist die Ticket-Anmeldung, maschinell begrenzt durch proxmox-nur-lesen.spec.ts", "rationale": "Ausdrueckliche Nutzeransage 22./23.09.", "phase": null},
|
|
||||||
{"decision": "Keine SSRF-Adresssperre nach Vorbild isPublicHttpUrl", "rationale": "Proxmox steht per Definition im internen Netz — eine Sperre wuerde jede echte Adresse blockieren. Schutz ist stattdessen, dass nur ein Administrator Adressen eintraegt.", "phase": null},
|
|
||||||
{"decision": "PMG nur Benutzer/Passwort, kein API-Token", "rationale": "Recherche A1: PMG kennt offenbar keine Token (Forenbeleg, keine Primaerquelle). Faellt beim Test auf, wenn es doch geht — dann nachruesten.", "phase": null},
|
|
||||||
{"decision": "Zertifikats-Ausnahme je Serverzeile, niemals global", "rationale": "Muster LdapConfig.tlsRejectUnauthorized + undici-Dispatcher aus favorites/icon-discovery.service.ts", "phase": null},
|
|
||||||
{"decision": "Dashboard-Reiter: der ERSTE Reiter ist der Standard, 'als Favorit festlegen' = nach vorn ziehen; kein zusaetzliches Kennzeichen", "rationale": "Nutzer praezisierte sich selbst mit 'bzw.' — verschiebbare Reiter, erster ist Standard", "phase": null},
|
|
||||||
{"decision": "Dashboard-Raster: belegter Platz bleibt gesperrt, nichts weicht aus (preventCollision bleibt)", "rationale": "Ausdrueckliche Nutzeransage 22.09.: 'Da wo schon ein widget ist, soll keins hinkommen, nichts verschieben.'", "phase": null},
|
|
||||||
{"decision": "KEIN Umbau der Proxmox-Modulseite (Detailgrad/Statusfarben)", "rationale": "Der Nutzer hat den Wunsch am 23.09. ausdruecklich zurueckgezogen: 'vergiss das letzte, was ich geschrieben habe'. Nicht von selbst wieder aufgreifen.", "phase": null}
|
|
||||||
],
|
|
||||||
"uncommitted_files": [],
|
|
||||||
"next_action": "Den offenen Befund der Abnahme beheben: sumOrNull in apps/api/src/proxmox/proxmox-normalize.ts muss null liefern, sobald EIN Teilwert fehlt (heute: (a ?? 0) + (b ?? 0), also halbe Summe als vollstaendige Zahl). Test fuer 'nur eine Haelfte vorhanden' ergaenzen (fehlt heute in proxmox-normalize.spec.ts). Gleich mit erledigen: 'Jetzt aktualisieren' nur fuer ADMIN/SUPER_ADMIN anzeigen. Danach Tore laufen lassen, committen, pushen, CI abwarten.",
|
|
||||||
"context_notes": "Sitzung vom 22.09. abends bis 23.09. nachmittags. Reihenfolge: Raster-Breitenfehler (im ECHTEN Linux-Client nachgemessen, nicht im Browser) -> Platte aufgeraeumt (3,6 GB frei -> 66 GB) -> Freigabe 1.3.1 -> Dashboard-Reiter -> Proxmox-Modul. 14 Commits liegen lokal und sind NICHT gepusht. Lokale Umgebung: Container laufen mit dem Proxmox-Stand; im lokalen Dashboard des Admin liegt ein Reiter 'Dashboard' mit 5 Kacheln; in der lokalen DB stehen ZWEI Test-Proxmox-Server ('Nachbau PVE' auf https://172.21.0.1:8006 und 'Nachbau kaputth' auf Port 9999, letzterer absichtlich unerreichbar) und das Proxmox-Modul ist im Marktplatz aktiviert — alles Testdaten, duerfen weg. Der Proxmox-Nachbau (Node-Skript + selbstsigniertes Zertifikat) liegt im Scratchpad unter /tmp/claude-1000/-home-vicolab-projects-tessera-ctl/3048d06f-c57f-475e-a181-e61dc35ebe9a/scratchpad/fake-proxmox.mjs und laeuft dort noch; /tmp ueberlebt einen Neustart nicht, das Skript ist aber in 20 Zeilen neu gebaut (Endpunkte: /api2/json/cluster/resources, /status/datastore-usage, /admin/datastore/{name}/snapshots, /statistics/mail, POST /access/ticket)."
|
|
||||||
}
|
|
||||||
+2
-1
@@ -7,7 +7,7 @@ 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."
|
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-23T15:30:00.000Z"
|
last_updated: "2026-09-23T15:30:00.000Z"
|
||||||
last_activity: 2026-09-23
|
last_activity: 2026-09-23
|
||||||
last_activity_desc: Quick 260923-dhh — Proxmox-Modul gebaut und gegen einen Nachbau geprueft; drei Befunde in 260923-ku6 behoben, ein Befund der Abnahme (PMG-Teilsumme) offen
|
last_activity_desc: Quick 260923-le6 — letzte Abnahmebefunde zum Proxmox-Modul behoben (PMG-Teilsumme, Aktualisieren-Knopf nur fuer Admins); 1.3.1 laeuft auf live (Nutzer bestaetigt)
|
||||||
state_head: 4d485432c003a6caf68f6d85aff7de0bd27794e2
|
state_head: 4d485432c003a6caf68f6d85aff7de0bd27794e2
|
||||||
progress:
|
progress:
|
||||||
total_phases: 18
|
total_phases: 18
|
||||||
@@ -468,6 +468,7 @@ Gerettet aus `.continue-here.md`. Relevant fuer die noch offenen Live-Tests.
|
|||||||
| 260923-dhh | **Proxmox-Modul (PVE, PBS, PMG) — nur beobachten.** Sieben Aufgaben: Tabellen `ProxmoxServer`/`ProxmoxServerStatus` mit RLS, Zugang verschluesselt per `CryptoService`, undici-Klient mit Dispatcher nur fuer die eingetragene Adresse, Zwischenlager statt Live-Abfrage, Hintergrunddienst je Mandant (`onApplicationBootstrap`, Tender-Muster), Einstellungsseite mit Verbindungstest, Modulseite, Doku. Zugang wahlweise API-Token oder Benutzer/Passwort; **PMG nur Passwort** (Recherche A1: PMG kennt offenbar keine Token). Kopfzeilen-Formate unterscheiden sich je Produkt (`PVEAPIToken=…=…` vs. `PBSAPIToken=…:…`) und liegen an EINER Stelle. **Riegel „nur lesen“ maschinell erzwungen:** `proxmox-nur-lesen.spec.ts` zaehlt die nicht-lesenden Aufrufe gegen eine benannte Konstante — einzige Ausnahme ist die Ticket-Anmeldung. **Keine SSRF-Adresssperre** (Proxmox steht per Definition im internen Netz, eine Sperre wuerde jede echte Adresse blockieren) — Schutz ist, dass nur ein Administrator Adressen eintraegt. **Rundgang gegen einen selbst gebauten Proxmox-Nachbau** (HTTPS, selbstsigniert, echte Antwortformen): Modul im Marktplatz freigeben, Server anlegen, Zertifikatsfehler korrekt benannt, nach gesetzter Ausnahme „Verbindung erfolgreich“, Zahlen der Modulseite exakt wie im Nachbau (18/42 % Last, 3 laufend / 1 gestoppt), unerreichbarer Server meldet „Der Server ist nicht erreichbar“. **Drei Befunde daraus in 260923-ku6 behoben.** **Ein Befund der Abnahme OFFEN:** `sumOrNull` in `normalizePmg` liefert bei EINEM fehlenden Teilwert die halbe Summe statt `null` — stiller Falschwert genau dort, wo die Feldnamen am schlechtesten belegt sind. **Zahlen:** api 1240 → 1311 Tests, web 693 → 708, type-check 4/4, lint 5/5, 53 Warnungen unveraendert. | 2026-09-23 | 3a1bfd9,4f8a368,998aba9,fccaf8d,723cf68,06fcdc0,3091b04 | [260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n](./quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/) |
|
| 260923-dhh | **Proxmox-Modul (PVE, PBS, PMG) — nur beobachten.** Sieben Aufgaben: Tabellen `ProxmoxServer`/`ProxmoxServerStatus` mit RLS, Zugang verschluesselt per `CryptoService`, undici-Klient mit Dispatcher nur fuer die eingetragene Adresse, Zwischenlager statt Live-Abfrage, Hintergrunddienst je Mandant (`onApplicationBootstrap`, Tender-Muster), Einstellungsseite mit Verbindungstest, Modulseite, Doku. Zugang wahlweise API-Token oder Benutzer/Passwort; **PMG nur Passwort** (Recherche A1: PMG kennt offenbar keine Token). Kopfzeilen-Formate unterscheiden sich je Produkt (`PVEAPIToken=…=…` vs. `PBSAPIToken=…:…`) und liegen an EINER Stelle. **Riegel „nur lesen“ maschinell erzwungen:** `proxmox-nur-lesen.spec.ts` zaehlt die nicht-lesenden Aufrufe gegen eine benannte Konstante — einzige Ausnahme ist die Ticket-Anmeldung. **Keine SSRF-Adresssperre** (Proxmox steht per Definition im internen Netz, eine Sperre wuerde jede echte Adresse blockieren) — Schutz ist, dass nur ein Administrator Adressen eintraegt. **Rundgang gegen einen selbst gebauten Proxmox-Nachbau** (HTTPS, selbstsigniert, echte Antwortformen): Modul im Marktplatz freigeben, Server anlegen, Zertifikatsfehler korrekt benannt, nach gesetzter Ausnahme „Verbindung erfolgreich“, Zahlen der Modulseite exakt wie im Nachbau (18/42 % Last, 3 laufend / 1 gestoppt), unerreichbarer Server meldet „Der Server ist nicht erreichbar“. **Drei Befunde daraus in 260923-ku6 behoben.** **Ein Befund der Abnahme OFFEN:** `sumOrNull` in `normalizePmg` liefert bei EINEM fehlenden Teilwert die halbe Summe statt `null` — stiller Falschwert genau dort, wo die Feldnamen am schlechtesten belegt sind. **Zahlen:** api 1240 → 1311 Tests, web 693 → 708, type-check 4/4, lint 5/5, 53 Warnungen unveraendert. | 2026-09-23 | 3a1bfd9,4f8a368,998aba9,fccaf8d,723cf68,06fcdc0,3091b04 | [260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n](./quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/) |
|
||||||
| 260923-ku6 | **Drei Befunde aus dem Proxmox-Rundgang behoben.** (1) „Verbindung testen“ pruefte den GESPEICHERTEN Stand statt der Eingabe — wer den Zugang tippt und vor dem Speichern testet, bekam die Antwort zum alten Wert; jetzt eigene Route `POST servers/test` mit Merge-Regel: normale Felder folgen dem Formular (auch geleert), Geheimnisfelder folgen „leer → gespeicherten Wert behalten“, weil das Formular Geheimnisse nie vorbefuellt. (2) Ein frisch angelegter Server zeigte „Ein unerwarteter Fehler ist aufgetreten“, obwohl nur noch nichts abgefragt war — jetzt eigener ruhiger Zustand mit Verweis auf „Jetzt aktualisieren“. (3) Die Klasse `uppercase` faerbte die ganze Zeile und zeigte die Adresse als „HTTPS://…“ — jetzt nur noch das Produktkuerzel. **Zahlen:** api 1311 → 1316, web 708 → 712, 53 Warnungen gehalten (eine neu ausgeloeste `useOptionalChain`-Warnung gleich mit aufgeloest). | 2026-09-23 | 710034c,f1bb7f7 | [260923-ku6-drei-nachbesserungen-aus-dem-browser-run](./quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/) |
|
| 260923-ku6 | **Drei Befunde aus dem Proxmox-Rundgang behoben.** (1) „Verbindung testen“ pruefte den GESPEICHERTEN Stand statt der Eingabe — wer den Zugang tippt und vor dem Speichern testet, bekam die Antwort zum alten Wert; jetzt eigene Route `POST servers/test` mit Merge-Regel: normale Felder folgen dem Formular (auch geleert), Geheimnisfelder folgen „leer → gespeicherten Wert behalten“, weil das Formular Geheimnisse nie vorbefuellt. (2) Ein frisch angelegter Server zeigte „Ein unerwarteter Fehler ist aufgetreten“, obwohl nur noch nichts abgefragt war — jetzt eigener ruhiger Zustand mit Verweis auf „Jetzt aktualisieren“. (3) Die Klasse `uppercase` faerbte die ganze Zeile und zeigte die Adresse als „HTTPS://…“ — jetzt nur noch das Produktkuerzel. **Zahlen:** api 1311 → 1316, web 708 → 712, 53 Warnungen gehalten (eine neu ausgeloeste `useOptionalChain`-Warnung gleich mit aufgeloest). | 2026-09-23 | 710034c,f1bb7f7 | [260923-ku6-drei-nachbesserungen-aus-dem-browser-run](./quick/260923-ku6-drei-nachbesserungen-aus-dem-browser-run/) |
|
||||||
| 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/) |
|
| 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/) |
|
||||||
|
| 260923-le6 | **Zwei Abnahmebefunde zum Proxmox-Modul behoben.** (1) `sumOrNull` in `normalizePmg` liefert jetzt `null`, sobald EIN Teilwert (Spam/Viren je Richtung) fehlt — vorher stille Teilsumme als vollstaendige Zahl (Blocker aus 260923-dhh-VERIFICATION, Wahrheit 7). (2) „Jetzt aktualisieren“ nur noch fuer ADMIN/SUPER_ADMIN sichtbar (Endpunkt verlangte das schon); `ServerCard` bekommt `isAdmin`, Nicht-Admins lesen bei nie abgefragtem Server „Die Werte erscheinen nach der naechsten automatischen Abfrage“ statt eines Verweises auf den Knopf. Neuer Seitentest `proxmox-page-roles.test.tsx` (5 Rollenfaelle). Offener Randfall: inaktiver, nie abgefragter Server — Text passt dort nicht ganz, Nutzerentscheidung. Proxmox-Tests api 82, web 26 gruen; Typpruefung beider Seiten fehlerfrei; Biome ohne neue Befunde. | 2026-09-23 | c13d657,2eb86e1,2f8dd14,e1b191b | [260923-le6-proxmox-abnahmebefunde-sumornull-null-be](./quick/260923-le6-proxmox-abnahmebefunde-sumornull-null-be/) |
|
||||||
|
|
||||||
## Deferred Items
|
## Deferred Items
|
||||||
|
|
||||||
|
|||||||
+221
@@ -0,0 +1,221 @@
|
|||||||
|
---
|
||||||
|
phase: quick
|
||||||
|
plan: 260923-le6
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- apps/api/src/proxmox/proxmox-normalize.ts
|
||||||
|
- apps/api/src/proxmox/proxmox-normalize.spec.ts
|
||||||
|
- 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
|
||||||
|
- apps/web/src/app/(portal)/modules/proxmox/page.tsx
|
||||||
|
- apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx
|
||||||
|
autonomous: true
|
||||||
|
requirements: []
|
||||||
|
|
||||||
|
estimate:
|
||||||
|
tokens: 45000
|
||||||
|
raw_tokens: 45000
|
||||||
|
tasks: 3
|
||||||
|
confidence: low
|
||||||
|
|
||||||
|
must_haves:
|
||||||
|
truths:
|
||||||
|
- "PMG: fehlt von einem Paar (spamcount_in/spamcount_out bzw. viruscount_in/viruscount_out) genau eine Haelfte, ist spamCount bzw. virusCount null (Anzeige 'unbekannt') — in beide Richtungen, nie eine Teilsumme"
|
||||||
|
- "PMG: sind beide Haelften vorhanden, bleibt die Summe wie bisher (10+2 -> 12); fehlen beide, bleibt null"
|
||||||
|
- "Auf der Proxmox-Modulseite sehen nur ADMIN und SUPER_ADMIN den Knopf 'Jetzt aktualisieren'; USER (und ein noch nicht geladener Benutzer) sehen ihn nicht"
|
||||||
|
- "Ein noch nie abgefragter Server zeigt Admins weiterhin 'Noch keine Abfrage gelaufen. Klicken Sie oben auf „Jetzt aktualisieren“.'; Nicht-Admins sehen stattdessen einen Text ohne Verweis auf den Knopf"
|
||||||
|
- "Sonst aendert sich an der Modulseite nichts (Festlegung: kein Umbau, keine zusaetzlichen Details/Statusfarben)"
|
||||||
|
artifacts:
|
||||||
|
- path: apps/api/src/proxmox/proxmox-normalize.ts
|
||||||
|
provides: "sumOrNull liefert null, sobald ein Teilwert null ist"
|
||||||
|
- path: apps/api/src/proxmox/proxmox-normalize.spec.ts
|
||||||
|
provides: "Testfaelle 'nur eine Haelfte vorhanden -> null' fuer Spam und Viren, beide Richtungen"
|
||||||
|
- path: apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx
|
||||||
|
provides: "optionale Eigenschaft isAdmin (Vorgabe false), waehlt den Hinweistext fuer noch nie abgefragte Server"
|
||||||
|
- path: apps/web/src/app/(portal)/modules/proxmox/page.tsx
|
||||||
|
provides: "Aktualisieren-Knopf nur fuer Admins, reicht isAdmin an ServerCard weiter"
|
||||||
|
- path: apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx
|
||||||
|
provides: "Seitentest: Knopf sichtbar fuer ADMIN/SUPER_ADMIN, unsichtbar fuer USER/null"
|
||||||
|
key_links:
|
||||||
|
- from: "apps/web/src/app/(portal)/modules/proxmox/page.tsx"
|
||||||
|
to: "ServerCard"
|
||||||
|
via: "isAdmin={isAdmin}"
|
||||||
|
pattern: "isAdmin=\\{isAdmin\\}"
|
||||||
|
- from: "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx"
|
||||||
|
to: "apps/web/src/messages/de.json proxmox.card.notPolledYetAutomatic"
|
||||||
|
via: "t('card.notPolledYetAutomatic')"
|
||||||
|
pattern: "card\\.notPolledYetAutomatic"
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Zwei Befunde aus der Abnahme des Proxmox-Moduls beheben, sonst nichts:
|
||||||
|
|
||||||
|
1. **PMG-Teilsumme (API):** `sumOrNull(a, b)` in `apps/api/src/proxmox/proxmox-normalize.ts` addiert heute einen fehlenden Teilwert als 0, sobald nur EINE Haelfte null ist. Dadurch zeigt die Seite z. B. „Spam: 10“ als vollstaendige Tageszahl, obwohl `spamcount_out` fehlte. Das ist der in `.planning/quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/260923-dhh-VERIFICATION.md` (Wahrheit 7, Blocker) belegte Fehler. Kuenftig ist die Summe null, sobald ein Teilwert null ist.
|
||||||
|
2. **Aktualisieren-Knopf nur fuer Admins (Web):** Der Knopf „Jetzt aktualisieren“ erscheint heute bei allen, die Zugriff auf das Modul haben. Der Endpunkt `POST servers/:id/poll` verlangt aber `@Roles(Role.ADMIN, Role.SUPER_ADMIN)` (`apps/api/src/proxmox/proxmox.controller.ts:89-90`), deshalb passiert beim Klick fuer alle anderen nichts. Kuenftig sehen nur ADMIN/SUPER_ADMIN den Knopf. Der Hinweis „Noch keine Abfrage gelaufen. Klicken Sie oben auf …“ darf Nicht-Admins nicht mehr auf einen Knopf verweisen, den sie nicht sehen.
|
||||||
|
|
||||||
|
**Festlegung (locked, vom Nutzer):** KEIN Umbau der Proxmox-Modulseite. Der Nutzer hat seinen Wunsch nach mehr Details bzw. Statusfarben ausdruecklich zurueckgezogen. Nur diese zwei Korrekturen, keine weiteren Anzeige-, Layout- oder Textaenderungen.
|
||||||
|
|
||||||
|
Hinweis zum Zuschnitt: Tracer-first entfaellt (wie `--no-tracer`). Es handelt sich um zwei voneinander unabhaengige Fehlerkorrekturen, jede in genau einer Schicht, ohne neue Architektur, die ein Durchstich absichern muesste. Aufgabe 1 (API) und Aufgabe 2/3 (Web) beruehren keine gemeinsamen Dateien. Aufgabe 3 braucht die Eigenschaft `isAdmin` aus Aufgabe 2.
|
||||||
|
|
||||||
|
Purpose: Das Modul soll keinen still falschen, plausibel aussehenden Wert zeigen (eigener Anspruch in `proxmox-normalize.ts` und `ServerCard.tsx`: „ein still falscher Wert waere schlimmer als ein ehrliches unbekannt“). Ausserdem soll kein Knopf erscheinen, der fuer den Betrachter wirkungslos ist.
|
||||||
|
Output: korrigierte `sumOrNull` samt Tests; `ServerCard` mit `isAdmin`-Eigenschaft und einem zweiten Hinweistext in de/en; Modulseite, die den Knopf nur Admins zeigt, samt neuem Seitentest.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/gsd-core/workflows/execute-plan.md
|
||||||
|
@~/.claude/gsd-core/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/STATE.md
|
||||||
|
@./CLAUDE.md
|
||||||
|
@.planning/quick/260923-dhh-proxmox-modul-pve-pbs-und-pmg-anbinden-n/260923-dhh-VERIFICATION.md
|
||||||
|
|
||||||
|
@apps/api/src/proxmox/proxmox-normalize.ts
|
||||||
|
@apps/api/src/proxmox/proxmox-normalize.spec.ts
|
||||||
|
@apps/web/src/app/(portal)/modules/proxmox/page.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/app/(portal)/modules/tender-radar/settings/settings-roles.test.tsx
|
||||||
|
|
||||||
|
<interfaces>
|
||||||
|
Bereits im Code vorhanden (vom Planer gelesen, nicht erneut suchen):
|
||||||
|
|
||||||
|
- `apps/web/src/lib/stores/auth-store.ts`: `useAuthStore((s) => s.user)`, `user.role` ist `'SUPER_ADMIN' | 'ADMIN' | 'USER'`.
|
||||||
|
- `page.tsx` berechnet BEREITS `const isAdmin = user?.role === 'ADMIN' || user?.role === 'SUPER_ADMIN';` (Zeile 18-19) und nutzt es fuer den Einstellungs-Link. Das ist das etablierte Muster; es wird kein neuer Mechanismus eingefuehrt.
|
||||||
|
- `apps/web/src/lib/proxmox-api.ts`: `listServers(): Promise<ProxmoxServer[]>`, `pollServer(id: string): Promise<ProxmoxTestResult>`, Typ `ProxmoxServer` (inkl. `isActive`, `pollIntervalMin`, `status: ProxmoxServerStatus | null`).
|
||||||
|
- `ServerCard` wird ausschliesslich in `page.tsx:99` verwendet (per grep geprueft).
|
||||||
|
- Test-Muster fuer Rollen: `settings-roles.test.tsx` mockt `@/lib/stores/auth-store` mit `useAuthStore: (selector) => mockAuthStore(selector)` und setzt je Fall `mockAuthStore.mockImplementation((sel) => sel({ user }))`, ausserdem `next/link` als `<a>` und `next-intl` mit handgeschriebener Uebersetzungstabelle.
|
||||||
|
- Nachrichtendateien: nur `apps/web/src/messages/de.json` und `apps/web/src/messages/en.json`. Namensraum `proxmox.card` (de.json ab Zeile 712). `umlaut-guard.spec.ts` prueft de.json auf Ersatzschreibungen (ae/oe/ue/ss) — neue deutsche Texte brauchen echte Umlaute.
|
||||||
|
- Abfragetakt: `ProxmoxServer.pollIntervalMin` Vorgabe 5, erlaubt 1–1440 (`dto/proxmox-server.dto.ts` `@Min(1) @Max(1440)`). Der Planer laeuft je Mandant im kleinsten Intervall der aktiven Server (`proxmox-scheduler.service.ts`). Inaktive Server (`isActive: false`) werden nicht automatisch abgefragt.
|
||||||
|
</interfaces>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto" tdd="true">
|
||||||
|
<name>Aufgabe 1: PMG-Summe wird null, sobald eine Haelfte fehlt (sumOrNull)</name>
|
||||||
|
<files>apps/api/src/proxmox/proxmox-normalize.ts, apps/api/src/proxmox/proxmox-normalize.spec.ts</files>
|
||||||
|
<read_first>apps/api/src/proxmox/proxmox-normalize.ts (Zeilen 222-270), apps/api/src/proxmox/proxmox-normalize.spec.ts (Zeilen 185-240)</read_first>
|
||||||
|
<behavior>
|
||||||
|
- Nur `spamcount_in: 10` vorhanden, `spamcount_out` fehlt -> `spamCount` ist `null` (heute faelschlich 10)
|
||||||
|
- Nur `spamcount_out: 2` vorhanden, `spamcount_in` fehlt -> `spamCount` ist `null`
|
||||||
|
- Nur `viruscount_in: 1` vorhanden, `viruscount_out` fehlt -> `virusCount` ist `null`
|
||||||
|
- Nur `viruscount_out: 3` vorhanden, `viruscount_in` fehlt -> `virusCount` ist `null`
|
||||||
|
- Eine Haelfte vorhanden, die andere ist nicht lesbar (z. B. `spamcount_out: 'abc'`, `readNumber` liefert null) -> `spamCount` ist `null`
|
||||||
|
- Unabhaengigkeit der Paare: Spam unvollstaendig, Viren vollstaendig (`viruscount_in: 1, viruscount_out: 0`) -> `spamCount` null, `virusCount` 1; `countIn`/`countOut` bleiben unberuehrt
|
||||||
|
- Unveraendert gruen: die bestehenden Tests „beide vorhanden -> 12/1“, „beide fehlen -> null“, „HTML -> antwortform“
|
||||||
|
</behavior>
|
||||||
|
<action>
|
||||||
|
RED: Im bestehenden `describe('normalizePmg (Aufgabe 3, <behavior>)', ...)`-Block von `proxmox-normalize.spec.ts` neue Faelle fuer jede Zeile aus `<behavior>` ergaenzen. Das geht als einzelne `it` oder als `it.each` ueber eine Tabelle {Beschreibung, data, erwartetes spamCount, erwartetes virusCount}. Jeder Testname nennt „nur eine Haelfte vorhanden -> null“ und die Richtung (in bzw. out) sowie Spam bzw. Viren. Vorhandene Tests unveraendert lassen. Der Planer hat geprueft, dass keiner das alte Verhalten festschreibt: Die vorhandenen PMG-Tests decken nur „beide vorhanden“ und „beide fehlen“ ab, und `proxmox.service.spec.ts:350-360` liefert beide Haelften (`spamcount_in: 1, spamcount_out: 0`). Test ausfuehren, die neuen Faelle muessen ROT sein. Commit `test(260923-le6): PMG-Teilsumme ohne Haelfte muss null sein`.
|
||||||
|
|
||||||
|
GREEN: `sumOrNull(a, b)` so aendern, dass es `null` zurueckgibt, sobald `a` ODER `b` `null` ist. Nur wenn beide Zahlen sind, wird ihre Summe zurueckgegeben. Die bisherige Ersatz-durch-Null-Addition entfaellt vollstaendig, ein fehlender Teilwert wird nie mehr als 0 behandelt. Ueber der Funktion einen kurzen deutschen Kommentar ergaenzen (Stil der Datei, ASCII-Umschreibungen wie im Rest der Datei): Eine Tageszahl aus zwei Teilwerten ist nur dann bekannt, wenn beide Teilwerte bekannt sind; eine Teilsumme saehe vollstaendig aus, waere aber still falsch (Abnahmebefund 260923-dhh, Wahrheit 7; PMG-Feldnamen sind nur Annahme A5). `normalizePmg` selbst und die Feldtabelle `PMG_STATS_FIELDS` bleiben unveraendert. Tests muessen GRUEN sein. Commit `fix(260923-le6): PMG-Summe null bei fehlendem Teilwert`.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>pnpm --filter api exec vitest run src/proxmox</automated>
|
||||||
|
<automated>test "$(grep -v '^\s*//' apps/api/src/proxmox/proxmox-normalize.ts | grep -c '?? 0) + (')" -eq 0</automated>
|
||||||
|
<automated>pnpm --filter api type-check</automated>
|
||||||
|
</verify>
|
||||||
|
<done>Alle Tests unter `apps/api/src/proxmox` gruen, darunter mindestens 5 neue Faelle „nur eine Haelfte vorhanden -> null“ (Spam in/out, Viren in/out, nicht lesbare Haelfte). Die Ersatz-durch-Null-Addition steht nicht mehr in `proxmox-normalize.ts`. API-Typpruefung ohne Fehler.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto" tdd="true">
|
||||||
|
<name>Aufgabe 2: ServerCard waehlt den Hinweistext nach Rolle (isAdmin) und zweiter Text in de/en</name>
|
||||||
|
<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>
|
||||||
|
<read_first>apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx (Zeilen 150-215), apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx, apps/web/src/messages/de.json (Zeilen 706-720), apps/web/src/messages/en.json (Zeilen 706-720)</read_first>
|
||||||
|
<behavior>
|
||||||
|
- `isAdmin` gesetzt, Server nie abgefragt (`status.lastPolledAt === null`) -> Text „Noch keine Abfrage gelaufen. Klicken Sie oben auf „Jetzt aktualisieren“.“ (wie heute)
|
||||||
|
- `isAdmin={false}`, Server nie abgefragt -> Text „Noch keine Abfrage gelaufen. Die Werte erscheinen nach der nächsten automatischen Abfrage.“, und nirgends in der Karte steht „Jetzt aktualisieren“
|
||||||
|
- `isAdmin` weggelassen -> verhaelt sich wie `isAdmin={false}` (sichere Vorgabe)
|
||||||
|
- Weiterhin in keinem der Faelle die Sammelmeldung „Unerwarteter Fehler.“
|
||||||
|
</behavior>
|
||||||
|
<action>
|
||||||
|
Umsetzung der zweiten Korrektur, Teil Karte.
|
||||||
|
|
||||||
|
(a) Nachrichten: In `apps/web/src/messages/de.json` unter `proxmox.card`, direkt nach `notPolledYet`, den neuen Schluessel `notPolledYetAutomatic` mit dem Wert „Noch keine Abfrage gelaufen. Die Werte erscheinen nach der nächsten automatischen Abfrage.“ anlegen. Echtes „ä“ verwenden (umlaut-guard), Sie-Form bzw. unpersoenlich wie die uebrigen App-Texte. In `apps/web/src/messages/en.json` an derselben Stelle `notPolledYetAutomatic`: „No poll has run yet. The values will appear after the next automatic poll.“ Andere Schluessel nicht anfassen; `notPolledYet`, `refresh` und `refreshing` bleiben unveraendert. Begruendung der Wortwahl (Planer-Ermessen, Vorschlag aus dem Auftrag angepasst): Ein „in Kürze“ waere nicht immer wahr, denn das Intervall ist je Server von 1 bis 1440 Minuten einstellbar (`@Max(1440)`). „Nach der nächsten automatischen Abfrage“ stimmt bei jedem Intervall und verweist auf keinen Knopf.
|
||||||
|
|
||||||
|
(b) `ServerCard.tsx`: `ServerCardProps` um die optionale Eigenschaft `isAdmin?: boolean` erweitern und in der Funktionssignatur mit Vorgabe `false` entgegennehmen. Die sichere Vorgabe bedeutet: Wer die Eigenschaft vergisst, zeigt keinen Verweis auf einen Knopf. Im vorhandenen Zweig fuer nie abgefragte Server (`status && !status.lastPolledAt`) den Text nach `isAdmin` waehlen. Ist `isAdmin` wahr, bleibt der heutige Aufruf `t('card.notPolledYet', { refreshLabel: t('card.refresh') })` unveraendert, sonst `t('card.notPolledYetAutomatic')`. Den Kommentar „Nachbesserung Befund 2“ um einen Satz ergaenzen: Nicht-Admins sehen den Knopf nicht (der Poll-Endpunkt verlangt ADMIN/SUPER_ADMIN) und bekommen deshalb den Text ohne Knopfverweis (260923-le6). Sonst NICHTS an der Karte aendern, auch keine Formatierung unbeteiligter Zeilen (Festlegung: kein Umbau). Insbesondere kein `biome format --write` auf die ganze Datei, das wuerde unbeteiligte Zeilen umbrechen.
|
||||||
|
|
||||||
|
(c) `ServerCard.test.tsx`: In die `next-intl`-Mock-Tabelle `'card.notPolledYetAutomatic'` mit dem deutschen Text aus (a) aufnehmen. Den bestehenden Test „Nachbesserung Befund 2: …“ auf `render(<ServerCard server={server} isAdmin />)` umstellen; seine Erwartungen bleiben. Neue Tests fuer die Faelle aus `<behavior>` ergaenzen: `isAdmin={false}` sowie weggelassenes `isAdmin` jeweils mit Erwartung des automatischen Textes, `queryByText(/Jetzt aktualisieren/)` ist `null` und `queryByText('Unerwarteter Fehler.')` ist `null`. Zuerst die Tests schreiben und ROT sehen, dann (a)+(b) umsetzen und GRUEN sehen. Ein Commit genuegt: `fix(260923-le6): Proxmox-Karte verweist Nicht-Admins nicht auf den Aktualisieren-Knopf`.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>pnpm --filter web exec vitest run "src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx" src/messages</automated>
|
||||||
|
<automated>node -e "const d=require('./apps/web/src/messages/de.json'),e=require('./apps/web/src/messages/en.json');const a=d.proxmox.card.notPolledYetAutomatic,b=e.proxmox.card.notPolledYetAutomatic;if(!a||!b||/aktualisieren/i.test(a)||/refresh/i.test(b)||!a.includes('nächsten'))process.exit(1);if(d.proxmox.card.notPolledYet!=='Noch keine Abfrage gelaufen. Klicken Sie oben auf „{refreshLabel}“.')process.exit(2)"</automated>
|
||||||
|
</verify>
|
||||||
|
<done>ServerCard-Tests gruen (bestehende und neue Admin-/Nicht-Admin-Faelle); `src/messages`-Tests (umlaut-guard, Paritaet) gruen. `notPolledYetAutomatic` existiert in de und en und erwaehnt keinen Aktualisieren-Knopf. `notPolledYet` ist unveraendert.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto" tdd="true">
|
||||||
|
<name>Aufgabe 3: Modulseite zeigt „Jetzt aktualisieren“ nur ADMIN/SUPER_ADMIN, mit Seitentest</name>
|
||||||
|
<files>apps/web/src/app/(portal)/modules/proxmox/page.tsx, apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx</files>
|
||||||
|
<read_first>apps/web/src/app/(portal)/modules/proxmox/page.tsx, apps/web/src/app/(portal)/modules/tender-radar/settings/settings-roles.test.tsx (Zeilen 1-100, nur das Mock-Muster)</read_first>
|
||||||
|
<behavior>
|
||||||
|
- Rolle USER, eine Serverliste mit einem nie abgefragten Server -> kein Knopf mit Namen „Jetzt aktualisieren“; der Karten-Hinweis ist der automatische Text
|
||||||
|
- Kein Benutzer geladen (`user: null`) -> kein Knopf
|
||||||
|
- Rolle ADMIN -> Knopf „Jetzt aktualisieren“ sichtbar; der Karten-Hinweis ist der Admin-Text mit Knopfverweis
|
||||||
|
- Rolle SUPER_ADMIN -> Knopf sichtbar
|
||||||
|
- Leere Serverliste bei ADMIN -> weiterhin kein Knopf (bestehende Bedingung `servers.length > 0` bleibt)
|
||||||
|
</behavior>
|
||||||
|
<action>
|
||||||
|
Umsetzung der zweiten Korrektur, Teil Seite.
|
||||||
|
|
||||||
|
(a) Neue Testdatei `apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx` nach dem Muster von `settings-roles.test.tsx` anlegen. Gemockt werden `@/lib/proxmox-api` (`listServers` als `vi.fn()`, der je Fall eine Liste aufloest, und `pollServer` als `vi.fn()`), `@/lib/stores/auth-store` (Selektor-Durchreichung ueber `mockAuthStore`), `next/link` (als `<a>`) und `next-intl`. Die handgeschriebene Uebersetzungstabelle enthaelt mindestens `title`, `description`, `loading`, `loadError`, `emptyState`, `card.refresh`, `card.refreshing`, `card.settingsLink`, `card.unknownValue`, `card.lastPolledLabel`, `card.notPolledYet` (mit `{refreshLabel}`-Ersetzung wie in `ServerCard.test.tsx`) und `card.notPolledYetAutomatic`. Die Seite ueber `import ProxmoxPage from './page'` rendern. Mit `waitFor`/`findByText` auf den Servernamen warten, weil `listServers` asynchron ist. Danach Knopf per `queryByRole('button', { name: 'Jetzt aktualisieren' })` bzw. `getByRole` pruefen. Ein Testfall je Zeile aus `<behavior>`; der Server im Test ist ein nie abgefragter Server (Status wie im Befund-2-Test von `ServerCard.test.tsx`: `lastPolledAt: null`, `reachable: false`, `errorKind: null`). `afterEach` mit `cleanup()` und `vi.clearAllMocks()`. Test ausfuehren, die USER- und null-Faelle muessen ROT sein.
|
||||||
|
|
||||||
|
(b) `page.tsx`: Die bestehende Bedingung des Aktualisieren-Knopfs (`servers !== null && servers.length > 0`) zusaetzlich an `isAdmin` knuepfen, sodass der Knopf nur fuer ADMIN/SUPER_ADMIN gerendert wird. Die vorhandene Variable `isAdmin` wiederverwenden, keinen neuen Rollen-Mechanismus einfuehren. `handleRefresh` bleibt unveraendert. An der Render-Stelle `<ServerCard server={server} />` die Eigenschaft `isAdmin={isAdmin}` weiterreichen. Den Kopfkommentar der Komponente um einen Satz ergaenzen: Der Knopf erscheint nur fuer Admins, weil `POST servers/:id/poll` `@Roles(ADMIN, SUPER_ADMIN)` verlangt; fuer andere waere er wirkungslos (260923-le6). Sonst nichts an der Seite aendern: keine neuen Texte, kein Layout, keine Import-Umsortierung. Das vorbestehende organizeImports-Signal von biome in dieser Datei bleibt unangetastet.
|
||||||
|
|
||||||
|
Tests GRUEN sehen. Commit `fix(260923-le6): Aktualisieren-Knopf der Proxmox-Seite nur fuer Admins`.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>pnpm --filter web exec vitest run "src/app/(portal)/modules/proxmox"</automated>
|
||||||
|
<automated>grep -c 'isAdmin={isAdmin}' "apps/web/src/app/(portal)/modules/proxmox/page.tsx"</automated>
|
||||||
|
<automated>pnpm --filter web type-check</automated>
|
||||||
|
</verify>
|
||||||
|
<done>Alle Web-Tests im Proxmox-Verzeichnis gruen (ServerCard, ServerForm, neuer Seitentest mit mindestens 5 Faellen: USER, null, ADMIN, SUPER_ADMIN, leere Liste). `page.tsx` reicht `isAdmin={isAdmin}` an `ServerCard` weiter. Web-Typpruefung ohne Fehler.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<threat_model>
|
||||||
|
## Trust Boundaries
|
||||||
|
|
||||||
|
| Boundary | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| Browser -> API `POST /proxmox/servers/:id/poll` | Nicht-Admin koennte die Abfrage manuell ausloesen; die Berechtigung prueft ausschliesslich der Server (`@Roles(ADMIN, SUPER_ADMIN)`) |
|
||||||
|
| PMG-Server -> `normalizePmg` | Fremde, nur angenommene Antwortform (Annahme A5); unvollstaendige Felder duerfen keinen falschen Wert erzeugen |
|
||||||
|
|
||||||
|
## STRIDE Threat Register
|
||||||
|
|
||||||
|
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||||
|
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||||
|
| T-le6-01 | Elevation of Privilege | `POST servers/:id/poll` | low | accept | Das Ausblenden des Knopfes ist reine Oberflaeche, keine Sicherheitsgrenze. Die Durchsetzung bleibt unveraendert serverseitig per `@Roles(Role.ADMIN, Role.SUPER_ADMIN)` in `proxmox.controller.ts:89-90`. Dieser Plan aendert den Controller nicht. |
|
||||||
|
| T-le6-02 | Tampering (Integritaet der Anzeige) | `sumOrNull` in `normalizePmg` | medium | mitigate | Aufgabe 1: Summe null, sobald ein Teilwert fehlt oder unlesbar ist. Die neuen Tests decken beide Richtungen fuer Spam und Viren ab. |
|
||||||
|
| T-le6-03 | Information Disclosure | `ServerCard` Hinweistext | low | accept | Der neue Text enthaelt keine Server- oder Zugangsdaten, nur einen statischen Hinweis. |
|
||||||
|
</threat_model>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Nach allen drei Aufgaben (vom Planer an der Ausgangslage 6530ae5 geprueft: alles gruen, `biome lint` sauber):
|
||||||
|
|
||||||
|
- `pnpm --filter api exec vitest run src/proxmox` gruen
|
||||||
|
- `pnpm --filter web exec vitest run "src/app/(portal)/modules/proxmox" src/messages` gruen
|
||||||
|
- `pnpm --filter api type-check` und `pnpm --filter web type-check` ohne Fehler
|
||||||
|
- `pnpm exec biome lint apps/api/src/proxmox/proxmox-normalize.ts apps/api/src/proxmox/proxmox-normalize.spec.ts "apps/web/src/app/(portal)/modules/proxmox/page.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/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx"` ohne Befund
|
||||||
|
- `pnpm exec biome check "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx"` ohne Befund (neue Datei, voll konform)
|
||||||
|
- `biome check` auf den fuenf VORHANDENEN Dateien: vorher 6 Befunde, alle vorbestehend (Formatierung je Datei, dazu organizeImports in `page.tsx`). Deren Anzahl darf nicht steigen. Die vorbestehenden Befunde werden nicht mit behoben, das waere fremder Diff (Festlegung: kein Umbau).
|
||||||
|
- Keine Container-Neubauten, kein Deploy, keine Browserpruefung in diesem Plan
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- Eine PMG-Antwort mit nur einer Haelfte eines Spam- oder Viren-Paares ergibt `null`, die Seite zeigt dort also „unbekannt“ statt einer Teilsumme.
|
||||||
|
- Auf der Proxmox-Modulseite sehen nur ADMIN und SUPER_ADMIN „Jetzt aktualisieren“. Der Hinweis fuer nie abgefragte Server verweist Nicht-Admins auf die automatische Abfrage statt auf den Knopf.
|
||||||
|
- Sonst keine sichtbare Aenderung an der Modulseite.
|
||||||
|
- In der SUMMARY als Beobachtung vermerken, nicht beheben: Inaktive Server (`isActive: false`) werden nicht automatisch abgefragt. Fuer einen inaktiven, nie abgefragten Server stimmt der neue Nicht-Admin-Text deshalb nicht ganz. Das ist ein vorbestehender Randfall, denn auch die Karte fuer Admins beachtet `isActive` heute nicht. Er liegt ausserhalb dieses Auftrags (Festlegung: kein Umbau) und wird dem Nutzer zur Entscheidung vorgelegt.
|
||||||
|
- In der SUMMARY vermerken, dass damit die offene Luecke (Wahrheit 7) aus `260923-dhh-VERIFICATION.md` geschlossen ist.
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
Create `.planning/quick/260923-le6-proxmox-abnahmebefunde-sumornull-null-be/260923-le6-SUMMARY.md` when done
|
||||||
|
</output>
|
||||||
+174
@@ -0,0 +1,174 @@
|
|||||||
|
---
|
||||||
|
phase: quick
|
||||||
|
plan: 260923-le6
|
||||||
|
subsystem: proxmox-modul
|
||||||
|
tags: [nestjs, next-intl, vitest, tdd, proxmox]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: quick-260923-dhh
|
||||||
|
provides: "Proxmox-Modul (PVE/PBS/PMG) inklusive normalizePmg und ServerCard; Abnahmebefund Wahrheit 7 (PMG-Teilsumme) blieb offen"
|
||||||
|
provides:
|
||||||
|
- "sumOrNull liefert null, sobald ein Teilwert einer PMG-Summe (Spam/Viren) fehlt oder unlesbar ist — nie mehr eine Teilsumme"
|
||||||
|
- "ServerCard zeigt Nicht-Admins fuer nie abgefragte Server einen Hinweis ohne Knopfverweis (isAdmin-Eigenschaft, Vorgabe false)"
|
||||||
|
- "Proxmox-Modulseite zeigt den Knopf 'Jetzt aktualisieren' nur ADMIN/SUPER_ADMIN"
|
||||||
|
affects: [proxmox-modul, dashboard-kachel-proxmox]
|
||||||
|
|
||||||
|
actuals:
|
||||||
|
tokens: 4581
|
||||||
|
tasks: 3
|
||||||
|
commits: 4
|
||||||
|
plan_head_before: 6530ae5
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "isAdmin?: boolean (Vorgabe false) als sichere Eigenschaft fuer UI-Elemente, deren serverseitige Aktion rollenbeschraenkt ist (uebernimmt das bestehende Muster aus page.tsx, kein neuer Mechanismus)"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx
|
||||||
|
modified:
|
||||||
|
- apps/api/src/proxmox/proxmox-normalize.ts
|
||||||
|
- apps/api/src/proxmox/proxmox-normalize.spec.ts
|
||||||
|
- 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
|
||||||
|
- apps/web/src/app/(portal)/modules/proxmox/page.tsx
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Wortwahl fuer notPolledYetAutomatic: 'nach der naechsten automatischen Abfrage' statt 'in Kuerze', weil das Poll-Intervall je Server 1-1440 Minuten einstellbar ist und 'in Kuerze' nicht immer zutraefe"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "sumOrNull(a, b): null wenn a ODER b null ist (statt Ersatz-durch-Null) — Muster fuer jede zukuenftige Tageszahl aus zwei Teilwerten"
|
||||||
|
|
||||||
|
requirements-completed: []
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
- id: D1
|
||||||
|
description: "PMG-Summe (Spam/Viren) ist null, sobald genau eine Haelfte fehlt oder unlesbar ist — in beide Richtungen (in/out), Paare unabhaengig voneinander"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#nur eine Haelfte vorhanden -> null (Spam, nur spamcount_in)"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#nur eine Haelfte vorhanden -> null (Spam, nur spamcount_out)"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#nur eine Haelfte vorhanden -> null (Viren, nur viruscount_in)"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#nur eine Haelfte vorhanden -> null (Viren, nur viruscount_out)"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#eine Haelfte ist nicht lesbar -> null (Spam, spamcount_out ist Text)"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/api/src/proxmox/proxmox-normalize.spec.ts#Unabhaengigkeit der Paare: Spam unvollstaendig, Viren vollstaendig"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D2
|
||||||
|
description: "Auf der Proxmox-Modulseite sehen nur ADMIN/SUPER_ADMIN den Knopf 'Jetzt aktualisieren'; USER und ein noch nicht geladener Benutzer sehen ihn nicht; ServerCard verweist Nicht-Admins nicht auf den Knopf"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx#Rolle USER: kein Knopf"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx#kein Benutzer geladen (user: null): kein Knopf"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx#Rolle ADMIN: Knopf sichtbar"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx#Rolle SUPER_ADMIN: Knopf sichtbar"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx#leere Serverliste bei ADMIN: weiterhin kein Knopf"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx#260923-le6: isAdmin={false}, noch nie abgefragt -> automatischer Hinweis ohne Knopfverweis"
|
||||||
|
status: pass
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx#260923-le6: isAdmin weggelassen -> verhaelt sich wie isAdmin={false}"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
|
||||||
|
duration: 21min
|
||||||
|
completed: 2026-09-23
|
||||||
|
status: complete
|
||||||
|
---
|
||||||
|
|
||||||
|
# Quick Task 260923-le6: Zwei Abnahmebefunde des Proxmox-Moduls behoben Summary
|
||||||
|
|
||||||
|
**PMG-Teilsumme wird null statt still falsch (sumOrNull), Aktualisieren-Knopf der Proxmox-Modulseite nur noch fuer ADMIN/SUPER_ADMIN sichtbar**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 21 min
|
||||||
|
- **Started:** 2026-09-23T13:12:00Z
|
||||||
|
- **Completed:** 2026-09-23T13:33:50Z
|
||||||
|
- **Tasks:** 3
|
||||||
|
- **Files modified:** 8 (7 geaendert, 1 neu)
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- `sumOrNull(a, b)` in `proxmox-normalize.ts` liefert `null`, sobald ein Teilwert (Spam oder Viren, je Richtung in/out) fehlt oder nicht lesbar ist — die bisherige stille Ersatz-durch-0-Addition ist vollstaendig entfernt. Damit ist Wahrheit 7 (Blocker) aus `260923-dhh-VERIFICATION.md` geschlossen.
|
||||||
|
- `ServerCard` bekommt die optionale Eigenschaft `isAdmin` (Vorgabe `false`) und zeigt Nicht-Admins fuer einen nie abgefragten Server einen neuen Hinweistext (`proxmox.card.notPolledYetAutomatic`, de/en), der auf keinen Knopf verweist.
|
||||||
|
- Die Proxmox-Modulseite zeigt den Knopf "Jetzt aktualisieren" nur noch, wenn `isAdmin` wahr ist (bestehende Variable wiederverwendet, kein neuer Rollen-Mechanismus), und reicht `isAdmin` an `ServerCard` weiter.
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Alle Aufgaben wurden per TDD (RED -> GREEN) umgesetzt und einzeln committet:
|
||||||
|
|
||||||
|
1. **Aufgabe 1 (RED): PMG-Teilsumme-Tests** - `c13d657` (test)
|
||||||
|
2. **Aufgabe 1 (GREEN): sumOrNull korrigiert** - `2eb86e1` (fix)
|
||||||
|
3. **Aufgabe 2: ServerCard mit isAdmin und zweitem Hinweistext** - `2f8dd14` (fix)
|
||||||
|
4. **Aufgabe 3: Aktualisieren-Knopf nur fuer Admins** - `e1b191b` (fix)
|
||||||
|
|
||||||
|
_Hinweis: Aufgabe 1 hatte planmaessig zwei Commits (RED/GREEN); Aufgaben 2 und 3 wurden je in einem Commit umgesetzt, wie im Plan vorgesehen (Tests zuerst rot gesehen, dann implementiert, ein Commit je Aufgabe)._
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `apps/api/src/proxmox/proxmox-normalize.ts` - `sumOrNull` liefert `null` bei fehlendem Teilwert statt Ersatz-durch-0
|
||||||
|
- `apps/api/src/proxmox/proxmox-normalize.spec.ts` - 6 neue Testfaelle fuer beide Richtungen (Spam/Viren), unlesbare Haelfte, Unabhaengigkeit der Paare
|
||||||
|
- `apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx` - neue `isAdmin`-Eigenschaft (Vorgabe `false`), waehlt den Hinweistext fuer nie abgefragte Server
|
||||||
|
- `apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.test.tsx` - bestehenden Test auf `isAdmin` umgestellt, zwei neue Faelle (`isAdmin={false}`, weggelassen)
|
||||||
|
- `apps/web/src/messages/de.json` / `en.json` - neuer Schluessel `proxmox.card.notPolledYetAutomatic`
|
||||||
|
- `apps/web/src/app/(portal)/modules/proxmox/page.tsx` - Knopf nur bei `isAdmin`, reicht `isAdmin={isAdmin}` an `ServerCard` weiter
|
||||||
|
- `apps/web/src/app/(portal)/modules/proxmox/proxmox-page-roles.test.tsx` (neu) - Seitentest mit 5 Faellen (USER, `user: null`, ADMIN, SUPER_ADMIN, leere Liste bei ADMIN)
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
- Formulierung "Noch keine Abfrage gelaufen. Die Werte erscheinen nach der naechsten automatischen Abfrage." statt eines "in Kuerze"-Hinweises, weil das Poll-Intervall je Server zwischen 1 und 1440 Minuten liegen kann (`@Max(1440)`) — die gewaehlte Formulierung stimmt bei jedem Intervall und verweist auf keinen Knopf.
|
||||||
|
- Keine weiteren Aenderungen an der Modulseite (Festlegung des Nutzers: kein Umbau, keine zusaetzlichen Details oder Statusfarben) — bestaetigt eingehalten.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan genau wie geschrieben ausgefuehrt.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Beobachtungen (nicht behoben, dem Nutzer zur Entscheidung vorgelegt)
|
||||||
|
- **Inaktive Server:** Ein inaktiver, nie abgefragter Server (`isActive: false`) wird nicht automatisch abgefragt (`proxmox-scheduler.service.ts` fragt nur aktive Server ab). Der neue Nicht-Admin-Hinweistext "...erscheinen nach der naechsten automatischen Abfrage" trifft fuer diesen Randfall nicht ganz zu. Das ist ein vorbestehender Randfall — auch die Admin-Karte beachtet `isActive` heute nicht — und liegt ausserhalb dieses Auftrags (Festlegung: kein Umbau). Wird hier nur vermerkt, nicht behoben.
|
||||||
|
|
||||||
|
## Verifikation (alle gruen, wie im Plan verlangt)
|
||||||
|
- `pnpm --filter api exec vitest run src/proxmox` - 82 Tests gruen (26 in `proxmox-normalize.spec.ts`, davon 6 neu)
|
||||||
|
- `pnpm --filter web exec vitest run "src/app/(portal)/modules/proxmox" src/messages` - 32 Tests gruen
|
||||||
|
- `pnpm --filter api type-check` und `pnpm --filter web type-check` - ohne Fehler
|
||||||
|
- `biome lint` auf den 6 Plan-Dateien - ohne Befund
|
||||||
|
- `biome check` auf der neuen Datei `proxmox-page-roles.test.tsx` - ohne Befund (nach `biome check --write` fuer Formatierung)
|
||||||
|
- `biome check` auf den 5 vorbestehenden Dateien - weiterhin genau 6 Befunde (vorbestehende Formatierung + `organizeImports` in `page.tsx`), keine neuen Befunde — wie im Plan festgelegt nicht behoben (fremder Diff)
|
||||||
|
- Keine Container-Neubauten, kein Deploy, keine Browserpruefung — wie im Plan vorgesehen
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
None - keine externe Konfiguration noetig.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
- Die offene Luecke (Wahrheit 7) aus `260923-dhh-VERIFICATION.md` ist geschlossen; das Proxmox-Modul hat keine bekannten offenen Abnahmebefunde mehr.
|
||||||
|
- Offen beim Nutzer (keine Entscheidung noetig, nur zur Kenntnis): der oben vermerkte Randfall bei inaktiven, nie abgefragten Servern.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
Alle im Plan genannten Dateien wurden gefunden, alle vier Commits sind im Log nachweisbar.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Plan: 260923-le6*
|
||||||
|
*Completed: 2026-09-23*
|
||||||
Reference in New Issue
Block a user