docs: CLI in README, Architektur und Konventionen

Refs #013

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 15:08:42 +02:00
co-authored by Claude Opus 5.5
parent bd4bca5399
commit 4ae08abd7c
6 changed files with 117 additions and 12 deletions
+6
View File
@@ -8,14 +8,20 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
## [Unveröffentlicht] ## [Unveröffentlicht]
### Hinzugefügt ### Hinzugefügt
- CLI `proxdeploy` (Go, ein Binary für Linux/macOS/Windows × amd64/arm64): `login`, `servers`, `distros`, `profiles`, `presets`, `vm`, `lxc`, `template list|build`, `batch`, `status`, `logs --follow`, `cancel`; Ausgabe im Aufbau der Vorgabe mit 24-bit-/256-Farben, `--ascii`, `--quiet`, `--json`, `--dry-run` (#013)
- API-Tokens für die CLI: anlegen und widerrufen in den Einstellungen, `proxdeploy login` tauscht Benutzername und Passwort gegen ein Token; Anmeldung per `Authorization: Bearer` (#013)
- Kurze Anfragen: fehlen Storage, Bridge, Node, Benutzer oder SSH-Schlüssel, nimmt der Server die Standards (Server-Einstellungen, Verbindungstest, eigener Benutzername, hinterlegte Schlüssel) – auch beim Template-Bau (#013)
- OpenAPI-Beschreibung unter `/api/v1/openapi.json`, aus denselben zod-Schemas wie die API (#013)
### Geändert ### Geändert
- Die Abschlussbox (Name, ID, IP, Profile, SSH bzw. Phase, Ursache, Hinweis) berechnet der Server; Web-GUI und CLI zeigen dieselben Zeilen (#013)
### Behoben ### Behoben
### Entfernt ### Entfernt
### Sicherheit ### Sicherheit
- API-Tokens werden nur als SHA-256 gespeichert und genau einmal angezeigt; ein ungültiges Token gilt als nicht angemeldet, auch wenn zusätzlich ein Sitzungscookie mitkommt (#013)
## [0.3.0] – 2026-10-12 ## [0.3.0] – 2026-10-12
+7
View File
@@ -38,6 +38,7 @@ src/app/api/v1/* Route Handler: Recht prüfen, zod, Service. Sonst nichts
src/components/* Darstellung, keine Geschäftslogik. src/components/* Darstellung, keine Geschäftslogik.
src/lib/* Framework-freie Helfer; was Client und Server teilen, liegt hier. src/lib/* Framework-freie Helfer; was Client und Server teilen, liegt hier.
src/worker/* Hintergrundprozess (pg-boss). src/worker/* Hintergrundprozess (pg-boss).
cli/ CLI in Go; nur REST-API. Typen aus cli/api/openapi.json (oapi-codegen).
``` ```
- **Web-GUI und CLI nutzen dieselbe REST-API.** Keine Logik nur für eine Oberfläche. - **Web-GUI und CLI nutzen dieselbe REST-API.** Keine Logik nur für eine Oberfläche.
@@ -61,6 +62,11 @@ Node 24 über nvm (`export NVM_DIR="$HOME/.nvm"; . "$NVM_DIR/nvm.sh"`), pnpm 12.
`pino@10.4.0`. Obergrenzen: **eslint 9.x** (eslint-plugin-react aus eslint-config-next kann 10 nicht), `pino@10.4.0`. Obergrenzen: **eslint 9.x** (eslint-plugin-react aus eslint-config-next kann 10 nicht),
**typescript ~6.0.3** (typescript-eslint 8 erlaubt < 6.1). **typescript ~6.0.3** (typescript-eslint 8 erlaubt < 6.1).
CLI: **Go 1.27.2** ohne sudo unter `~/.local/go` (`export PATH="$HOME/.local/go/bin:$PATH"`),
`cobra 1.10.2`, `BurntSushi/toml 1.6.0`, `x/term 0.46.0`, `go-runewidth 0.0.30`,
`go.yaml.in/yaml/v3 3.0.5`, `oapi-codegen 2.8.0` (als `go tool`). Antwortschemas der API stehen in
`src/lib/schemas/api.ts`; nach einer Änderung `pnpm openapi` und `go generate ./...` in `cli/`.
Next 16: `proxy.ts` statt middleware; `cookies()`, `headers()`, `params`, `searchParams` sind async. Next 16: `proxy.ts` statt middleware; `cookies()`, `headers()`, `params`, `searchParams` sind async.
Prisma 7: Client aus `@/generated/prisma/client`, Enum-Werte aus `@/generated/prisma/enums`, Zugriff Prisma 7: Client aus `@/generated/prisma/client`, Enum-Werte aus `@/generated/prisma/enums`, Zugriff
über den Lazy-Proxy `src/lib/db.ts`. über den Lazy-Proxy `src/lib/db.ts`.
@@ -70,6 +76,7 @@ Prisma 7: Client aus `@/generated/prisma/client`, Enum-Werte aus `@/generated/pr
```bash ```bash
pnpm db:up pnpm db:up
pnpm lint && pnpm typecheck && pnpm format:pruefen && pnpm test pnpm lint && pnpm typecheck && pnpm format:pruefen && pnpm test
pnpm cli:pruefen # wenn API-Schemas oder cli/ betroffen sind
``` ```
Ohne laufende Datenbank überspringt `pnpm test` die Datenbanktests und sagt es auf stderr. Ohne laufende Datenbank überspringt `pnpm test` die Datenbanktests und sagt es auf stderr.
+71 -1
View File
@@ -20,7 +20,7 @@ In Entwicklung. Version und Fortschritt stehen im [CHANGELOG](CHANGELOG.md), der
| 1 · v0.1.0 | Server-Verwaltung, Fingerprint-Pinning, Verbindungstest mit Fähigkeitserkennung | ✓ fertig, auf PVE 9.2 geprüft | | 1 · v0.1.0 | Server-Verwaltung, Fingerprint-Pinning, Verbindungstest mit Fähigkeitserkennung | ✓ fertig, auf PVE 9.2 geprüft |
| 2 · v0.2.0 | Katalog, Template-Bau, Debian-13-VM, Live-Fortschritt, Assistent | ✓ fertig, auf PVE 9.2 geprüft | | 2 · v0.2.0 | Katalog, Template-Bau, Debian-13-VM, Live-Fortschritt, Assistent | ✓ fertig, auf PVE 9.2 geprüft |
| 3 · v0.3.0 | LXC, Ubuntu, Profile, Vorlagen, Profile im Template, SSH-Schlüssel | ✓ fertig, auf PVE 9.2 geprüft (Bau-Adresse #021: Abnahme offen) | | 3 · v0.3.0 | LXC, Ubuntu, Profile, Vorlagen, Profile im Template, SSH-Schlüssel | ✓ fertig, auf PVE 9.2 geprüft (Bau-Adresse #021: Abnahme offen) |
| 4 · v0.4.0 | CLI `proxdeploy` (Go) | ◐ als Nächstes | | 4 · v0.4.0 | CLI `proxdeploy` (Go), API-Tokens | ◐ in Arbeit |
| 5 · v0.5.0 | Verlauf, Audit-Log, Rollen, OIDC | ○ geplant | | 5 · v0.5.0 | Verlauf, Audit-Log, Rollen, OIDC | ○ geplant |
| 6 · v0.6.0 | Branding, README mit Screenshots, Installer | ○ geplant | | 6 · v0.6.0 | Branding, README mit Screenshots, Installer | ○ geplant |
@@ -37,6 +37,72 @@ Maßgeblich ist die Proxmox-API (geprüft gegen PVE 8.x und 9.2):
Das API-Token braucht eine eigene Rolle; die Befehle stehen in Das API-Token braucht eine eigene Rolle; die Befehle stehen in
[docs/proxmox-rechte.md](docs/proxmox-rechte.md). [docs/proxmox-rechte.md](docs/proxmox-rechte.md).
## CLI
`proxdeploy` ist ein einzelnes Binary (Linux, macOS, Windows; amd64 und arm64) und spricht nur die
REST-API – dieselbe wie die Web-GUI, mit denselben Phasentexten.
```bash
proxdeploy login https://proxdeploy.example # fragt Benutzer und Passwort, speichert ein Token
proxdeploy servers
proxdeploy distros --type lxc
proxdeploy profiles
proxdeploy vm web01 --server rz1 --distro debian-13 --profile base,docker --ip 10.0.20.15/24 --gw 10.0.20.1 --vlan 20
proxdeploy lxc dns01 --server rz1 --distro ubuntu-24.04 --dry-run
proxdeploy template build --server rz1 --distro debian-13 --profile base,docker
proxdeploy batch gaeste.yaml
proxdeploy status a-7f3k
proxdeploy logs a-7f3k --follow
```
```
⬡ ProxDeploy v0.4 · Server rz1 · Node pve01 · Debian 13 (Template 9013)
✓ Prüfungen VMID 120 frei · local-zfs · vmbr0 VLAN 20
✓ Klonen full clone 9013 → 120 · Disk auf 40G
✓ cloud-init user florian · SSH-Key · Profile base, docker
✓ Start VM 120 läuft
✓ Guest-Agent antwortet nach 18s
◐ Provisionierung cloud-init läuft … 1m 12s
```
- Was nicht angegeben ist, füllt der Server: Storage, Bridge und Node aus den Server-Einstellungen
bzw. dem Verbindungstest, Benutzer = eigener Benutzername, SSH-Schlüssel = die in den Einstellungen
hinterlegten. `--preset` belegt aus einer Vorlage vor; Flags gehen vor.
- Konfiguration in `~/.config/proxdeploy/config.toml` (Rechte 0600): `url`, `token`, optional
`server` als Standard für `--server` und `[instances.<name>]` für weitere Instanzen
(`--instance`). `PROXDEPLOY_URL`, `PROXDEPLOY_TOKEN`, `PROXDEPLOY_INSTANCE` gehen vor.
- Tokens für Skripte und CI: Web-GUI → Einstellungen → API-Tokens, dann `proxdeploy login <url> --token pd_…`.
- Ausgabe: Farben (24-bit, sonst 256) nur im Terminal und ohne `NO_COLOR`/`--no-color`; `--ascii`
ersetzt Symbole durch `[OK]`, `[..]`, `[!!]`; `--quiet` zeigt nur die Abschlussbox; `--json` ist
maschinenlesbar. Ohne Terminal (Pipe, CI) erscheint jede Phase als eine Zeile, sobald sie fertig ist.
- Exit-Codes: `0` Erfolg, `1` Auftrag fehlgeschlagen, `2` Bedienfehler, `3` Verbindung/Anmeldung.
- `Strg+C` hängt nur ab – der Auftrag läuft weiter (`proxdeploy status <id>`); abbrechen mit
`proxdeploy cancel <id>`.
`batch` rollt mehrere Gäste aus; die Schlüssel heißen wie die Flags. Die Datei wird vollständig
geprüft, bevor der erste Auftrag startet:
```yaml
defaults:
server: rz1
distro: debian-13
profile: [base]
guests:
- name: web01
type: vm
profile: [base, docker]
ip: 10.0.20.15/24
gw: 10.0.20.1
memory: 4096
- name: mon01
type: lxc
profile: [base, zabbix-agent]
vars: { zabbix-agent: { server: zbx.example } }
```
Bauen: `cli/bauen.sh 0.4.0` legt die sechs Binaries und `SHA256SUMS` unter `cli/bin/` ab (Go 1.27).
## Entwicklung ## Entwicklung
Voraussetzungen: Node 24 (z. B. über nvm), pnpm 12 (corepack), Docker für PostgreSQL. Voraussetzungen: Node 24 (z. B. über nvm), pnpm 12 (corepack), Docker für PostgreSQL.
@@ -54,8 +120,12 @@ Prüfen vor jedem Commit:
```bash ```bash
pnpm lint && pnpm typecheck && pnpm format:pruefen && pnpm test pnpm lint && pnpm typecheck && pnpm format:pruefen && pnpm test
pnpm test:e2e # Browser-Abläufe gegen den gebauten Stand (Desktop und 390 px) pnpm test:e2e # Browser-Abläufe gegen den gebauten Stand (Desktop und 390 px)
pnpm cli:pruefen # openapi.json und Go-Typen aktuell, go vet, go test (Golden-Files)
``` ```
Ändert sich ein Schema der API, erst `pnpm openapi`, dann in `cli/` `go generate ./...` – der
Go-Client nutzt die aus `cli/api/openapi.json` erzeugten Typen.
Konventionen (deutsche Bezeichner, Schichtung, Versionen) stehen in [CLAUDE.md](CLAUDE.md). Konventionen (deutsche Bezeichner, Schichtung, Versionen) stehen in [CLAUDE.md](CLAUDE.md).
## Betrieb ## Betrieb
+13 -3
View File
@@ -500,9 +500,19 @@ TTY-Erkennung, 24-bit-Farben und SSE. Der Nachteil (keine geteilten TS-Typen) wi
`openapi.json` generierten Client (`oapi-codegen`) aufgefangen; ein CI-Schritt prüft, dass der `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`. 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 - Konfig `~/.config/proxdeploy/config.toml` (`url`, `token`, optional `server` als Standard und
Instanzen), Rechte 0600; `PROXDEPLOY_URL`/`PROXDEPLOY_TOKEN` überschreiben. `[instances.<name>]` für mehrere Instanzen – nicht `profiles`, das hieße wie `--profile`), Rechte
- `login <url>` fragt Benutzername/Passwort ab, legt ein Token an und speichert es (oder `--token`). 0600; `PROXDEPLOY_URL`/`PROXDEPLOY_TOKEN`/`PROXDEPLOY_INSTANCE` überschreiben.
- **Kurze Anfragen:** Die CLI schickt nur gesetzte Flags. Der Server füllt nach der Vorlage Storage,
Bridge, Node (Server-Standards bzw. Verbindungstest), Benutzer (eigener Name) und SSH-Schlüssel
(hinterlegte) – `anfrageErgaenzen` in `src/server/services/ausrollen.ts`.
- **Abschlussbox** (`abschluss` im Auftrag) berechnet der Server; Web und CLI zeigen dieselben Zeilen.
- **Generierter Code:** Antwortschemas als zod in `src/lib/schemas/api.ts`, daraus `openapi.json`
(`pnpm openapi`) und daraus die Go-Typen (oapi-codegen, nur Modelle). Anfragen gehen als Map hinaus
(sonst schickte Go leere Pflichtfelder statt sie wegzulassen). `pnpm cli:pruefen` schlägt fehl,
wenn etwas veraltet ist; `tests/api-schemas.test.ts` prüft echte Antworten gegen die Schemas.
- `login <url>` fragt Benutzername/Passwort ab, tauscht sie über `POST /api/v1/auth/token` gegen ein
Token und speichert es (oder `--token`). Tokens: `pd_` + 256 Bit, gespeichert nur als SHA-256.
- Ausgabe exakt nach Vorgabe; Renderer in `cli/internal/ausgabe/` mit Golden-File-Tests für Farbe, - 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 `--no-color`, `--ascii`, `--quiet`, `--json`, `--dry-run`. Breite der Phasenspalte aus dem längsten
Phasennamen, Box-Breite aus dem Inhalt (Unicode-Breite beachtet). Phasennamen, Box-Breite aus dem Inhalt (Unicode-Breite beachtet).
+19 -7
View File
@@ -1,5 +1,5 @@
# #013 CLI proxdeploy (Go) # #013 CLI proxdeploy (Go)
**Status:** offen **Status:** in Arbeit
**Meilenstein:** v0.4.0 **Meilenstein:** v0.4.0
**Labels:** feature, cli **Labels:** feature, cli
**Geschätzt:** 12 h **Tatsächlich:** – **Geschätzt:** 12 h **Tatsächlich:** –
@@ -8,16 +8,28 @@
Alle Befehle aus der Vorgabe, Ausgabe exakt im Format der Vorgabe. Alle Befehle aus der Vorgabe, Ausgabe exakt im Format der Vorgabe.
## Aufgaben ## Aufgaben
- [ ] OpenAPI aus zod, Go-Client per oapi-codegen, Prüfung auf Aktualität - [x] API-Tokens (`pd_…`, nur SHA-256 gespeichert, Ablauf, Widerruf) mit Bearer-Anmeldung, `POST /auth/token` für `login`, Verwaltung in den Einstellungen
- [ ] login, servers, distros, profiles, vm, lxc, template build, batch, status, logs --follow - [x] Kurze Anfragen: Server füllt Storage, Bridge, Node, Benutzer, Schlüssel (`anfrageErgaenzen`), auch beim Template-Bau
- [ ] Renderer: Farbe 24-bit/256/aus, --ascii, --quiet, --json, --dry-run; Golden-Tests - [x] Abschlussbox serverseitig (`abschluss`), Web und CLI zeigen dieselben Zeilen
- [ ] Release-Builds für linux/darwin/windows × amd64/arm64 - [x] OpenAPI aus zod (`/api/v1/openapi.json`, `pnpm openapi`), Go-Typen per oapi-codegen, `pnpm cli:pruefen`
- [x] login, servers, distros, profiles, presets, vm, lxc, template list/build, batch, status, logs --follow, cancel
- [x] Renderer: Farbe 24-bit/256/aus, --ascii, --quiet, --json, --dry-run; Golden-Tests
- [x] Release-Builds für linux/darwin/windows × amd64/arm64 (`cli/bauen.sh`)
- [ ] Abnahme auf pve-demo (VM + LXC per batch)
## Akzeptanzkriterien ## Akzeptanzkriterien
- [ ] Ausgabe entspricht zeichengenau dem Mockup (Golden-File) - [x] Ausgabe entspricht zeichengenau dem Mockup (`cli/internal/ausgabe/testdata/mockup.txt`, von Hand aus der Vorgabe übernommen)
## Abhängigkeiten ## Abhängigkeiten
#008, #012 #008, #012
## Notizen / Entscheidungen ## Notizen / Entscheidungen
– - **Anfragen als Map, Antworten typisiert.** oapi-codegen macht Pflichtfelder zu Nicht-Zeigern; Go
schickte dann `"storage": ""` und überschriebe Vorlagenwerte. Deshalb gehen nur gesetzte Flags hinaus.
- **`[instances.<name>]`** statt `[profiles.<name>]` in der Konfiguration – „profile“ ist schon `--profile`.
- **Strg+C hängt nur ab**, der Auftrag läuft weiter; Abbruch ist `proxdeploy cancel`.
- **Ohne Terminal** (Pipe, CI) kein Neuzeichnen: jede Phase eine Zeile, sobald fertig; die Kopfzeile
nach der ersten Phase, weil Node und Template erst dann feststehen.
- **SSE-Ausfall:** Wiederverbinden mit Last-Event-ID; nach drei Fehlschlägen ohne Stand Polling alle 2 s.
- **Go 1.27.2** ohne sudo unter `~/.local/go`; Bibliotheken mit abgelagerten Versionen (x/term 0.46.0,
go-runewidth 0.0.30 statt der wenige Tage alten Nachfolger).
+1 -1
View File
@@ -16,7 +16,7 @@ Details und Architektur: [../architektur.md](../architektur.md). Zeiten werden a
| [#010](010-ubuntu.md) | Ubuntu 22.04, 24.04 und 26.04 | erledigt | v0.3.0 | 3 h | 0 h 05 min | | [#010](010-ubuntu.md) | Ubuntu 22.04, 24.04 und 26.04 | erledigt | v0.3.0 | 3 h | 0 h 05 min |
| [#011](011-profile-docker-zabbix.md) | Profile docker und zabbix-agent, Variablen, Editor | erledigt | v0.3.0 | 6 h | 0 h 10 min | | [#011](011-profile-docker-zabbix.md) | Profile docker und zabbix-agent, Variablen, Editor | erledigt | v0.3.0 | 6 h | 0 h 10 min |
| [#012](012-vorlagen.md) | Vorlagen (Presets) | erledigt | v0.3.0 | 3 h | 0 h 11 min | | [#012](012-vorlagen.md) | Vorlagen (Presets) | erledigt | v0.3.0 | 3 h | 0 h 11 min |
| [#013](013-cli.md) | CLI proxdeploy (Go) | offen | v0.4.0 | 12 h | – | | [#013](013-cli.md) | CLI proxdeploy (Go) | in Arbeit | v0.4.0 | 12 h | – |
| [#014](014-verlauf.md) | Verlauf und Wiederholen | offen | v0.5.0 | 4 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 | – | | [#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 | – | | [#016](016-oidc.md) | Anmeldung per OIDC | offen | v0.5.0 | 4 h | – |