Files

16 KiB
Raw Permalink Blame History

phase, plan, subsystem, tags, dependency-graph, tech-stack, key-files, decisions, metrics, actuals, plan_head_before, status
phase plan subsystem tags dependency-graph tech-stack key-files decisions metrics actuals plan_head_before status
quick-260923-dhh 01 infrastructure
proxmox
pve
pbs
pmg
undici
scheduler
rls
module-registry
nestjs
next-intl
requires provides affects
proxmox-module
proxmox-server-model
proxmox-background-poller
apps/api/src/proxmox
apps/web/src/app/(portal)/modules/proxmox
apps/web/src/lib/proxmox-api.ts
added patterns
undiciFetch statt globalem fetch fuer einen bedingten TLS-Dispatcher (zweites, unabhaengiges Auftreten nach icon-discovery.service.ts)
Nur-Lese-Riegel per Quelltext-Analyse (proxmox-nur-lesen.spec.ts), Vorbild rls-access-inventory.spec.ts
Scheduler kombiniert DkvSchedulerService-Mandanten-Fan-out mit TenderSchedulerService-onApplicationBootstrap-Timing
select ohne Geheimnisfelder statt nachtraeglicher Maskierung
created modified
apps/api/prisma/migrations/20260923140000_proxmox_server/migration.sql
apps/api/src/proxmox/proxmox.types.ts
apps/api/src/proxmox/proxmox-auth.ts
apps/api/src/proxmox/proxmox-client.service.ts
apps/api/src/proxmox/proxmox-normalize.ts
apps/api/src/proxmox/proxmox.service.ts
apps/api/src/proxmox/proxmox-scheduler.service.ts
apps/api/src/proxmox/proxmox.controller.ts
apps/api/src/proxmox/proxmox.module.ts
apps/api/src/proxmox/proxmox.seed.ts
apps/api/src/proxmox/dto/proxmox-server.dto.ts
apps/api/src/proxmox/proxmox-nur-lesen.spec.ts
apps/web/src/app/(portal)/modules/proxmox/page.tsx
apps/web/src/app/(portal)/modules/proxmox/layout.tsx
apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx
apps/web/src/app/(portal)/modules/proxmox/settings/page.tsx
apps/web/src/app/(portal)/modules/proxmox/settings/components/ServerForm.tsx
apps/web/src/lib/proxmox-api.ts
apps/api/prisma/schema.prisma
apps/api/src/app.module.ts
apps/api/src/prisma/rls-access-inventory.spec.ts
apps/web/src/lib/module-loader.ts
apps/web/src/messages/de.json
apps/web/src/messages/en.json
apps/web/src/messages/umlaut-dictionary.ts
docs/mandantentrennung-zugriffsklassifikation.md
docs/anleitung-entwicklung.md
docs/anleitung-anwender.md
D-01 bis D-11 aus dem Plan woertlich umgesetzt, keine Abweichung.
proxmoxGet uebergibt bewusst KEIN method-Feld an undiciFetch (GET ist der Grundwert) — dadurch ist loginTicket() in proxmox-auth.ts die einzige Stelle, die ein Anfrageverfahren explizit uebergibt, und proxmox-nur-lesen.spec.ts kann das maschinell auf genau EINS pruefen.
Ticket-Erneuerung sitzt je POLL-DURCHLAUF, nicht je Aufruf: ein PBS-Durchlauf mit mehreren Folgeabfragen (Belegung + je Datenspeicher Sicherungen) loggt sich bei 401 hoechstens einmal neu ein, nicht einmal je Anfrage.
proxmox.service.ts ist der EINZIGE forSystem()-Aufrufer des Moduls (loadActiveServersForScheduler) — in FORSYSTEM_ALLOWED_CALL_SITES eingetragen, Stand von ProxmoxServer auf system-gebunden gehoben.
docs/anwenderhandbuch.md aus dem Plan existiert nicht im Repo — der echte Dateiname ist docs/anleitung-anwender.md; dort den Proxmox-Abschnitt eingefuegt (Rule 3).
duration completed
~5h (Session unterbrochen und fortgesetzt) 2026-09-23
tokens tasks commits
50829 7 7
ec9c779 complete

Quick 260923-dhh: Proxmox-Modul (PVE/PBS/PMG) — nur beobachten Summary

Vollstaendiges Proxmox-Modul (Datenbank, Dienst, API, Hintergrundabfrage je Mandant, Einstellungsseite, Modulseite, Dokumentation) — PVE/PBS/PMG werden per API-Token (PVE/PBS) oder Ticket-Anmeldung (alle drei) nur gelesen, kein Weg im Modul veraendert je etwas bei Proxmox.

Gemessene Torzahlen

Tor Ausgangswert (23.09., vor Beginn) Endstand (nach Aufgabe 7)
pnpm --filter @tessera/api test 1240 Tests, 77 Dateien 1311 Tests, 82 Dateien
pnpm --filter @tessera/web test 693 Tests, 82 Dateien 708 Tests, 84 Dateien
rls-coverage.spec.ts / rls-access-inventory.spec.ts 5 / 30 5 / 30 (unveraendert gruen)
proxmox-nur-lesen.spec.ts (existierte nicht) 2 Tests, gruen
pnpm type-check 4/4 4/4
pnpm lint 5/5 5/5
Biome-Warnungen in apps/web 53 53 (exakt unveraendert)

Performance

  • Duration: ~5h (inklusive einer Unterbrechung durch Nutzungslimit, an derselben Stelle fortgesetzt)
  • Tasks: 7/7
  • Files modified: 34 (18 neu, 16 geaendert)

Accomplishments

  • ProxmoxServer/ProxmoxServerStatus mit RLS (tenant_isolation_policy auf beiden, system_read_policy zusaetzlich auf ProxmoxServer fuer den Planer-Startpfad)
  • proxmox-auth.ts als einzige Stelle, die Kopfzeilen/Cookies baut: Token-Schema je Produkt (PVE =, PBS :, PMG lehnt ab) und Ticket-Anmeldung (die einzige nicht-lesende Anfrage des Moduls)
  • proxmox-client.service.ts/proxmox-normalize.ts: nachsichtige Fehler-/Feldbehandlung, sieben stabile Fehlerschluessel, nie ein Wurf bei unerwarteter Form
  • proxmox-scheduler.service.ts: ein Cron-Auftrag je Mandant (proxmox-poll:<tenantId>), onApplicationBootstrap, Abfrageintervall = kleinstes pollIntervalMin der aktiven Server
  • Einstellungsseite (anlegen/bearbeiten/loeschen/testen) und Modulseite (Serverliste mit produktabhaengiger Auslastung, null immer als „unbekannt")
  • Anwenderhandbuch- und Entwicklungsanleitung-Abschnitte, Zugriffsklassifikation vollstaendig nachgezogen

Task Commits

Jede Aufgabe wurde einzeln committet:

  1. Aufgabe 1: PVE per Token, Ende-zu-Ende — 3a1bfd9 (feat)
  2. Aufgabe 2: Benutzer/Passwort, Fehlerklassen, Nur-Lesen-Riegel — 4f8a368 (test)
  3. Aufgabe 3: PBS und PMG auswerten — 998aba9 (feat)
  4. Aufgabe 4: Hintergrundabfrage je Mandant, Verbindungstest — fccaf8d (feat)
  5. Aufgabe 5: Einstellungsseite (anlegen, bearbeiten, loeschen, testen) — 723cf68 (feat)
  6. Aufgabe 6: Modulseite mit Auslastung — 06fcdc0 (feat)
  7. Aufgabe 7: Dokumentation und Nachmessung aller Tore — 3091b04 (docs)

Kein separater Metadaten-Commit — STATE.md/SUMMARY.md werden laut Auftrag nicht committet.

Files Created/Modified

Siehe key-files im Frontmatter — vollstaendige Liste, hier die wichtigsten:

  • apps/api/prisma/migrations/20260923140000_proxmox_server/migration.sql — RLS-Migration, von Hand geschrieben (Vorbild 20260923120000_dashboard_tabs)
  • apps/api/src/proxmox/proxmox-client.service.ts — proxmoxGet, classifyFailure, parseJsonLenient
  • apps/api/src/proxmox/proxmox-auth.ts — buildTokenAuthHeader, loginTicket, buildTicketCookieHeader
  • apps/api/src/proxmox/proxmox-normalize.ts — normalizePve/normalizePbs/normalizePmg plus readNumber/readText/readBool/readList
  • apps/api/src/proxmox/proxmox.service.ts — CRUD, Poll-Logik, Zehn-Sekunden-Sperre, loadActiveServersForScheduler (einziger forSystem()-Aufruf)
  • apps/api/src/proxmox/proxmox-scheduler.service.ts — Planer je Mandant
  • apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx — einzige Stelle, die einen Messwert in Text verwandelt

Decisions Made

Siehe decisions im Frontmatter. Zusaetzlich zwei technische Entwurfsentscheidungen, die der Plan nicht bis auf diese Ebene vorschrieb:

  • Signatur proxmoxGet(target, path): target traegt fertige Kopfzeilen ({ baseUrl, tlsRejectUnauthorized, headers }), gebaut ausschliesslich von proxmox-auth.ts — der Klient selbst kennt keine Anmeldeform, nur HTTP-Transport und Fehlerklassifikation.
  • proxmox-nur-lesen.spec.ts erkennt Aufrufformen ueber Klammertiefen-Bilanzierung (nicht per einfachem Zeilen-Regex), weil Proxmox-Pfade und proxmoxGet(/getWithRetry(- Aufrufe im Quelltext ueber mehrere Zeilen verteilt sind.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking] docs/anwenderhandbuch.md existiert nicht im Repo

  • Found during: Aufgabe 7
  • Issue: Das Plan-Frontmatter nennt docs/anwenderhandbuch.md als zu aendernde Datei; diese Datei gibt es im Repository nicht. Der tatsaechliche Anwenderhandbuch-Dateiname ist docs/anleitung-anwender.md (bestaetigt per git log --diff-filter=A).
  • Fix: Den Proxmox-Abschnitt in docs/anleitung-anwender.md eingefuegt statt eine neue, falsch benannte Datei anzulegen.
  • Files modified: docs/anleitung-anwender.md
  • Verification: Datei existiert, Abschnitt „Proxmox" lesbar, Modulzahl „vier" auf „fuenf" korrigiert.
  • Committed in: 3091b04 (Aufgabe-7-Commit)

2. [Rule 3 - Blocking] Umlaut-Regressionswaechter (umlaut-guard.spec.ts) schlug fehl

  • Found during: Aufgabe 5 und erneut Aufgabe 6
  • Issue: Neue, bereits korrekte deutsche Woerter mit „ss" (bewusst, gemessene, Messung, Prozessorlast) in den neuen de.json-Texten wurden vom Waechter als moegliche ae/oe/ue/ss-Ersatzschreibung markiert, weil sie noch nicht auf der Positivliste standen.
  • Fix: Alle vier Woerter zu UMLAUT_ALLOWLIST in apps/web/src/messages/umlaut-dictionary.ts hinzugefuegt (kein Ersatzschreibung — bereits korrektes Deutsch).
  • Files modified: apps/web/src/messages/umlaut-dictionary.ts
  • Verification: umlaut-guard.spec.ts gruen, pnpm --filter @tessera/web test vollstaendig gruen.
  • Committed in: 723cf68 (Aufgabe 5), 06fcdc0 (Aufgabe 6)

3. [Rule 3 - Blocking] proxmox-nur-lesen.spec.ts erkannte den getWithRetry-Umschlag nicht

  • Found during: Aufgabe 3 (beim Einbau der PBS-Mehrfachabfrage)
  • Issue: Der urspruengliche Riegel erkannte Proxmox-Pfade nur innerhalb direkter proxmoxGet(...)-Aufrufe; nach der Extraktion der Ticket-Erneuerung in einen privaten Umschlag getWithRetry() (Aufgabe 2/3) lagen alle Pfade jetzt in dessen Argumenten, nicht mehr direkt in proxmoxGet(...).
  • Fix: Die erlaubte Aufrufform-Liste um getWithRetry erweitert (dokumentierte Ausnahme, selbst durch dieselbe erste Aussage des Riegels abgesichert: getWithRetry ruft ausschliesslich proxmoxGet).
  • Files modified: apps/api/src/proxmox/proxmox-nur-lesen.spec.ts
  • Verification: Beide Aussagen des Riegels gruen, bewusster Test bestaetigt weiterhin genau eine undiciFetch-Methodenstelle.
  • Committed in: 998aba9 (Aufgabe 3)

Total deviations: 3 auto-fixed (alle Rule 3 — blockierende Fehler beim Ausfuehren, keine davon eine architektonische Entscheidung) Impact on plan: Keine Abweichung vom fachlichen Umfang des Plans; alle drei Korrekturen waren notwendig, damit die vom Plan selbst verlangten Tore (Aufgabe 7: alle Testsuiten gruen) ueberhaupt erreichbar waren.

Issues Encountered

Die Ausfuehrung wurde durch ein Nutzungslimit mitten in Aufgabe 4 unterbrochen (nach dem Schreiben von proxmox-scheduler.service.ts und dem Wiring in proxmox.controller.ts/ proxmox.module.ts, vor dem Schreiben der zugehoerigen Testdatei). Nach Fortsetzung wurde der Stand anhand von git status/git log verifiziert und exakt an der protokollierten Stelle weitergearbeitet — keine Wiederholung bereits committeter Aufgaben.

User Setup Required

Es gibt in dieser Umgebung keinen echten PVE-/PBS-/PMG-Server. Alle Tests laufen gegen erfundene Antworten in der von der Recherche dokumentierten Form (vi.mock('undici', …)). Folgende Annahmen der Recherche sind vor dem ersten echten Test explizit zu bestaetigen bzw. bei Abweichung an genau einer Stelle nachzuziehen:

  • Annahme A2 — Ticket-Cookie-Namen fuer PBS/PMG: PBSAuthCookie/PMGAuthCookie sind aus dem PVE-Muster ABGELEITET, nicht aus Primaerdoku bestaetigt. Nachzuziehende Stelle: TICKET_COOKIE_NAME in apps/api/src/proxmox/proxmox-auth.ts.
  • Annahme A3 — PBS-Belegungs-/Snapshot-Feldnamen: store/total/used/avail und backup-time/verification sind aus Forenbelegen abgeleitet. Nachzuziehende Stelle: PBS_USAGE_FIELDS/PBS_SNAPSHOT_FIELDS in apps/api/src/proxmox/proxmox-normalize.ts (mehrere plausible Namen je Feld moeglich, der Leser nimmt den ersten vorhandenen).
  • Annahme A5 — PMG-Statistikfelder: count_in/count_out/spamcount_in/spamcount_out/ viruscount_in/viruscount_out sind aus pmgsh-Community-Belegen abgeleitet. Nachzuziehende Stelle: PMG_STATS_FIELDS in apps/api/src/proxmox/proxmox-normalize.ts.
  • NUR-LESE-Rollen am Proxmox-Server selbst anlegen (aus dem Plan-Frontmatter user_setup, unveraendert offen): PVE PVEAuditor, PBS Audit/DatastoreAudit, PMG Auditor — je Produkt fuer den Zugang, den Tessera nutzt.

Weicht die Wirklichkeit an einer dieser Stellen ab, zeigt die Modulseite dank der nachsichtigen Leser „unbekannt" statt eines Absturzes, und die gekuerzte Rohantwort bleibt im Zwischenlager erhalten (rawSample, bis 20 000 Zeichen) — der Nutzer sieht darin, wie das Feld tatsaechlich heisst.

Known Stubs

Keine — jede in <must_haves> genannte Wahrheit ist durch mindestens einen automatisierten Test belegt (siehe Aufgaben 1–6). Die drei oben genannten Annahmen sind keine Stubs, sondern dokumentierte, noch nicht am echten Server bestaetigte Feldnamen — die Auswertung fuer sie ist vollstaendig gebaut, nur ihre exakten externen Namen sind ungeprueft.

Next Phase Readiness

  • Das Modul ist vollstaendig gebaut und alle automatisierten Tore sind gruen; die Dashboard-Kachel (D-11) ist bewusst nicht Teil dieses Auftrags und folgt separat (WIDGET_TYPES/WIDGET_MODULE_SLUGS/registerWidget, siehe docs/anleitung-entwicklung.md, Abschnitt „Eine Kachel zum Modul").
  • Blocker fuer den naechsten Schritt: keiner auf Code-Ebene. Der Nutzer muss das Modul gegen mindestens einen echten PVE-/PBS-/PMG-Server pruefen (siehe „User Setup Required"), bevor die drei Annahmen als bestaetigt gelten koennen.
  • Container wurden in dieser Ausfuehrung bewusst NICHT neu gebaut/neu gestartet und es wurde keine Browser-Pruefung durchgefuehrt (Auftragsvorgabe) — das uebernimmt der Nutzer bzw. eine spaetere Sitzung.

Phase: quick-260923-dhh Completed: 2026-09-23

Self-Check: PASSED

All 24 files listed under key-files (created + modified) verified present on disk. All 7 task commits (3a1bfd9, 4f8a368, 998aba9, fccaf8d, 723cf68, 06fcdc0, 3091b04) verified present in git log.

Nachbesserungen aus dem Rundgang

Drei Befunde aus dem menschlichen Browser-Rundgang zu diesem Modul wurden behoben — Details, Tasks und Tests in einem eigenen Quick-Task: 260923-ku6-drei-nachbesserungen-aus-dem-browser-run (Commits 710034c, f1bb7f7).

Befund 1 (wichtig): „Verbindung testen" pruefte den gespeicherten Stand, nicht das Formular. Eine im Formular abgeschaltete Zertifikatspruefung oder ein neu eingetipptes Token-/Passwort-Geheimnis wurden vom Test ignoriert und griffen erst nach „Speichern" — eine Falle fuer den naheliegenden Ablauf (eintippen, testen, dann erst speichern). Behoben durch ein neues TestProxmoxServerDto samt Merge-Baustein resolveEffectiveTestServer in ProxmoxService: normale Formularfelder gewinnen immer (auch wenn absichtlich geleert), Geheimnisfelder behalten die bestehende „leer gelassen -> gespeicherten Wert weiterverwenden"- Regel aus updateServer, weil ServerForm sie beim Laden nie aus der Datenbank vorbefuellt. Neue Route POST servers/test (ohne :id) deckt denselben Test waehrend der Neuanlage ab, wo es noch keinen gespeicherten Server gibt; der Testen-Knopf steht jetzt immer zur Verfuegung, nicht mehr erst nach dem ersten Speichern.

Befund 2 (wichtig): falsche Meldung fuer „noch nie abgefragt". Ein frisch angelegter Server zeigte „Letzte Abfrage: unbekannt" UND faelschlich „Ein unerwarteter Fehler ist aufgetreten" — die leere Zwischenlagerzeile aus createServer hat reachable: false und errorKind: null, was bisher blind in die Fehleruebersetzung unbekannt lief. Behoben durch einen eigenen, ruhigen Zustand fuer status.lastPolledAt === null, der auf „Jetzt aktualisieren" verweist; die bestehenden Fehlermeldungen (inkl. unbekannt fuer echte unbekannte Fehler) bleiben fuer bereits abgefragte, aber nicht erreichbare Server unveraendert.

Befund 3 (kosmetisch): die Adresse wurde in Grossbuchstaben angezeigt. Die Klasse uppercase sass auf der ganzen Statuszeile statt nur auf dem Produktkuerzel und faerbte dadurch auch die Adresse gross. Jetzt nur noch auf dem Produktkuerzel (<span>).

Zahlen nach der Nachbesserung: api 1311 → 1316 Tests, web 708 → 712 Tests, type-check 4/4, lint 5/5, Biome apps/web weiterhin exakt 53 Warnungen. Container wurden nicht neu gebaut, keine Browser-Pruefung in diesem Lauf (macht der Orchestrator danach).