docs: Architekturplan, Issues und Projektorganisation anlegen
Plan für ProxDeploy zur Freigabe: Architektur (app, worker, Postgres), Prisma-Entwurf, REST-API, Dateistruktur und sechs Etappen. Die Proxmox-API wurde gegen das Schema von PVE 9.2 und die Quellen der 8er-Zweige geprüft. Daraus folgt die Fähigkeitserkennung pro Server: Template-Bau per API erst ab 8.4, Snippets und LXC-Exec nur per SSH. Refs #001 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
|||||||
|
node_modules/
|
||||||
|
.next/
|
||||||
|
out/
|
||||||
|
dist/
|
||||||
|
coverage/
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
src/generated/
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
cli/bin/
|
||||||
|
playwright-report/
|
||||||
|
test-results/
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
Alle nennenswerten Änderungen an ProxDeploy werden in dieser Datei dokumentiert.
|
||||||
|
|
||||||
|
Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
||||||
|
und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
||||||
|
|
||||||
|
## [Unveröffentlicht]
|
||||||
|
|
||||||
|
### Hinzugefügt
|
||||||
|
- Architektur- und Umsetzungsplan (`docs/architektur.md`) mit Prüfung der Proxmox-API 8.x/9.x und der Image-Quellen (#001)
|
||||||
|
- Issues #001–#020 für die sechs Etappen und den Feldtest (#001)
|
||||||
|
|
||||||
|
### Geändert
|
||||||
|
|
||||||
|
### Behoben
|
||||||
|
|
||||||
|
### Entfernt
|
||||||
|
|
||||||
|
### Sicherheit
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# DEVLOG – ProxDeploy
|
||||||
|
|
||||||
|
## Zeitübersicht
|
||||||
|
|
||||||
|
**Gesamt:** 0 h 25 min (laufende Sitzung)
|
||||||
|
|
||||||
|
Zeiten stammen aus den Git-Commit-Zeitstempeln je Issue; Wartezeit auf Rückmeldungen ist enthalten.
|
||||||
|
|
||||||
|
| Issue | Zeit |
|
||||||
|
|---|---|
|
||||||
|
| #001 Projekt-Setup | 0 h 25 min (laufend) |
|
||||||
|
|
||||||
|
| Meilenstein | Zeit |
|
||||||
|
|---|---|
|
||||||
|
| v0.1.0 | – |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2026-10-12 · Sitzung 1 · 08:45–laufend
|
||||||
|
**Issue:** #001
|
||||||
|
**Version:** 0.1.0-dev
|
||||||
|
|
||||||
|
### Erledigt
|
||||||
|
- Auftrag gelesen, Rückfragen gestellt: Reverse-Proxy (ja), OIDC (implementieren, vorerst nur lokal testen), Testumgebung (folgt), CLI (Go)
|
||||||
|
- Umgebung geprüft: Docker 29 vorhanden, Node und Go fehlen → Builds und Tests laufen im Container
|
||||||
|
- Proxmox-API 8.x/9.x gegen API-Schema 9.2, Quellen der stable-8-Zweige und Release Notes geprüft (Ergebnis: `docs/architektur.md` Abschnitt 3)
|
||||||
|
- Image-URLs, Prüfsummen-Dateien, LXC-Template-Namen, Docker- und Zabbix-Repos per Abruf geprüft
|
||||||
|
- Git-Repository (`main`), CHANGELOG, DEVLOG, Architekturplan und 20 Issues angelegt
|
||||||
|
|
||||||
|
### Entscheidungen
|
||||||
|
- **VM-Provisionierung immer über den Guest-Agent:** funktioniert ohne SSH und liefert Live-Fortschritt. Snippets braucht es nur beim Template-Bau.
|
||||||
|
- **Guest-Agent wird ins Template gebaut:** keines der vier Cloud-Images bringt ihn mit, und ohne Agent gibt es bei DHCP keine IP und keine Provisionierung.
|
||||||
|
- **LXC braucht für Profile immer SSH** (zum Node oder in den Container): Proxmox hat keine Exec-API für Container.
|
||||||
|
- **Template-Bau per API erst ab PVE 8.4** (`download-url` mit `content=import`); davor über SSH.
|
||||||
|
- **Planer und Ausführung getrennt:** der Dry-Run zeigt exakt den Plan, den der worker danach abarbeitet.
|
||||||
|
- **CLI in Go** mit aus OpenAPI generiertem Client.
|
||||||
|
- **Deutsche Bezeichner** wie in ProxLedger und Laufzettel; YAML-Schlüssel im Katalog bleiben englisch (Vorgabe).
|
||||||
@@ -0,0 +1,602 @@
|
|||||||
|
# ProxDeploy – Architektur- und Umsetzungsplan
|
||||||
|
|
||||||
|
Stand: 2026-10-12 · Version 0.1.0-dev · **Entwurf zur Freigabe**
|
||||||
|
|
||||||
|
## 1. Überblick
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser (Web-GUI) Terminal (proxdeploy, Go)
|
||||||
|
│ Cookie │ Bearer-Token
|
||||||
|
└──────────┬──────────────┘
|
||||||
|
▼ REST /api/v1 + SSE
|
||||||
|
┌────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ProxDeploy (Docker Compose oder Debian-LXC), hinter Reverse-Proxy │
|
||||||
|
│ ┌──────────────────────┐ pg-boss ┌────────────────────────────┐ │
|
||||||
|
│ │ app (Next.js) │──Auftrag────▶│ worker (Node) │ │
|
||||||
|
│ │ UI · REST-API · SSE │◀─LISTEN/─────│ Engine: Planer, Phasen, │ │
|
||||||
|
│ │ Dry-Run (Planer) │ NOTIFY │ Proxmox-Client, Adapter │ │
|
||||||
|
│ └──────────┬───────────┘ └──────┬───────────┬─────────┘ │
|
||||||
|
│ └────────── PostgreSQL ───────────┘ │ │
|
||||||
|
└───────────────────────────────────────────────────────────┼─────────────┘
|
||||||
|
HTTPS :8006 (Token, Fingerprint-Pin) │ optional SSH
|
||||||
|
▼
|
||||||
|
Proxmox VE 8.x / 9.x (Einzelhost oder Cluster)
|
||||||
|
│ Guest-Agent / SSH in den Gast
|
||||||
|
▼
|
||||||
|
VM oder LXC (Debian, Ubuntu, …)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Ein Backend, zwei Oberflächen.** Die Engine (`src/engine/`) ist frameworkfrei und enthält die
|
||||||
|
gesamte Deploy-Logik. Die Web-GUI und die CLI sprechen ausschließlich die REST-API; die GUI hat
|
||||||
|
keinen Sonderweg an der API vorbei (Server Actions rufen dieselben Services wie die Route Handler).
|
||||||
|
- **app** liefert UI, REST-API, OpenAPI-Spezifikation und SSE-Ströme. Sie führt nie ein Deployment
|
||||||
|
aus, nur den **Planer** für den Dry-Run (reine Funktion, keine schreibenden Proxmox-Aufrufe).
|
||||||
|
- **worker** ist derselbe Codestand als eigener Prozess und arbeitet Aufträge aus der pg-boss-Queue ab.
|
||||||
|
Jede Phasenänderung wird in die DB geschrieben und per `NOTIFY auftrag_<id>` gemeldet; die app hängt
|
||||||
|
sich mit `LISTEN` daran und streamt an alle offenen SSE-Verbindungen. Ein Neuladen der Seite oder ein
|
||||||
|
Wiederverbinden der CLI liest zuerst den Stand aus der DB und setzt dann ab `Last-Event-ID` fort.
|
||||||
|
- **PostgreSQL** ist die einzige Datenhaltung (inkl. Queue). Keine Dateien außer dem Katalog im Image.
|
||||||
|
|
||||||
|
## 2. Tech-Stack
|
||||||
|
|
||||||
|
| Bereich | Wahl | Begründung |
|
||||||
|
|---|---|---|
|
||||||
|
| Web/API | Next.js 16 (App Router), React 19, TypeScript strict | Vorgabe; wie Laufzettel/ProxLedger |
|
||||||
|
| Styling | Tailwind CSS 4, Tokens als CSS-Variablen unter `@theme`, eigene Komponenten | Vorgabe, kein Admin-Template |
|
||||||
|
| Schriften | Space Grotesk, JetBrains Mono über `@fontsource-variable`, selbst gehostet | keine Google-Anfragen aus dem Intranet |
|
||||||
|
| Icons | Lucide (Stroke) + die Statussymbole ✓ ◐ ✗ ○ als Text | Status nie nur Farbe |
|
||||||
|
| DB | PostgreSQL 17, Prisma 7 mit `@prisma/adapter-pg` | Vorgabe |
|
||||||
|
| Jobs | pg-boss auf derselben Datenbank | Vorgabe; kein Redis nötig |
|
||||||
|
| Validierung | zod (Request, Katalog-YAML, Profil-Editor) | eine Schemaquelle für API, OpenAPI und Katalog |
|
||||||
|
| OpenAPI | aus den zod-Schemas erzeugt (`/api/v1/openapi.json`) | Go-Client wird daraus generiert |
|
||||||
|
| Auth | `jose` (Sitzungs-Cookie), `openid-client` (OIDC, PKCE), argon2id | wie ProxLedger; kein Auth.js-Beta |
|
||||||
|
| SSH | `ssh2` (Node) | Snippets schreiben, `pct exec`, SSH in den Gast |
|
||||||
|
| YAML | `yaml` (eemeli) | erhält Kommentare im Profil-Editor |
|
||||||
|
| Logs | `pino` (JSON auf stdout), zusätzlich pro Auftrag in der DB | Betrieb + GUI |
|
||||||
|
| Tests | Vitest (Engine, API mit echter Test-DB), Playwright (Assistent, Live-Ansicht, 390 px) | |
|
||||||
|
| CLI | **Go**, statisches Binary | siehe Abschnitt 9 |
|
||||||
|
|
||||||
|
Exakte Versionen werden in #001 gegen npm/Go-Proxy geprüft und **gepinnt** (abgelagerte Fassungen,
|
||||||
|
keine RCs) und in `CLAUDE.md` festgehalten.
|
||||||
|
|
||||||
|
## 3. Was geht per Proxmox-API, was braucht SSH
|
||||||
|
|
||||||
|
Geprüft am 2026-10-12 gegen das API-Schema von PVE 9.2 (`apidoc.js`), die Quellen der Zweige
|
||||||
|
`stable-8`/`stable-bookworm` (pve-storage, qemu-server, pve-container) und die Release Notes
|
||||||
|
8.0–9.2. Belege stehen in den Issues #005 und #007.
|
||||||
|
|
||||||
|
| Fähigkeit | PVE 8.0–8.3 | PVE 8.4+ / 9.x | Weg |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Cloud-Image herunterladen + Checksumme prüfen (`download-url`, `content=import`, qcow2/raw/vmdk) | **nein** (nur iso/vztmpl, OVA ab 8.2) | ja | API |
|
||||||
|
| Disk aus heruntergeladenem Image anlegen (`scsi0: <stor>:0,import-from=<stor>:import/<datei>`) | nur per absolutem Pfad → nur `root@pam` | ja, per Volume-ID | API |
|
||||||
|
| Klonen, Konfiguration, cloud-init (`ciuser`, `sshkeys`, `ipconfigN`, `nameserver`, `searchdomain`, `ciupgrade`), Start/Stopp, Template | ja | ja | API |
|
||||||
|
| Guest-Agent `exec`, `exec-status`, `file-write` (max. 60 KiB je Aufruf), `network-get-interfaces` | ja (`VM.Monitor`) | ja (`VM.GuestAgent.*` ab 9.0) | API |
|
||||||
|
| LXC anlegen (`ssh-public-keys`, `net0` mit `tag`, `unprivileged`, `features: nesting`) | ja | ja | API |
|
||||||
|
| LXC-Template-Liste und -Download (`aplinfo`) | ja | ja | API |
|
||||||
|
| LXC-IP auslesen (`lxc/{id}/interfaces`) | ja | ja | API |
|
||||||
|
| LXC-Features außer `nesting` (`keyctl`, `fuse`, …) | nur `root@pam` per Ticket, **kein Token** | dito | SSH (`pct set`) |
|
||||||
|
| **Befehle im LXC ausführen** | **keine API** | **keine API** | SSH (`pct exec` auf dem Node **oder** SSH in den Container) |
|
||||||
|
| **cloud-init-Snippets schreiben** (`cicustom`) | **keine API** (Upload nur iso/vztmpl/import) | dito | SSH |
|
||||||
|
| Zertifikats-Fingerprint | `nodes/{n}/certificates/info` | dito | API (nach erstem Pin) |
|
||||||
|
|
||||||
|
**Folgerungen für die Engine:**
|
||||||
|
|
||||||
|
1. **Fähigkeitserkennung pro Server** (`src/engine/proxmox/faehigkeiten.ts`), beim Verbindungstest und
|
||||||
|
vor jedem Auftrag aufgefrischt: PVE-Version je Node, Storages mit Inhaltstyp `import`, `snippets`,
|
||||||
|
`vztmpl`, `images`/`rootdir`, Rechte des Tokens (`GET /access/permissions`), SSH konfiguriert und
|
||||||
|
erreichbar. Daraus ergibt sich pro Server und Vorgang die **Strategie**, die in der GUI sichtbar ist
|
||||||
|
(„Template-Bau: per API“ / „braucht SSH, weil PVE 8.3“).
|
||||||
|
2. **VM-Provisionierung läuft immer über den Guest-Agent** (Skript per `file-write` in 60-KiB-Stücken,
|
||||||
|
dann `exec` + `exec-status`-Polling). Damit funktioniert sie **ohne SSH** und liefert Live-Fortschritt.
|
||||||
|
Standard-cloud-init von Proxmox liefert nur Benutzer, Keys und Netz; `ciupgrade=0`, Updates macht
|
||||||
|
das Profil `base` (sichtbar als eigene Phase statt stummem Boot-Upgrade).
|
||||||
|
3. **Der Guest-Agent ist in keinem der vier Cloud-Images vorinstalliert** (geprüft in den Paketlisten).
|
||||||
|
Deshalb wird er **beim Template-Bau** eingebaut, damit jeder Klon sofort einen Agent hat:
|
||||||
|
- mit SSH zum Node: einmaliger Vorbereitungsstart mit `cicustom: vendor=<snippet>` (installiert
|
||||||
|
`qemu-guest-agent`, `cloud-init clean`, `poweroff`) – funktioniert auch mit DHCP;
|
||||||
|
- ohne SSH: Vorbereitungsstart mit einer **Bau-Adresse** (statische IP aus den Server-Einstellungen)
|
||||||
|
und dem ProxDeploy-Bereitstellungsschlüssel per `sshkeys`, dann SSH **in die VM**, dieselben Schritte.
|
||||||
|
- Danach `cloud-init clean`, Maschinen-ID leeren, als Template markieren.
|
||||||
|
4. **LXC-Provisionierung** braucht immer SSH – bevorzugt `pct exec` über SSH zum Node (kein Netzweg
|
||||||
|
zum Container nötig), sonst SSH direkt in den Container (Bereitstellungsschlüssel per
|
||||||
|
`ssh-public-keys`, IP aus Konfiguration bzw. `lxc/{id}/interfaces`). Das `debian`-Standard-Template
|
||||||
|
bringt `openssh-server` mit; der Bereitstellungsschlüssel wird am Ende wieder entfernt.
|
||||||
|
5. **Ohne jedes SSH** sind möglich: VM aus vorhandenem oder per API gebautem Template (PVE ≥ 8.4) mit
|
||||||
|
allen Profilen; LXC ohne Profile (nur Anlegen + Start). Die GUI graut nicht Mögliches mit Begründung aus.
|
||||||
|
|
||||||
|
**SSH-Zugang** pro Server: ProxDeploy erzeugt ein ed25519-Schlüsselpaar, zeigt den öffentlichen
|
||||||
|
Schlüssel samt Einzeiler zum Hinterlegen, pinnt den Host-Key beim ersten Test (Bestätigung durch den
|
||||||
|
Admin). Benutzer `root` auf dem Node (für `pct` und `/var/lib/vz/snippets` nötig).
|
||||||
|
|
||||||
|
## 4. Proxmox-Rechte (Rolle `ProxDeploy`)
|
||||||
|
|
||||||
|
Wird im README ausführlich dokumentiert, inkl. `pveum`-Befehlen.
|
||||||
|
|
||||||
|
- **Gemeinsam:** `VM.Allocate VM.Clone VM.Audit VM.Config.Disk VM.Config.CDROM VM.Config.CPU
|
||||||
|
VM.Config.Memory VM.Config.Network VM.Config.HWType VM.Config.Options VM.Config.Cloudinit
|
||||||
|
VM.PowerMgmt VM.Console Datastore.AllocateSpace Datastore.AllocateTemplate Datastore.Audit SDN.Use
|
||||||
|
SDN.Audit Sys.Audit Pool.Audit`
|
||||||
|
- **nur 8.x:** `VM.Monitor` (Guest-Agent); vor 8.2 statt `Sys.AccessNetwork` → `Sys.Modify`
|
||||||
|
- **8.2+ und 9.x:** `Sys.AccessNetwork` auf `/nodes/<node>` (für `download-url`)
|
||||||
|
- **nur 9.x:** `VM.GuestAgent.Audit VM.GuestAgent.Unrestricted` (ersetzt `VM.Monitor`)
|
||||||
|
- **optional:** `Datastore.Allocate` (heruntergeladene Images/Templates wieder löschen),
|
||||||
|
`Sys.Modify` (privilegierte Container ab 9.0)
|
||||||
|
- ACL: `/vms` oder ein Pool, `/storage/<id>`, `/sdn/zones/localnetwork` (bzw. konkrete Zonen), `/`
|
||||||
|
nur für `Sys.Audit`. Der Verbindungstest gleicht die effektiven Rechte gegen diese Liste ab und
|
||||||
|
nennt fehlende Rechte einzeln.
|
||||||
|
|
||||||
|
## 5. Distributionen, Adapter, Profile
|
||||||
|
|
||||||
|
### Katalog als Daten
|
||||||
|
|
||||||
|
`catalog/distros/*.yaml` und `catalog/profiles/*.yaml` liegen im Repo und im Image. Der worker
|
||||||
|
synchronisiert sie beim Start in die DB (Upsert über `id`, Hash der Datei; Aktiv-Schalter und eigene
|
||||||
|
Profile bleiben unangetastet). Die **YAML-Schlüssel bleiben englisch** wie in der Vorgabe – sie sind
|
||||||
|
ein Austauschformat, kein Code-Bezeichner. Validiert mit zod; ein fehlerhafter Eintrag wird mit
|
||||||
|
Dateiname und Pfad gemeldet und übersprungen, nicht der Start abgebrochen.
|
||||||
|
|
||||||
|
Mitgeliefert (URLs am 2026-10-12 per Abruf geprüft): Debian 12, Debian 13, Ubuntu 22.04, Ubuntu 24.04.
|
||||||
|
Ubuntu 26.04 LTS ist ebenfalls verfügbar (Cloud-Image und LXC-Template) – **Vorschlag: mitliefern**.
|
||||||
|
|
||||||
|
- Debian: `cloud.debian.org/images/cloud/<codename>/latest/debian-<n>-genericcloud-amd64.qcow2`,
|
||||||
|
`SHA512SUMS` (Zeilenformat `<hash>␣␣<datei>`), Benutzer `debian`
|
||||||
|
- Ubuntu: `cloud-images.ubuntu.com/<codename>/current/<codename>-server-cloudimg-amd64.img` (qcow2),
|
||||||
|
`SHA256SUMS` (Zeilenformat `<hash>␣*<datei>`), Benutzer `ubuntu`
|
||||||
|
- LXC: alle `*-standard_*_amd64.tar.zst`; bei mehreren Treffern (Debian 13: `13.1-2` und `13.6-1`)
|
||||||
|
gewinnt die höchste Version (Versionssortierung).
|
||||||
|
|
||||||
|
Ergänzende Felder gegenüber der Vorgabe: `codename`, `arch` (vorerst `amd64`), `vm.bios_default`
|
||||||
|
(`ovmf`/`seabios`), `vm.template_vmid_offset` (z. B. Debian 13 → 9013), `vm.min_disk_gb`.
|
||||||
|
|
||||||
|
### Provisionierungs-Adapter
|
||||||
|
|
||||||
|
`src/engine/adapter/schnittstelle.ts` definiert `FamilienAdapter` – jede Methode liefert ein
|
||||||
|
**idempotentes Shell-Fragment** (kein Ausführen im Adapter, damit testbar und im Dry-Run anzeigbar):
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface FamilienAdapter {
|
||||||
|
familie: string; // "debian"
|
||||||
|
aktualisieren(): Skript;
|
||||||
|
paketeInstallieren(pakete: string[]): Skript;
|
||||||
|
dienstAktivieren(name: string, starten?: boolean): Skript;
|
||||||
|
repoHinzufuegen(repo: PaketQuelle): Skript; // Schlüssel-URL, URIs, Suites, Komponenten
|
||||||
|
zeitzoneSetzen(tz: string): Skript;
|
||||||
|
localeSetzen(locale: string): Skript;
|
||||||
|
tastaturSetzen(layout: string): Skript;
|
||||||
|
benutzerAnlegen(b: Benutzerangaben): Skript; // inkl. sudo, authorized_keys
|
||||||
|
sshHaerten(o: SshHaertung): Skript; // PasswordAuthentication no, PermitRootLogin no
|
||||||
|
gastAgentInstallieren(): Skript;
|
||||||
|
automatischeUpdates(an: boolean): Skript;
|
||||||
|
fakten(): Skript; // gibt OS-Fakten (codename, ID) als JSON aus
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Registriert in `src/engine/adapter/index.ts`. Ein neuer Adapter (`rhel`, `alpine`, `suse`) ist eine
|
||||||
|
neue Datei + ein Eintrag in der Registry + Tests; Katalog und Profile verweisen per `family` darauf.
|
||||||
|
|
||||||
|
### Profile
|
||||||
|
|
||||||
|
Ein Profil ist eine Liste deklarativer **Schritte** je Familie, die der Adapter in Shell übersetzt.
|
||||||
|
Für Sonderfälle gibt es `run` (rohes Shell, ausdrücklich nicht portabel). Variablen werden als
|
||||||
|
Formularfelder angezeigt und mit `{{ var.name }}` eingesetzt (eigene kleine Template-Funktion,
|
||||||
|
nur Ersetzung, keine Logik; Werte werden für Shell gequotet).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
id: zabbix-agent
|
||||||
|
name: Zabbix Agent 2
|
||||||
|
description: Zabbix Agent 2 (7.0 LTS) aus dem offiziellen Repo
|
||||||
|
requires: [base]
|
||||||
|
variables:
|
||||||
|
- { name: server, label: Zabbix-Server, type: string, required: true }
|
||||||
|
- { name: server_active, label: ServerActive, type: string, default: "{{ var.server }}" }
|
||||||
|
lxc: {} # z. B. docker: { features: { nesting: true } }
|
||||||
|
families:
|
||||||
|
debian:
|
||||||
|
- repo_deb: "https://repo.zabbix.com/zabbix/7.0/{{ os.id }}/pool/main/z/zabbix-release/zabbix-release_latest_7.0+{{ os.id }}{{ os.version_id }}_all.deb"
|
||||||
|
- packages: [zabbix-agent2]
|
||||||
|
- file: { path: /etc/zabbix/zabbix_agent2.d/proxdeploy.conf, content: "Server={{ var.server }}\nServerActive={{ var.server_active }}\nHostname={{ guest.name }}\n" }
|
||||||
|
- service: { name: zabbix-agent2, enable: true, restart: true }
|
||||||
|
```
|
||||||
|
|
||||||
|
Fehlt `families.<familie>` für die gewählte Distribution, ist das Profil im Assistenten ausgegraut
|
||||||
|
(„keine Umsetzung für Familie rhel“). Eigene Profile werden im YAML-Editor angelegt, gegen dasselbe
|
||||||
|
zod-Schema geprüft und mit `origin: custom` gespeichert; Katalog-Profile sind schreibgeschützt,
|
||||||
|
lassen sich aber als Kopie bearbeiten.
|
||||||
|
|
||||||
|
Mitgeliefert: `base`, `docker` (Docker CE, deb822 `docker.sources`, Key `/etc/apt/keyrings/docker.asc`,
|
||||||
|
Pakete `docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin`; LXC:
|
||||||
|
`nesting=1`), `zabbix-agent` (7.0 LTS; 8.0 hat noch keine Agent-Pakete).
|
||||||
|
|
||||||
|
## 6. Engine: Aufträge und Phasen
|
||||||
|
|
||||||
|
```
|
||||||
|
src/engine/
|
||||||
|
proxmox/ client.ts (fetch + undici, Fingerprint-Pinning), endpunkte/*.ts, faehigkeiten.ts, aufgaben.ts (UPID warten)
|
||||||
|
ssh/ verbindung.ts, node.ts (pct exec, Snippet schreiben), gast.ts
|
||||||
|
katalog/ schema.ts (zod), laden.ts, pruefsumme.ts (beide Zeilenformate)
|
||||||
|
adapter/ schnittstelle.ts, debian.ts, index.ts
|
||||||
|
profile/ aufloesen.ts (Reihenfolge, requires, Variablen), rendern.ts (→ Skript)
|
||||||
|
planer/ vm.ts, lxc.ts, template.ts → Plan { phasen[], aufrufe[] } (rein, keine I/O außer Lesen)
|
||||||
|
ablauf/ ausfuehren.ts (Phasen-Runner), ereignisse.ts (Senke-Interface), fehler.ts (Ursache + Hinweis)
|
||||||
|
transport/ gastagent.ts, ssh-node.ts, ssh-gast.ts → gemeinsames Interface `Ausfuehrer`
|
||||||
|
sperren.ts VMID-Reservierung
|
||||||
|
```
|
||||||
|
|
||||||
|
**Planer und Ausführung trennen.** Der Planer bekommt eine validierte Anfrage + einen *lesenden*
|
||||||
|
Proxmox-Zugriff + Fähigkeiten und liefert den Plan: die Phasen und je Phase die geplanten
|
||||||
|
API-Aufrufe (`POST /nodes/pve01/qemu/9013/clone newid=120 full=1 …`). Der Dry-Run zeigt genau diesen
|
||||||
|
Plan; die Ausführung arbeitet ihn ab. So können Dry-Run und Wirklichkeit nicht auseinanderlaufen.
|
||||||
|
|
||||||
|
**Phasen** (VM): Prüfungen → Template (übersprungen, wenn vorhanden) → Klonen → Hardware & Disk →
|
||||||
|
cloud-init → Start → Guest-Agent → Provisionierung (je Profil eine Unterzeile im Log) → Abschluss.
|
||||||
|
LXC: Prüfungen → LXC-Template → Anlegen → Start → Netzwerk → Provisionierung → Abschluss.
|
||||||
|
Jede Phase schreibt `status`, `detail` (der Muted-Text der CLI), `dauer`, bei Fehler `ursache` und
|
||||||
|
`hinweis`. **Web und CLI rendern nur diese Felder** – kein Text wird in einem Client erfunden.
|
||||||
|
|
||||||
|
**VMID-Vergabe ohne Doppelungen:** `pg_advisory_xact_lock(hash(serverId))`, dann nächste freie ID
|
||||||
|
aus `/cluster/resources` ∪ Tabelle `VmidReservierung`, Reservierung schreiben, Sperre fällt mit der
|
||||||
|
Transaktion. Die Reservierung gilt bis Auftragsende (bzw. Ablauf nach 2 h als Sicherung). Beim
|
||||||
|
`create`/`clone` wird ein Konflikt (`already exists`) einmal mit neuer ID wiederholt.
|
||||||
|
|
||||||
|
**Fehler und Aufräumen:** Ein Fehler beendet den Auftrag mit Status `FEHLGESCHLAGEN`, die Phase trägt
|
||||||
|
Ursache und Lösungshinweis (z. B. „Token fehlt VM.GuestAgent.Unrestricted auf /vms/120 → Rolle
|
||||||
|
ergänzen“). Was angelegt wurde, steht in `Auftrag.angelegt` (VMID, heruntergeladene Volumes).
|
||||||
|
„Aufräumen“ ist ein eigener Auftrag (`AUFRAEUMEN`), nur nach Bestätigung, und löscht nur, was
|
||||||
|
ProxDeploy selbst angelegt hat (geprüft über das Tag `proxdeploy` + Auftrags-ID in der Beschreibung).
|
||||||
|
|
||||||
|
**Parallelität:** pg-boss mit konfigurierbarer Parallelität im worker (Standard 4); Template-Bau pro
|
||||||
|
Server+Distribution singleton (zweiter Deploy wartet auf denselben Bau statt doppelt zu bauen).
|
||||||
|
|
||||||
|
## 7. Datenmodell (Prisma, Entwurf)
|
||||||
|
|
||||||
|
Namensabbildung (verbindlich, kommt nach `CLAUDE.md`):
|
||||||
|
|
||||||
|
| Vorgabe | Modell / Begriff | Vorgabe | Modell / Begriff |
|
||||||
|
|---|---|---|---|
|
||||||
|
| User | `Benutzer` | Deployment / Job | `Auftrag` (Art `AUSROLLEN`, `TEMPLATE_BAUEN`, `AUFRAEUMEN`) |
|
||||||
|
| API token (CLI) | `ApiToken` | Phase | `Phase` |
|
||||||
|
| SSH key | `SshSchluessel` | Job log line | `Logeintrag` |
|
||||||
|
| Server | `Server` | VMID lock | `VmidReservierung` |
|
||||||
|
| Node | `Knoten` (nur Feldname, kein Modell) | Template (Proxmox) | `Template` |
|
||||||
|
| Distribution | `Distribution` | Preset | `Vorlage` |
|
||||||
|
| Profile | `Profil` | Audit log | `Protokoll` |
|
||||||
|
| Setting | `Einstellung` | Key provider | `SchluesselQuelle` (Interface) |
|
||||||
|
|
||||||
|
```prisma
|
||||||
|
enum Rolle { ADMIN OPERATOR }
|
||||||
|
enum GastTyp { VM LXC }
|
||||||
|
enum AuftragsArt { AUSROLLEN TEMPLATE_BAUEN AUFRAEUMEN }
|
||||||
|
enum AuftragsStatus { WARTEND LAEUFT ERFOLGREICH FEHLGESCHLAGEN ABGEBROCHEN AUFGERAEUMT }
|
||||||
|
enum PhasenStatus { OFFEN LAEUFT ERLEDIGT FEHLER UEBERSPRUNGEN }
|
||||||
|
enum Herkunft { KATALOG EIGEN }
|
||||||
|
enum Quelle { WEB CLI API }
|
||||||
|
|
||||||
|
model Benutzer {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
benutzername String @unique
|
||||||
|
anzeigename String
|
||||||
|
email String?
|
||||||
|
passwortHash String? // null bei reinen OIDC-Benutzern
|
||||||
|
oidcSubjekt String? @unique
|
||||||
|
rolle Rolle @default(OPERATOR)
|
||||||
|
aktiv Boolean @default(true)
|
||||||
|
standards Json? // persönliche Standardwerte im Assistenten
|
||||||
|
erstelltAm DateTime @default(now())
|
||||||
|
apiTokens ApiToken[] sshSchluessel SshSchluessel[] auftraege Auftrag[] protokoll Protokoll[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model ApiToken {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
benutzerId String
|
||||||
|
name String
|
||||||
|
praefix String @unique // "pd_ab12cd34" – erkennbar, Rest nur gehasht
|
||||||
|
hash String // SHA-256 des Geheimnisses
|
||||||
|
zuletztGenutztAm DateTime?
|
||||||
|
ablaufAm DateTime?
|
||||||
|
widerrufenAm DateTime?
|
||||||
|
erstelltAm DateTime @default(now())
|
||||||
|
}
|
||||||
|
|
||||||
|
model SshSchluessel {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
benutzerId String? // null = für alle sichtbar (Team-Schlüssel)
|
||||||
|
name String
|
||||||
|
oeffentlich String
|
||||||
|
fingerabdruck String // SHA256:…
|
||||||
|
quelle String @default("lokal") // Kennung der SchluesselQuelle (später z. B. sshkeyvault)
|
||||||
|
@@unique([benutzerId, fingerabdruck])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Server {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String @unique // "rz1" – auch CLI-Name
|
||||||
|
url String // https://host:8006
|
||||||
|
tokenId String // user@realm!tokenid
|
||||||
|
tokenGeheimnis String // AES-256-GCM, v1:<iv>:<tag>:<daten>
|
||||||
|
tlsPruefen Boolean @default(true)
|
||||||
|
fingerabdruck String? // SHA-256, gepinnt bei selbst signiertem Zertifikat
|
||||||
|
sshAktiv Boolean @default(false)
|
||||||
|
sshBenutzer String @default("root")
|
||||||
|
sshPort Int @default(22)
|
||||||
|
sshPrivat String? // verschlüsselt
|
||||||
|
sshOeffentlich String?
|
||||||
|
sshHostSchluessel Json? // je Node gepinnt
|
||||||
|
templateVmidVon Int @default(9000)
|
||||||
|
templateVmidBis Int @default(9999)
|
||||||
|
gastVmidVon Int @default(100)
|
||||||
|
bauNetz Json? // Bridge, VLAN, IP/CIDR, Gateway für Template-Vorbereitung ohne SSH
|
||||||
|
standards Json? // Standard-Node, -Storage, -Bridge
|
||||||
|
faehigkeiten Json? // letzte Erkennung (Version, Storages, Rechte, Strategien)
|
||||||
|
erreichbar Boolean?
|
||||||
|
geprueftAm DateTime?
|
||||||
|
erstelltAm DateTime @default(now())
|
||||||
|
}
|
||||||
|
|
||||||
|
model Distribution {
|
||||||
|
id String @id // "debian-13"
|
||||||
|
name String
|
||||||
|
familie String
|
||||||
|
definition Json // validiertes YAML
|
||||||
|
dateiHash String
|
||||||
|
aktiv Boolean @default(true)
|
||||||
|
synchronisiertAm DateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
model Profil {
|
||||||
|
id String @id // "docker"
|
||||||
|
name String
|
||||||
|
beschreibung String?
|
||||||
|
herkunft Herkunft
|
||||||
|
quelltext String // YAML wie eingegeben (Kommentare bleiben)
|
||||||
|
definition Json
|
||||||
|
aktiv Boolean @default(true)
|
||||||
|
geaendertVonId String?
|
||||||
|
geaendertAm DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
model Template {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
serverId String
|
||||||
|
knoten String
|
||||||
|
vmid Int
|
||||||
|
distributionId String
|
||||||
|
storage String
|
||||||
|
imageQuelle String // URL + Prüfsumme des Images
|
||||||
|
gebautVonAuftragId String?
|
||||||
|
gebautAm DateTime
|
||||||
|
@@unique([serverId, vmid])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Vorlage { // Preset
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String @unique // "docker-host-klein"
|
||||||
|
titel String
|
||||||
|
beschreibung String?
|
||||||
|
gastTyp GastTyp
|
||||||
|
parameter Json // Teilmenge der Auftrags-Anfrage
|
||||||
|
erstelltVonId String?
|
||||||
|
geaendertAm DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
model Auftrag {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
kurzId String @unique // "d-7f3k2" für CLI und URLs
|
||||||
|
art AuftragsArt
|
||||||
|
status AuftragsStatus @default(WARTEND)
|
||||||
|
serverId String
|
||||||
|
knoten String?
|
||||||
|
gastTyp GastTyp?
|
||||||
|
vmid Int?
|
||||||
|
name String?
|
||||||
|
distributionId String?
|
||||||
|
profile String[]
|
||||||
|
anfrage Json // validierte Anfrage (Grundlage für „Wiederholen“)
|
||||||
|
plan Json // Plan zum Zeitpunkt des Starts
|
||||||
|
ergebnis Json? // IP, SSH-Befehl, Dauer
|
||||||
|
angelegt Json? // was zum Aufräumen gehört
|
||||||
|
fehler Json? // { phase, ursache, hinweis }
|
||||||
|
quelle Quelle
|
||||||
|
erstelltVonId String
|
||||||
|
wiederholtVonId String?
|
||||||
|
vorlageId String?
|
||||||
|
erstelltAm DateTime @default(now())
|
||||||
|
gestartetAm DateTime?
|
||||||
|
beendetAm DateTime?
|
||||||
|
phasen Phase[] log Logeintrag[]
|
||||||
|
@@index([serverId, erstelltAm]) @@index([status])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Phase {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
auftragId String
|
||||||
|
reihenfolge Int
|
||||||
|
schluessel String // "klonen"
|
||||||
|
titel String // "Klonen"
|
||||||
|
status PhasenStatus @default(OFFEN)
|
||||||
|
detail String?
|
||||||
|
ursache String?
|
||||||
|
hinweis String?
|
||||||
|
gestartetAm DateTime?
|
||||||
|
beendetAm DateTime?
|
||||||
|
@@unique([auftragId, schluessel])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Logeintrag {
|
||||||
|
id BigInt @id @default(autoincrement()) // auch SSE-Event-ID
|
||||||
|
auftragId String
|
||||||
|
zeit DateTime @default(now())
|
||||||
|
stufe String // debug|info|warn|error
|
||||||
|
phase String?
|
||||||
|
nachricht String
|
||||||
|
daten Json?
|
||||||
|
@@index([auftragId, id])
|
||||||
|
}
|
||||||
|
|
||||||
|
model VmidReservierung {
|
||||||
|
serverId String
|
||||||
|
vmid Int
|
||||||
|
auftragId String
|
||||||
|
ablaufAm DateTime
|
||||||
|
@@id([serverId, vmid])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Protokoll { // Audit-Log, nur anhängen
|
||||||
|
id BigInt @id @default(autoincrement())
|
||||||
|
zeit DateTime @default(now())
|
||||||
|
benutzerId String?
|
||||||
|
quelle Quelle
|
||||||
|
aktion String // "Server angelegt", "Ausrollung gestartet"
|
||||||
|
ziel String? // "server:rz1", "auftrag:d-7f3k2"
|
||||||
|
details Json?
|
||||||
|
ip String?
|
||||||
|
}
|
||||||
|
|
||||||
|
model Einstellung { schluessel String @id wert Json }
|
||||||
|
```
|
||||||
|
|
||||||
|
Datenbankregeln (CHECK/Trigger, wie in Laufzettel): `Protokoll` nur INSERT, VMID-Bereiche
|
||||||
|
`von < bis`, `Auftrag.vmid` innerhalb 100–999999999, ein Template je Server/VMID.
|
||||||
|
|
||||||
|
## 8. REST-API (`/api/v1`)
|
||||||
|
|
||||||
|
Authentifizierung: Sitzungs-Cookie (Web) **oder** `Authorization: Bearer pd_…` (CLI). Rolle und
|
||||||
|
Aktiv-Status werden pro Anfrage aus der DB gelesen. Jede schreibende Anfrage → `Protokoll`.
|
||||||
|
Fehler einheitlich `{ fehler: { code, nachricht, hinweis?, felder? } }`.
|
||||||
|
|
||||||
|
| Methode + Pfad | Rolle | Zweck |
|
||||||
|
|---|---|---|
|
||||||
|
| `POST /auth/anmelden`, `POST /auth/abmelden`, `GET /auth/oidc/start`, `GET /auth/oidc/rueckruf` | – | Anmeldung |
|
||||||
|
| `GET /ich` | alle | aktueller Benutzer, Rolle, Version |
|
||||||
|
| `GET /server` · `POST /server` · `GET/PATCH/DELETE /server/:name` | Admin schreibt | Server |
|
||||||
|
| `POST /server/pruefen` | Admin | Verbindungstest ohne Speichern (liefert Fingerprint zum Bestätigen) |
|
||||||
|
| `POST /server/:name/test` | alle | Version, Cluster/Nodes, Storages, Bridges, Rechte, Fähigkeiten |
|
||||||
|
| `GET /server/:name/ressourcen?knoten=` | alle | Nodes, freie Ressourcen, Storages, Bridges/VLANs/VNets, nächste freie ID |
|
||||||
|
| `POST /server/:name/ssh` | Admin | Schlüsselpaar erzeugen/erneuern, Host-Key pinnen |
|
||||||
|
| `GET /distributionen?typ=vm\|lxc` · `PATCH /distributionen/:id` | Admin schreibt | Katalog |
|
||||||
|
| `GET /profile` · `POST /profile` · `PUT/DELETE /profile/:id` · `POST /profile/pruefen` | Admin schreibt | Profile + Validierung |
|
||||||
|
| `GET /server/:name/templates` | alle | Templates je Node |
|
||||||
|
| `POST /server/:name/templates` | Admin, Operator | Template bauen → Auftrag |
|
||||||
|
| `POST /auftraege/plan` | alle | **Dry-Run**: Plan + CLI-Befehl, nichts wird angelegt |
|
||||||
|
| `POST /auftraege` | Operator+ | Ausrollen (VM/LXC) → `202 { id, kurzId }` |
|
||||||
|
| `POST /auftraege/stapel` | Operator+ | Batch (YAML/JSON-Liste) |
|
||||||
|
| `GET /auftraege?server=&typ=&distribution=&status=&seite=` | alle | Verlauf |
|
||||||
|
| `GET /auftraege/:id` | alle | Stand inkl. Phasen + Ergebnis |
|
||||||
|
| `GET /auftraege/:id/ereignisse` | alle | **SSE**: `phase`, `log`, `ende`; `Last-Event-ID` |
|
||||||
|
| `GET /auftraege/:id/log?ab=` | alle | Detail-Log |
|
||||||
|
| `POST /auftraege/:id/wiederholen` · `/abbrechen` · `/aufraeumen` | Operator+ | |
|
||||||
|
| `GET/POST/PATCH/DELETE /vorlagen…` | Operator+ | Presets |
|
||||||
|
| `GET/POST/DELETE /schluessel…` | eigene | SSH-Public-Keys (über `SchluesselQuelle`) |
|
||||||
|
| `GET/POST/DELETE /tokens…` | eigene | CLI-Tokens (Geheimnis nur einmal angezeigt) |
|
||||||
|
| `GET/POST/PATCH /benutzer…` | Admin | Benutzer, Rollen |
|
||||||
|
| `GET /protokoll?…` | Admin | Audit-Log |
|
||||||
|
| `GET/PUT /einstellungen` | Admin | Standardwerte, OIDC, Bereitstellungsschlüssel |
|
||||||
|
| `GET /openapi.json`, `GET /gesundheit` | – | Spezifikation, Healthcheck |
|
||||||
|
|
||||||
|
## 9. CLI (`cli/`, Go)
|
||||||
|
|
||||||
|
**Begründung Go:** ein statisches Binary pro Plattform (linux/darwin/windows × amd64/arm64, ~8 MB,
|
||||||
|
keine Laufzeit nötig – passt auf jeden Admin-Rechner und Jump-Host), sehr gute Unterstützung für
|
||||||
|
TTY-Erkennung, 24-bit-Farben und SSE. Der Nachteil (keine geteilten TS-Typen) wird durch den aus
|
||||||
|
`openapi.json` generierten Client (`oapi-codegen`) aufgefangen; ein CI-Schritt prüft, dass der
|
||||||
|
generierte Code aktuell ist. Bibliotheken: `cobra` (Befehle), `BurntSushi/toml`, `golang.org/x/term`.
|
||||||
|
|
||||||
|
- Konfig `~/.config/proxdeploy/config.toml` (`url`, `token`, optional `[profiles.<name>]` für mehrere
|
||||||
|
Instanzen), Rechte 0600; `PROXDEPLOY_URL`/`PROXDEPLOY_TOKEN` überschreiben.
|
||||||
|
- `login <url>` fragt Benutzername/Passwort ab, legt ein Token an und speichert es (oder `--token`).
|
||||||
|
- Ausgabe exakt nach Vorgabe; Renderer in `cli/internal/ausgabe/` mit Golden-File-Tests für Farbe,
|
||||||
|
`--no-color`, `--ascii`, `--quiet`, `--json`, `--dry-run`. Breite der Phasenspalte aus dem längsten
|
||||||
|
Phasennamen, Box-Breite aus dem Inhalt (Unicode-Breite beachtet).
|
||||||
|
- Exit-Codes: 0 Erfolg, 1 Auftrag fehlgeschlagen, 2 Bedienfehler, 3 Verbindung/Anmeldung.
|
||||||
|
- Die Web-GUI zeigt im letzten Assistentenschritt den passenden CLI-Befehl; erzeugt wird er vom
|
||||||
|
Server (`POST /auftraege/plan` liefert `cliBefehl`), damit beide Seiten dieselben Flags kennen.
|
||||||
|
|
||||||
|
## 10. Web-GUI
|
||||||
|
|
||||||
|
Seitenleiste mit Wortmarke, Server-Umschalter, Navigation (Übersicht, Ausrollen, Verlauf, Templates,
|
||||||
|
Vorlagen, Katalog, Server*, Einstellungen; * nur Admin schreibend). Panel-Karten mit 1-px-Linie,
|
||||||
|
Radius 14 px, Tokens aus der Farbtabelle der Vorgabe, dunkel zuerst, helles Theme umschaltbar
|
||||||
|
(`data-theme`), Kontrast ≥ 4,5:1 in beiden (wird in Tests geprüft). Statusanzeige als Komponente
|
||||||
|
`<Status>` mit Symbol + Farbe + Text.
|
||||||
|
|
||||||
|
- **Assistent** `/ausrollen`: Schritte als Route-Segmente mit dem Zustand in der URL (`?s=…`), damit
|
||||||
|
Zurückspringen, Neuladen und Teilen funktionieren; Vorbelegen per `?vorlage=` oder `?wiederholen=`.
|
||||||
|
Am Handy eine Schrittleiste oben, Formular einspaltig.
|
||||||
|
- **Live-Ansicht** `/auftraege/[kurzId]`: Terminal-Karte (JetBrains Mono) mit genau dem Aufbau der
|
||||||
|
CLI, darunter ausklappbares Detail-Log, am Ende die Ergebnis-Karte mit Kopieren-Knopf. Fallback auf
|
||||||
|
Polling, falls SSE durch den Proxy geblockt wird.
|
||||||
|
|
||||||
|
## 11. Sicherheit
|
||||||
|
|
||||||
|
- Secrets (Proxmox-Token, SSH-Private-Keys, OIDC-Client-Secret) mit AES-256-GCM, Schlüssel aus
|
||||||
|
`PROXDEPLOY_SCHLUESSEL` (32 Byte, Base64); Versionspräfix im Chiffrat für spätere Rotation.
|
||||||
|
Geheimnisse verlassen die API nie (nur „gesetzt“/Fingerprint).
|
||||||
|
- CLI-Tokens nur gehasht gespeichert; Passwörter argon2id; Anmeldung mit Rate-Limit.
|
||||||
|
- TLS zu Proxmox: Standard Systemvertrauen; bei selbst signiertem Zertifikat Pinning des
|
||||||
|
SHA-256-Fingerprints (TOFU **mit** Bestätigung im Formular). Kein globales `NODE_TLS_REJECT_UNAUTHORIZED`.
|
||||||
|
- Hinter Reverse-Proxy: `TRUST_PROXY=true` wertet `X-Forwarded-For/Proto` aus; Cookies `Secure`
|
||||||
|
abhängig vom tatsächlichen Schema (Lehre aus ProxLedger 0.11.1); SSE mit `X-Accel-Buffering: no`.
|
||||||
|
- Profil-Variablen werden für Shell gequotet; `run`-Schritte nur in Profilen, die ein Admin anlegt.
|
||||||
|
- Bereitstellungsschlüssel (für SSH in Gäste) wird nach der Provisionierung aus dem Gast entfernt.
|
||||||
|
|
||||||
|
## 12. Betrieb
|
||||||
|
|
||||||
|
- `docker-compose.yml`: `app`, `worker`, `postgres`, `migrate` (einmalig `prisma migrate deploy`).
|
||||||
|
Ein gemeinsames Image, Next `output: "standalone"`, Non-root.
|
||||||
|
- `deploy/install-lxc.sh`: auf dem Proxmox-Host ausführen → legt Debian-13-LXC an (per `pct`),
|
||||||
|
installiert Node, PostgreSQL, systemd-Units für app und worker, erzeugt `.env` mit Zufallsschlüssel.
|
||||||
|
- `.env.example` mit allen Variablen (`DATABASE_URL`, `PROXDEPLOY_SCHLUESSEL`, `SITZUNG_GEHEIMNIS`,
|
||||||
|
`APP_URL`, `TRUST_PROXY`, `OIDC_*`, `WORKER_PARALLEL`, `LOG_LEVEL`, `ADMIN_BENUTZER/PASSWORT` für
|
||||||
|
den ersten Start).
|
||||||
|
|
||||||
|
## 13. Dateistruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
proxdeploy/
|
||||||
|
├─ catalog/{distros,profiles}/*.yaml
|
||||||
|
├─ cli/ Go-Modul: cmd/proxdeploy, internal/{api,ausgabe,konfig,befehle}
|
||||||
|
├─ src/
|
||||||
|
│ ├─ app/(app)/… Seiten (Übersicht, ausrollen, auftraege, server, templates, vorlagen, katalog, einstellungen)
|
||||||
|
│ ├─ app/(auth)/anmelden
|
||||||
|
│ ├─ app/api/v1/… Route Handler (dünn: Recht prüfen, zod, Service)
|
||||||
|
│ ├─ components/ UI-Bausteine (Karte, Status, Terminal, Assistent, Formulare)
|
||||||
|
│ ├─ engine/ siehe Abschnitt 6 – frameworkfrei, ohne Prisma-Import
|
||||||
|
│ ├─ server/services/ Regeln + Schreiboperationen, rufen Engine und Prisma
|
||||||
|
│ ├─ server/queries/ Lesemodelle
|
||||||
|
│ ├─ server/auth/ Sitzung, Token, OIDC, Rechte
|
||||||
|
│ ├─ worker/ main.ts, Senke (Ereignisse → DB + NOTIFY), Katalog-Sync
|
||||||
|
│ └─ lib/ kryptografie.ts, formate.ts, logger.ts
|
||||||
|
├─ prisma/schema.prisma, migrations/
|
||||||
|
├─ public/brand/ Logo-Assets, Favicons, Manifest-Icons
|
||||||
|
├─ assets/ Banner, Avatar (Repo)
|
||||||
|
├─ deploy/install-lxc.sh
|
||||||
|
├─ tests/ engine/*, api/*, e2e/*
|
||||||
|
├─ docs/architektur.md, docs/issues/
|
||||||
|
├─ CHANGELOG.md, DEVLOG.md, CLAUDE.md, README.md, .env.example
|
||||||
|
└─ docker-compose.yml, Dockerfile
|
||||||
|
```
|
||||||
|
|
||||||
|
## 14. Etappen und Meilensteine
|
||||||
|
|
||||||
|
| Version | Etappe | Issues | Test gegen echten Proxmox |
|
||||||
|
|---|---|---|---|
|
||||||
|
| v0.1.0 | 1 – Server-Verwaltung + Verbindungstest | #001–#003 | Verbindungstest, Fähigkeiten, Rechte |
|
||||||
|
| v0.2.0 | 2 – Katalog, Template-Bau, Debian-13-VM, Live-Fortschritt | #004–#008 | Template bauen, VM ausrollen, Fehler + Aufräumen |
|
||||||
|
| v0.3.0 | 3 – LXC, Ubuntu, Profile, Presets | #009–#012 | LXC mit/ohne SSH, docker/zabbix |
|
||||||
|
| v0.4.0 | 4 – CLI | #013 | alle Befehle gegen die laufende Instanz |
|
||||||
|
| v0.5.0 | 5 – Verlauf, Audit, Rollen, OIDC | #014–#016 | – |
|
||||||
|
| v0.6.0 | 6 – Branding, README, Installer | #017–#019 | Installer in echtem LXC |
|
||||||
|
| v1.0.0 | Feldtest 8.x + 9.x, Feinschliff | #020 | vollständig |
|
||||||
|
|
||||||
|
Bis die Testumgebung steht, entwickle ich gegen einen **Proxmox-Mock** (`tests/proxmox-mock/`, ein
|
||||||
|
kleiner HTTP-Server mit Zustand, der die benutzten Endpunkte inkl. UPID-Tasks nachbildet). Die
|
||||||
|
Abnahme jeder Etappe gegen echten Proxmox wird nachgeholt und im DEVLOG vermerkt; ohne sie wird die
|
||||||
|
Version nicht als abgeschlossen markiert.
|
||||||
|
|
||||||
|
## 15. Offene Punkte
|
||||||
|
|
||||||
|
1. **Ubuntu 26.04** zusätzlich mitliefern? (Vorschlag: ja)
|
||||||
|
2. **Standard-BIOS** für Templates: OVMF (UEFI, braucht EFI-Disk) oder SeaBIOS? (Vorschlag: OVMF,
|
||||||
|
pro Distribution überschreibbar)
|
||||||
|
3. **Template-VMID-Schema**: feste Zuordnung je Distribution (Debian 13 → 9013, Ubuntu 24.04 → 9024)
|
||||||
|
plus Node-Versatz im Cluster mit lokalem Storage (pve02 → 9113)? (Vorschlag: ja)
|
||||||
|
4. **Domain** für `APP_URL` und OIDC-Redirect – kann später in `.env` gesetzt werden.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# #001 Projekt-Setup
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.1.0
|
||||||
|
**Labels:** chore, infrastruktur
|
||||||
|
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Lauffähiges Grundgerüst mit Projektorganisation, Design-Tokens und Prüfwerkzeugen.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Git, `.gitignore`, CHANGELOG, DEVLOG, Issues, `docs/architektur.md`, `CLAUDE.md` mit Namensabbildung
|
||||||
|
- [ ] Next.js 16, TypeScript strict, Tailwind 4 mit Tokens aus der Farbtabelle (dunkel + hell)
|
||||||
|
- [ ] Prisma 7 + Docker-Compose für Entwicklung (Postgres), Vitest mit Test-DB, ESLint/Prettier
|
||||||
|
- [ ] Versionen exakt pinnen und begründen; Build/Tests laufen in Docker (lokal kein Node)
|
||||||
|
- [ ] Grundlayout: Seitenleiste mit Wortmarke, Server-Umschalter, Theme-Umschalter, `<Status>`-Komponente
|
||||||
|
- [ ] Lokale Anmeldung (erster Admin aus `.env`), Sitzungs-Cookie, `/api/v1/gesundheit`
|
||||||
|
- [ ] pino-Logger (JSON), `.env.example`
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] `lint`, `typecheck`, `test`, `build` grün im Container
|
||||||
|
- [ ] Anmeldung funktioniert im gebauten Stand; keine Secrets im Repo
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
–
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# #002 Server-Verwaltung und Verschlüsselung
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.1.0
|
||||||
|
**Labels:** feature, sicherheit
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Proxmox-Server anlegen, bearbeiten, löschen; Geheimnisse verschlüsselt.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] AES-256-GCM-Helfer mit Versionspräfix, Tests (falscher Schlüssel, manipulierte Daten)
|
||||||
|
- [ ] Modell `Server`, Services, REST `/api/v1/server`, Formular mit Token-ID/Secret
|
||||||
|
- [ ] TLS: Fingerprint holen (`POST /server/pruefen`), anzeigen, bestätigen, pinnen
|
||||||
|
- [ ] Proxmox-Client mit undici-Agent und Fingerprint-Vergleich, UPID-Warten
|
||||||
|
- [ ] SSH optional: Schlüsselpaar erzeugen, Einzeiler anzeigen, Host-Key pinnen
|
||||||
|
- [ ] Protokolleintrag je Änderung
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Secret erscheint nie in API-Antworten oder Logs
|
||||||
|
- [ ] Falscher Fingerprint → klare Fehlermeldung, keine Verbindung
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#001
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# #003 Verbindungstest und Fähigkeitserkennung
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.1.0
|
||||||
|
**Labels:** feature, proxmox
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Button „Verbindung testen“ zeigt Version, Cluster/Nodes, Storages, Bridges/VLANs und was per API bzw. nur per SSH geht.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] `/version`, `/cluster/status`, `/cluster/resources`, `/nodes/{n}/storage`, `/nodes/{n}/network`, SDN-VNets
|
||||||
|
- [ ] Rechte über `/access/permissions` gegen Rolle (8.x/9.x-Variante) abgleichen, fehlende einzeln nennen
|
||||||
|
- [ ] Fähigkeiten: download-url import (≥ 8.4), import-from per Volume, Snippets-Storage, SSH erreichbar
|
||||||
|
- [ ] Übersichtsseite mit Serverstatus und freien Ressourcen; Serverdetail mit Nodes/Storages/Bridges
|
||||||
|
- [ ] Proxmox-Mock für Tests (8.3, 8.4, 9.2 als Varianten)
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Gegen echten Proxmox geprüft (sobald Testumgebung da ist)
|
||||||
|
- [ ] Tests decken 8.3 (SSH nötig), 8.4 und 9.2 ab
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#002
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# #004 Katalog: Distributionen und Profile als Daten
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.2.0
|
||||||
|
**Labels:** feature, katalog
|
||||||
|
**Geschätzt:** 5 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
YAML-Katalog laden, validieren, in die DB synchronisieren, in der GUI ansehen und deaktivieren.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] zod-Schemas für `catalog/distros` und `catalog/profiles`
|
||||||
|
- [ ] Debian 12/13, Ubuntu 22.04/24.04 (URLs/Prüfsummen geprüft am 2026-10-12)
|
||||||
|
- [ ] Prüfsummen-Parser für beide Zeilenformate; LXC-Musterauflösung mit Versionssortierung
|
||||||
|
- [ ] Sync beim worker-Start (Upsert, Aktiv-Schalter bleibt), fehlerhafte Datei überspringen + melden
|
||||||
|
- [ ] Katalog-Seite (Distributionen, Profile, aktiv/inaktiv)
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Unit-Tests für Schema, Sync und Muster
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#001
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# #005 Adapter debian und Profil-Engine
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.2.0
|
||||||
|
**Labels:** feature, engine
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Interface `FamilienAdapter`, Umsetzung `debian`, Profil `base` wird zu einem idempotenten Skript.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Interface + Registry; `debian`-Adapter (apt, systemd, deb822, locale, keyboard, sshd_config.d)
|
||||||
|
- [ ] Profilauflösung (requires, Reihenfolge, Variablen, Shell-Quoting)
|
||||||
|
- [ ] Profil `base` (Updates, Guest-Agent, Europe/Berlin, de_DE.UTF-8, Tastatur de, unattended-upgrades, sudo-User, SSH-Härtung, chrony, fail2ban optional)
|
||||||
|
- [ ] Snapshot-Tests der erzeugten Skripte; shellcheck auf die Ausgabe
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Neues Profil/neuer Adapter braucht keine Änderung an Engine-Code
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#004
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# #006 Aufträge, Phasen, worker und Live-Fortschritt
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.2.0
|
||||||
|
**Labels:** feature, engine
|
||||||
|
**Geschätzt:** 8 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Hintergrund-Jobs mit Phasen in der DB, live per SSE in der Web-GUI.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] pg-boss im worker, Modelle `Auftrag`, `Phase`, `Logeintrag`, `VmidReservierung`
|
||||||
|
- [ ] Phasen-Runner mit Ereignis-Senke (DB + NOTIFY), Fehler mit Ursache + Hinweis
|
||||||
|
- [ ] SSE-Endpunkt mit Last-Event-ID, Polling-Fallback
|
||||||
|
- [ ] VMID-Vergabe mit Advisory-Lock, Test mit parallelen Aufträgen
|
||||||
|
- [ ] Live-Ansicht als Terminal-Karte, Detail-Log, Ergebnis-Karte
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Zwei parallele Aufträge bekommen nie dieselbe VMID (Test)
|
||||||
|
- [ ] Neuladen der Seite mitten im Auftrag zeigt den vollständigen Stand
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#003
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# #007 Template-Bau für VMs
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.2.0
|
||||||
|
**Labels:** feature, proxmox
|
||||||
|
**Geschätzt:** 8 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Cloud-Image laden, Prüfsumme prüfen, VM anlegen, Disk importieren, Guest-Agent einbauen, als Template markieren.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Weg A (≥ 8.4): `download-url` (content=import, checksum) + `import-from` per Volume-ID
|
||||||
|
- [ ] Weg B (SSH): Download + Prüfung auf dem Node, Import per `qm importdisk`/`import-from`
|
||||||
|
- [ ] Hardware: q35, OVMF+EFI-Disk oder SeaBIOS, virtio-scsi-single, discard/ssd/iothread, CPU host, serielle Konsole, agent=1, cloud-init-Laufwerk
|
||||||
|
- [ ] Guest-Agent einbauen: Snippet (SSH) oder Bau-Adresse + SSH in die VM
|
||||||
|
- [ ] Template-Übersicht je Server/Node, VMID-Bereich konfigurierbar
|
||||||
|
- [ ] Singleton je Server+Distribution
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Debian-13-Template auf echtem Proxmox gebaut (8.x und 9.x, sobald verfügbar)
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#005, #006
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# #008 Deploy-Assistent und VM ausrollen
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.2.0
|
||||||
|
**Labels:** feature
|
||||||
|
**Geschätzt:** 10 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Debian-13-VM aus Template vollständig unattended, Assistent mit Dry-Run und CLI-Befehl.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Planer VM (Phasen + geplante API-Aufrufe), `POST /auftraege/plan`
|
||||||
|
- [ ] Ausführung: Klonen, Disk vergrößern, cloud-init (sshkeys korrekt kodiert, ciupgrade=0), Start, Agent, Provisionierung per Agent
|
||||||
|
- [ ] Fehlendes Template → automatisch bauen anbieten
|
||||||
|
- [ ] Assistent mit 9 Schritten, URL-Zustand, Handy-tauglich
|
||||||
|
- [ ] Aufräumen nach Bestätigung
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] VM mit base-Profil per SSH erreichbar; Fehlerfall zeigt Ursache + Hinweis
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#007
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #009 LXC-Container ausrollen
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.3.0
|
||||||
|
**Labels:** feature, proxmox
|
||||||
|
**Geschätzt:** 8 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
LXC aus Proxmox-Template, Provisionierung per pct exec (SSH zum Node) oder SSH in den Container.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] aplinfo prüfen/herunterladen, Planer LXC, Swap, unprivilegiert, Features (nesting per API, keyctl nur per SSH)
|
||||||
|
- [ ] Transport `ssh-node` (pct exec) und `ssh-gast` (Bereitstellungsschlüssel, danach entfernen)
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] LXC mit base auf echtem Proxmox, einmal mit und einmal ohne Node-SSH
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#008
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #010 Ubuntu 22.04 und 24.04
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.3.0
|
||||||
|
**Labels:** feature, katalog
|
||||||
|
**Geschätzt:** 3 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Ubuntu als VM und LXC über den debian-Adapter.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Unterschiede im Adapter (Codename-Ermittlung, Locale-Paket, unattended-upgrades)
|
||||||
|
- [ ] ggf. Ubuntu 26.04 (offener Punkt)
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Je eine Ubuntu-VM und ein Ubuntu-LXC ausgerollt
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#009
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# #011 Profile docker und zabbix-agent, Variablen, Editor
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.3.0
|
||||||
|
**Labels:** feature
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Kombinierbare Profile mit Variablen; eigene Profile im YAML-Editor.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] docker (deb822, nesting bei LXC automatisch), zabbix-agent (7.0 LTS, Server/ServerActive)
|
||||||
|
- [ ] Variablen als Formularfelder; Ausgrauen ohne Umsetzung für die Familie
|
||||||
|
- [ ] YAML-Editor mit Validierung und Fehlerstelle
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] docker run hello-world im ausgerollten Gast erfolgreich
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#005
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# #012 Vorlagen (Presets)
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.3.0
|
||||||
|
**Labels:** feature
|
||||||
|
**Geschätzt:** 3 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Gespeicherte Kombinationen, im Assistenten mit einem Klick vorbelegbar.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] CRUD, „aus diesem Auftrag als Vorlage speichern“, Beispiel „Docker-Host klein“
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] `--preset` in API und Assistent identisch aufgelöst
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#008
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# #013 CLI proxdeploy (Go)
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.4.0
|
||||||
|
**Labels:** feature, cli
|
||||||
|
**Geschätzt:** 12 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Alle Befehle aus der Vorgabe, Ausgabe exakt im Format der Vorgabe.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] OpenAPI aus zod, Go-Client per oapi-codegen, Prüfung auf Aktualität
|
||||||
|
- [ ] login, servers, distros, profiles, vm, lxc, template build, batch, status, logs --follow
|
||||||
|
- [ ] Renderer: Farbe 24-bit/256/aus, --ascii, --quiet, --json, --dry-run; Golden-Tests
|
||||||
|
- [ ] Release-Builds für linux/darwin/windows × amd64/arm64
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Ausgabe entspricht zeichengenau dem Mockup (Golden-File)
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#008, #012
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #014 Verlauf und Wiederholen
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.5.0
|
||||||
|
**Labels:** feature
|
||||||
|
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Alle Aufträge filterbar, mit gleichen Parametern wiederholen.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Filter Server/Typ/Distribution/Status, Seitenblättern
|
||||||
|
- [ ] Wiederholen (neue VMID/Name abfragen)
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Filter bleiben in der URL
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#008
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# #015 Rollen, Benutzer, Tokens, Audit-Log
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.5.0
|
||||||
|
**Labels:** feature, sicherheit
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Admin/Operator serverseitig erzwungen, jede Aktion protokolliert.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Rechte-Tabelle, strukturelle Prüfung aller Route Handler (Test)
|
||||||
|
- [ ] Benutzerverwaltung, CLI-Tokens, SSH-Keys über `SchluesselQuelle`
|
||||||
|
- [ ] Audit-Log-Ansicht mit Filter
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Operator kann keine Server/Katalog/Benutzer ändern (Tests)
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#001
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# #016 Anmeldung per OIDC
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.5.0
|
||||||
|
**Labels:** feature, sicherheit
|
||||||
|
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Optionale OIDC-Anmeldung (z. B. authentik), Rollen über Gruppen-Claim.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] openid-client mit PKCE, Discovery, Gruppen → Rolle, Konto-Verknüpfung
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Tests gegen einen Mock-IdP (echter IdP später)
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#015
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #017 Branding-Assets
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.6.0
|
||||||
|
**Labels:** design
|
||||||
|
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Alle Logo-Varianten, Banner, Favicons, Manifest-Icons nach Vorgabe.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] symbol(-light), icon-small, avatar, logo(-light), banner 1280×640
|
||||||
|
- [ ] Favicon 16/32, Apple-Touch-Icon, Manifest-Icons per Skript aus SVG
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Darstellung in beiden Themes geprüft
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#001
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #018 README und Dokumentation
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.6.0
|
||||||
|
**Labels:** doku
|
||||||
|
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
README mit Banner, Screenshots, Installation, CLI, Proxmox-Rechten, neuer Distribution, eigenem Profil.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Screenshots aus dem gebauten Stand
|
||||||
|
- [ ] Hinweis: unabhängiges Tool, nicht von Proxmox Server Solutions
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Anleitungen einmal Schritt für Schritt nachvollzogen
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#013
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #019 Docker-Image und LXC-Installer
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v0.6.0
|
||||||
|
**Labels:** infrastruktur
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Produktionsbetrieb per Docker Compose oder in einem Debian-LXC.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Dockerfile (standalone, non-root), Compose mit migrate
|
||||||
|
- [ ] `deploy/install-lxc.sh` (auf dem Proxmox-Host), Update-Pfad
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Installer in echtem LXC durchgelaufen
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
#001
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# #020 Feldtest 8.x und 9.x, Version 1.0.0
|
||||||
|
**Status:** offen
|
||||||
|
**Meilenstein:** v1.0.0
|
||||||
|
**Labels:** test
|
||||||
|
**Geschätzt:** 6 h **Tatsächlich:** –
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Vollständiger Durchlauf gegen echte Proxmox-Hosts beider Hauptversionen.
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
- [ ] Matrix: VM/LXC × Debian/Ubuntu × mit/ohne SSH × 8.x/9.x
|
||||||
|
- [ ] Gefundene Fehler als eigene Issues
|
||||||
|
|
||||||
|
## Akzeptanzkriterien
|
||||||
|
- [ ] Alle Kombinationen grün oder mit Begründung ausgeschlossen
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
alle
|
||||||
|
|
||||||
|
## Notizen / Entscheidungen
|
||||||
|
–
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Issue-Übersicht
|
||||||
|
|
||||||
|
Details und Architektur: [../architektur.md](../architektur.md). Zeiten werden aus dem [DEVLOG](../../DEVLOG.md) übernommen.
|
||||||
|
|
||||||
|
| Nr. | Titel | Status | Meilenstein | Geschätzt | Tatsächlich |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| [#001](001-projekt-setup.md) | Projekt-Setup | offen | v0.1.0 | 4 h | – |
|
||||||
|
| [#002](002-verschluesselung-server.md) | Server-Verwaltung und Verschlüsselung | offen | v0.1.0 | 6 h | – |
|
||||||
|
| [#003](003-verbindungstest.md) | Verbindungstest und Fähigkeitserkennung | offen | v0.1.0 | 6 h | – |
|
||||||
|
| [#004](004-katalog.md) | Katalog: Distributionen und Profile als Daten | offen | v0.2.0 | 5 h | – |
|
||||||
|
| [#005](005-adapter-profile.md) | Adapter debian und Profil-Engine | offen | v0.2.0 | 6 h | – |
|
||||||
|
| [#006](006-auftraege-sse.md) | Aufträge, Phasen, worker und Live-Fortschritt | offen | v0.2.0 | 8 h | – |
|
||||||
|
| [#007](007-template-bau.md) | Template-Bau für VMs | offen | v0.2.0 | 8 h | – |
|
||||||
|
| [#008](008-vm-ausrollen.md) | Deploy-Assistent und VM ausrollen | offen | v0.2.0 | 10 h | – |
|
||||||
|
| [#009](009-lxc.md) | LXC-Container ausrollen | offen | v0.3.0 | 8 h | – |
|
||||||
|
| [#010](010-ubuntu.md) | Ubuntu 22.04 und 24.04 | offen | v0.3.0 | 3 h | – |
|
||||||
|
| [#011](011-profile-docker-zabbix.md) | Profile docker und zabbix-agent, Variablen, Editor | offen | v0.3.0 | 6 h | – |
|
||||||
|
| [#012](012-vorlagen.md) | Vorlagen (Presets) | offen | v0.3.0 | 3 h | – |
|
||||||
|
| [#013](013-cli.md) | CLI proxdeploy (Go) | offen | v0.4.0 | 12 h | – |
|
||||||
|
| [#014](014-verlauf.md) | Verlauf und Wiederholen | offen | v0.5.0 | 4 h | – |
|
||||||
|
| [#015](015-rollen-audit.md) | Rollen, Benutzer, Tokens, Audit-Log | offen | v0.5.0 | 6 h | – |
|
||||||
|
| [#016](016-oidc.md) | Anmeldung per OIDC | offen | v0.5.0 | 4 h | – |
|
||||||
|
| [#017](017-branding.md) | Branding-Assets | offen | v0.6.0 | 4 h | – |
|
||||||
|
| [#018](018-readme.md) | README und Dokumentation | offen | v0.6.0 | 4 h | – |
|
||||||
|
| [#019](019-installer.md) | Docker-Image und LXC-Installer | offen | v0.6.0 | 6 h | – |
|
||||||
|
| [#020](020-feldtest.md) | Feldtest 8.x und 9.x, Version 1.0.0 | offen | v1.0.0 | 6 h | – |
|
||||||
Reference in New Issue
Block a user