From a54c1b628554069ab88d91dd3fdb9f2f42054ca0 Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Thu, 17 Sep 2026 19:42:04 +0200 Subject: [PATCH] docs: Projektorganisation, Architekturplan und Issues pro Phase (#001) Co-Authored-By: Claude Opus 5 (1M context) --- .gitignore | 53 +++++ CHANGELOG.md | 20 ++ DEVLOG.md | 39 ++++ docs/architektur.md | 184 ++++++++++++++++++ docs/issues/001-projekt-setup.md | 31 +++ docs/issues/002-prototyp.md | 31 +++ docs/issues/003-datenmodell.md | 28 +++ docs/issues/004-agent-api.md | 28 +++ docs/issues/005-agent-skript.md | 31 +++ docs/issues/006-kunden-hostzuweisung.md | 27 +++ docs/issues/007-hosts-detailansichten.md | 25 +++ docs/issues/008-laufzeiten-rechnungen.md | 28 +++ ...9-kundenuebersicht-dashboard-jahresbahn.md | 25 +++ docs/issues/010-export.md | 22 +++ docs/issues/011-warnregeln.md | 26 +++ docs/issues/012-benachrichtigungen.md | 25 +++ docs/issues/013-authentifizierung.md | 26 +++ docs/issues/014-deployment.md | 26 +++ docs/issues/015-feinschliff-v1.md | 24 +++ docs/issues/README.md | 22 +++ 20 files changed, 721 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 DEVLOG.md create mode 100644 docs/architektur.md create mode 100644 docs/issues/001-projekt-setup.md create mode 100644 docs/issues/002-prototyp.md create mode 100644 docs/issues/003-datenmodell.md create mode 100644 docs/issues/004-agent-api.md create mode 100644 docs/issues/005-agent-skript.md create mode 100644 docs/issues/006-kunden-hostzuweisung.md create mode 100644 docs/issues/007-hosts-detailansichten.md create mode 100644 docs/issues/008-laufzeiten-rechnungen.md create mode 100644 docs/issues/009-kundenuebersicht-dashboard-jahresbahn.md create mode 100644 docs/issues/010-export.md create mode 100644 docs/issues/011-warnregeln.md create mode 100644 docs/issues/012-benachrichtigungen.md create mode 100644 docs/issues/013-authentifizierung.md create mode 100644 docs/issues/014-deployment.md create mode 100644 docs/issues/015-feinschliff-v1.md create mode 100644 docs/issues/README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6710e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +# Abhängigkeiten +node_modules/ +.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases + +# Next.js / Build +.next/ +out/ +build/ +dist/ +*.tsbuildinfo +next-env.d.ts + +# Tests +coverage/ +test-results/ +playwright-report/ + +# Umgebungsvariablen +.env +.env.* +!.env.example + +# Lokale Datenbanken / Daten +*.db +*.sqlite +*.sqlite3 +/data/ +/postgres-data/ +/uploads/ + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +*.log + +# Betriebssystem / Editor +.DS_Store +Thumbs.db +.idea/ +.vscode/* +!.vscode/extensions.json +*.swp + +# Vercel / Sonstiges +.vercel +*.pem diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5ec0f62 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +Alle nennenswerten Änderungen an ProxLedger 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 +- Projektorganisation: Devlog, Changelog, Issue-Übersicht und Issues pro Phase (#001) +- Architektur- und Umsetzungsplan in `docs/architektur.md` (#001) + +### Geändert + +### Behoben + +### Entfernt + +### Sicherheit diff --git a/DEVLOG.md b/DEVLOG.md new file mode 100644 index 0000000..75a07eb --- /dev/null +++ b/DEVLOG.md @@ -0,0 +1,39 @@ +# DEVLOG – ProxLedger + +## Zeitübersicht + +**Gesamt:** 0 h 00 min (laufende Sitzung nicht eingerechnet) + +| Issue | Zeit | +|---|---| +| #001 Projekt-Setup | 0 h 00 min | + +| Meilenstein | Zeit | +|---|---| +| v0.1.0 | 0 h 00 min | + +--- + +## 2026-09-17 · Sitzung 1 · 19:36–laufend +**Issue:** #001 Projekt-Setup +**Version:** 0.1.0-dev + +### Erledigt +- Auftrag gelesen, Rückfragen gestellt +- Umgebung geprüft: Ubuntu 26.04, Git 2.53; Node/Docker fehlten → Node 24 LTS per nvm installiert +- Repository-Rechte korrigiert (Verzeichnis gehörte root), Branch `master` → `main`, Git-Identität lokal gesetzt +- `.gitignore`, `CHANGELOG.md`, `DEVLOG.md`, Architekturplan und 15 Issues angelegt + +### Entscheidungen +- **AdminLTE 4.9.1 nur als CSS:** stabil, Bootstrap 5.3.8, kein jQuery; die JS-Plugins manipulieren das DOM und werden daher als React-Komponenten nachgebaut. +- **Host-Identität über Agent-Token statt Server-ID:** Die Server-ID ändert sich bei Hardwaretausch und soll dann eine Warnung auslösen, statt einen neuen Host zu erzeugen. +- **Rechnungen mit Positionen:** Proxmox-Sammelbestellungen und Sammelrechnungen an Kunden sollen ohne doppelte Rechnungsnummern abbildbar sein. +- **Eigener Worker-Prozess** für zeitgesteuerte Warnregeln und Benachrichtigungen, unabhängig von Seitenaufrufen. +- **Prototyp direkt im Next.js-Projekt**, damit die Komponenten weiterverwendet werden. + +### Probleme / offene Fragen +- Docker ist nicht installiert und `sudo` erfordert ein Passwort → Installation muss manuell erfolgen (benötigt ab #003). +- Offen: Rolle „readonly“ zusätzlich zu Admin? (vorläufig vorgesehen) + +### Nächster Schritt +- Next.js-Grundgerüst (#001), danach Prototyp (#002) diff --git a/docs/architektur.md b/docs/architektur.md new file mode 100644 index 0000000..907329a --- /dev/null +++ b/docs/architektur.md @@ -0,0 +1,184 @@ +# ProxLedger – Architektur- und Umsetzungsplan + +Stand: 2026-09-17 · Version 0.1.0-dev + +## 1. Überblick + +``` + Kundennetz A (NAT) Kundennetz B Betreiber +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────────┐ +│ PVE-Host │ │ PBS-Host │ │ ProxLedger (Docker / LXC) │ +│ proxledger-agent│─HTTPS─▶│ proxledger-agent│─────▶│ ┌────────┐ ┌───────────┐ │ +│ (systemd-Timer) │ Push │ (systemd-Timer) │ Push │ │ web │ │ worker │ │ +└──────────────────┘ └──────────────────┘ │ │Next.js │ │ Cron-Jobs │ │ + │ └───┬────┘ └─────┬─────┘ │ + │ └──── Postgres ┘ │ + └──────────────────────────────┘ + │ SMTP (M365) / Webhook + ▼ + E-Mail, Matrix, Zabbix, HA +``` + +- **Push-Modell:** Das Dashboard fragt nie aktiv bei Hosts an. Agents melden sich täglich per HTTPS. +- **web:** Next.js (App Router) liefert UI, Agent-API (`/api/agent/v1/*`) und `install.sh`/`proxledger-agent.sh`. +- **worker:** Derselbe Code-Stand, eigener Prozess (`node dist/worker.js`) für zeitgesteuerte Aufgaben: + Warnregeln auswerten, „keine Meldung seit 48 h“, Benachrichtigungen versenden, Zusammenfassungen. +- **PostgreSQL:** einzige Datenhaltung; PDF-Uploads auf einem Volume (`/data/uploads`), Metadaten in der DB. + +## 2. Tech-Stack + +| Bereich | Wahl | Begründung | +|---|---|---| +| Framework | Next.js (App Router), TypeScript strict | Vorgabe | +| ORM | Prisma + PostgreSQL | Vorgabe, Migrationen versioniert | +| UI | `admin-lte` 4.x **nur CSS** + Bootstrap 5.3 + eigene React-Komponenten | AdminLTE 4.9.1 ist stabil, jQuery-frei; die Vanilla-JS-Plugins (PushMenu, Treeview, CardWidget) manipulieren das DOM direkt und werden als React-Komponenten nachgebaut | +| Icons | Bootstrap Icons | AdminLTE-4-Standard | +| Schrift | Source Sans 3 über `next/font` (selbst gehostet) | kein externer Request zur Laufzeit | +| Validierung | zod (API und Server Actions) | Vorgabe | +| Auth | Auth.js (OIDC authentik + Credentials-Fallback) | ausgereift, App-Router-kompatibel | +| Passwörter/Tokens | argon2id (Passwörter), SHA-256 über 256-Bit-Zufallstoken (API-Tokens) | Token haben volle Entropie, SHA-256 reicht und ist schnell nachschlagbar | +| Scheduler | `croner` im Worker | leichtgewichtig, zeitzonenfähig | +| E-Mail | nodemailer (SMTP, STARTTLS 587, M365-tauglich) | | +| PDF | `@react-pdf/renderer` | kein Chromium im Container | +| Tests | Vitest; Integrationstests gegen Postgres (Docker) | | +| Agent | Bash, `curl`, Bordmittel; systemd-Service + Timer | Vorgabe | + +Zeitzone der Anzeige: `Europe/Berlin`, Datenhaltung in UTC. Datumsformat `dd.MM.yyyy`, Währung EUR. + +## 3. Datenmodell + +Gegenüber dem Vorschlag im Auftrag zwei bewusste Änderungen: + +1. **Host-Identität ist nicht die Server-ID.** Die Server-ID ändert sich bei Hardwaretausch/Neuinstallation – genau das soll + eine Warnung auslösen. Ein Host wird daher über seinen Agent-Token bzw. eine beim Enrollment erzeugte `agentId` + (abgeleitet aus `/etc/machine-id`) identifiziert; die Server-ID ist ein Attribut mit Historie. Meldet ein neu + registrierter Agent eine Server-ID, die bereits ein bestehender Host hatte, wird das als Neuinstallation erkannt und + zur Übernahme vorgeschlagen. +2. **Rechnungen sind eigene Entitäten mit Positionen.** Eine Proxmox-Bestellung enthält oft mehrere Keys, eine + Kundenrechnung oft mehrere Hosts. Jede Laufzeit verweist auf höchstens eine Einkaufs- und eine Verkaufsposition. + Marge = Verkauf netto − Einkauf netto der Position(en). + +### Entitäten (vereinfacht) + +``` +Customer 1─n Site +Customer 1─n Host (customerId nullable → „nicht zugeordnet“) +Site 1─n Host +Host 1─n Report +Host 1─n SubscriptionKey (Key-Historie: key, firstSeen, lastSeen) +Host 1─n ServerIdHistory +Host 1─n SubscriptionPeriod (Laufzeit: startDate, endDate, key, status: vorgeschlagen|bestätigt) +SubscriptionPeriod n─1 PurchaseInvoiceItem ─n─1 PurchaseInvoice (Proxmox) +SubscriptionPeriod n─1 SalesInvoiceItem ─n─1 SalesInvoice (Kunde) +Host 1─n AgentToken (Hash, erstellt, zuletzt benutzt, widerrufen) +EnrollmentToken (Hash, gültig bis, max. Nutzungen, optional customerId/siteId) +Alert (type, severity, hostId?, customerId?, periodId?, fingerprint, openedAt, resolvedAt, acknowledgedAt) +Notification (alertId?, channel, sentAt, status) – Deduplizierung über Alert-Fingerprint +AlertRuleSetting (key, enabled, thresholds JSON) +NotificationChannel (type: email|webhook, config JSON, enabled) +User (email, name, role: admin|readonly, passwordHash?, oidcSubject?) +AuditLog (userId?, action, entity, entityId, diff JSON, createdAt) +Tag n─m Host +Attachment (PDF: path, mime, size, sha256) – an PurchaseInvoice / SalesInvoice +``` + +**PurchaseInvoice (Proxmox):** Rechnungsnummer, Rechnungsdatum, Fälligkeitsdatum, netto, brutto, Rabatt, Zahlungsart, +bezahlt (bool), Bezahldatum, PDF. +**SalesInvoice (Kunde):** erstellt (bool), Rechnungsnummer, Rechnungsdatum, Betrag netto/brutto, vom Kunden bezahlt (bool), +Bezahldatum, PDF. +USt-Satz standardmäßig 19 %, pro Rechnung überschreibbar. Beträge als `Decimal(12,2)`. + +Das „Häkchen direkt in der Tabelle“ setzt den Status der verknüpften Rechnung. Existiert noch keine Rechnung, legt das +Häkchen eine Minimal-Rechnung an (Nummer später nachtragbar). + +## 4. Agent-API + +Basis: `/api/agent/v1`, nur JSON, strikt getrennt vom UI (eigene Route-Group, keine Session-Cookies, eigenes Rate-Limit). + +| Methode | Pfad | Auth | Zweck | +|---|---|---|---| +| POST | `/enroll` | Enrollment-Token (Bearer) | Host registrieren → liefert `hostId` + host-spezifischen API-Token (einmalig im Klartext) | +| POST | `/report` | Host-Token (Bearer) | Statusbericht; Antwort enthält `latestAgentVersion`, `serverTime` | +| GET | `/ping` | Host-Token | Verbindungstest (`proxledger-agent --test`) | +| GET | `/install.sh`, `/agent.sh` | öffentlich | Installer und Agent-Skript (Version eingebettet) | + +- zod-Schemas mit `nullable()` für alle optionalen Felder; unbekannte Felder werden ignoriert und geloggt. +- Rate-Limit: Token-Bucket im Prozess (pro IP und pro Token), z. B. 10 Anfragen/Minute; `429` mit `Retry-After`. +- Report-Verarbeitung in einer Transaktion: Report speichern → Host-Stammdaten aktualisieren → Key-/Server-ID-Historie → + Laufzeitvorschlag bei neuem `nextduedate` → betroffene Warnregeln neu auswerten. +- Nachgesendete (gepufferte) Reports tragen ihren Original-Zeitstempel (`collectedAt`) und werden idempotent über `reportId` (UUID vom Agent) angenommen. + +## 5. Agent + +- `install.sh`: prüft root/Produkt, lädt `proxledger-agent.sh` vom Dashboard, `enroll`, schreibt `/etc/proxledger/agent.conf` (600), + installiert `proxledger.service` + `proxledger.timer` (`OnCalendar=daily`, `RandomizedDelaySec=4h`, `Persistent=true`), erster Report sofort. +- Optionen: `--token`, `--url`, `--ca-cert`, `--uninstall`, `--update`, `--test`. +- Sammelt: Subscription (PVE/PBS/PMG), Hostname, FQDN, IPs, Cluster/Node, Produktversion, Kernel, Sockets, CPU-Modell, Uptime, + Anzahl Updates, Agent-Version, Zeitstempel. Fehlende Werte → `null`. JSON wird ohne `jq` erzeugt (eigene Escape-Funktion). +- Fehlschlag: 3 Versuche mit Backoff (30 s, 2 min, 8 min), danach Ablage in `/var/lib/proxledger/spool/`, beim nächsten Lauf nachsenden (max. 30 Dateien). +- Logging über `logger -t proxledger` bzw. stdout ins Journal. +- Update: nur wenn `AUTO_UPDATE=yes` in der Config oder manuell via `--update`; Prüfsumme vom Dashboard wird verifiziert. + +## 6. Warnregeln + +Regeln sind reine Funktionen `(Kontext) → AlertCandidate[]`, getrennt testbar. Der Worker gleicht Kandidaten mit offenen Alerts +ab (Fingerprint = Regel + Objekt-ID [+ Schwelle]): neue öffnen, verschwundene schließen, bestehende unverändert lassen. +Benachrichtigt wird nur beim Öffnen bzw. beim Wechsel auf eine höhere Stufe (30 → 14 → 7 Tage). + +| Regel | Standard | +|---|---| +| Subscription läuft ab | 30 / 14 / 7 Tage | +| Status ≠ active | sofort | +| Sockets lizenziert ≠ physisch | sofort | +| Keine Meldung | 48 h | +| Server-ID geändert | sofort | +| Key von mehreren Hosts gemeldet | sofort | +| Host ohne Kunde | sofort (nur Info) | +| Proxmox-Rechnung unbezahlt, Fälligkeit | ≤ 7 Tage | +| Verlängert/bezahlt, Kundenrechnung fehlt | sofort | +| Kundenrechnung unbezahlt | nach 30 Tagen | + +## 7. Sicherheit + +- UI-Routen per Middleware geschützt (ab #013). **Bis dahin nicht öffentlich betreiben.** +- Tokens: 32 Byte Zufall, Präfix `plx_e_` (Enrollment) / `plx_h_` (Host), in der DB nur SHA-256-Hash; einzeln widerrufbar. +- Audit-Log für alle schreibenden Server Actions (vor #013 mit Akteur „system“). +- Security-Header (CSP, HSTS hinter Reverse Proxy), Upload-Prüfung (nur PDF, max. 10 MB). + +## 8. Projektstruktur + +``` +proxledger/ +├─ agent/ Bash-Agent, Installer, systemd-Units +├─ deploy/ docker-compose, LXC-Installer, Beispiel-Proxy-Configs +├─ docs/ Architektur, Issues +├─ prisma/ schema.prisma, migrations, seed.ts +├─ public/ favicon.svg, Icons +├─ src/ +│ ├─ app/ +│ │ ├─ (dashboard)/ UI-Seiten (AdminLTE-Layout) +│ │ ├─ (auth)/login/ +│ │ └─ api/agent/v1/ Agent-API +│ ├─ components/ Layout, Logo, SmallBox, Card, Badge, DataTable … +│ ├─ lib/ db, auth, tokens, validation, format +│ ├─ server/ Services (reports, alerts, invoices, notifications) +│ ├─ worker/ Scheduler-Einstiegspunkt +│ └─ mock/ Beispieldaten für den Prototyp +└─ tests/ +``` + +## 9. Meilensteine + +| Version | Inhalt | Issues | +|---|---|---| +| 0.1.0 | Projekt-Setup, Prototyp, Datenmodell, Agent-API | #001–#004 | +| 0.2.0 | Agent-Skript | #005 | +| 0.3.0 | Kunden, Standorte, Hostzuweisung, Enrollment-Tokens | #006 | +| 0.4.0 | Host-Tabelle, Suche, Detailansichten | #007 | +| 0.5.0 | Laufzeiten und Rechnungen | #008 | +| 0.6.0 | Kundenübersicht, Dashboard live, Jahresbahn, Export | #009, #010 | +| 0.7.0 | Warnregeln | #011 | +| 0.8.0 | Benachrichtigungen | #012 | +| 0.9.0 | Authentifizierung, Audit-Log | #013 | +| 0.10.0 | Deployment (Docker, LXC), Doku | #014 | +| 1.0.0 | Feinschliff, Dark-Mode, Mobil, Härtung | #015 | diff --git a/docs/issues/001-projekt-setup.md b/docs/issues/001-projekt-setup.md new file mode 100644 index 0000000..84a8a9d --- /dev/null +++ b/docs/issues/001-projekt-setup.md @@ -0,0 +1,31 @@ +# #001 Projekt-Setup +**Status:** in Arbeit +**Meilenstein:** v0.1.0 +**Labels:** chore, infrastruktur +**Geschätzt:** 3 h **Tatsächlich:** – + +## Ziel +Arbeitsfähiges Repository mit Projektorganisation (Devlog, Changelog, Issues) und einem lauffähigen Next.js-Grundgerüst inklusive AdminLTE-CSS, Linting und Prisma-Grundkonfiguration. + +## Aufgaben +- [x] Git-Repository mit Branch `main`, `.gitignore` +- [x] `DEVLOG.md`, `CHANGELOG.md`, `docs/issues/` mit Übersicht +- [x] Architektur- und Umsetzungsplan (`docs/architektur.md`) +- [x] Issues pro Phase anlegen +- [ ] Next.js (App Router, TypeScript strict, `src/`) aufsetzen +- [ ] Abhängigkeiten: `admin-lte`, `bootstrap`, `bootstrap-icons`, zod +- [ ] ESLint + Prettier, `npm run lint`, `npm run typecheck` +- [ ] Version `0.1.0-dev` in `package.json`, Versionsanzeige-Helfer +- [ ] Vitest-Grundkonfiguration + +## Akzeptanzkriterien +- [ ] `npm run dev` startet ohne Fehler +- [ ] `npm run lint` und `npm run typecheck` sind grün +- [ ] Keine Remote-URL in Projektdateien + +## Abhängigkeiten +– + +## Notizen / Entscheidungen +- AdminLTE 4.9.1 (Bootstrap 5.3.8) ist stabil und jQuery-frei. Es wird **nur das CSS** eingebunden; die interaktiven Teile (Sidebar-Toggle, Treeview, Card-Widgets) werden als React-Komponenten nachgebaut, weil die AdminLTE-Plugins das DOM direkt manipulieren. +- Node 24 LTS über nvm (Benutzerinstallation). diff --git a/docs/issues/002-prototyp.md b/docs/issues/002-prototyp.md new file mode 100644 index 0000000..a82165c --- /dev/null +++ b/docs/issues/002-prototyp.md @@ -0,0 +1,31 @@ +# #002 Klickbarer Prototyp +**Status:** offen +**Meilenstein:** v0.1.0 +**Labels:** ui, prototyp +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +Klickbarer UI-Prototyp der Seiten „Dashboard“, „Kunden-Detail“ und „Host-Detail“ mit realistischen Beispieldaten und ohne Backend, als Abstimmungsgrundlage für Look & Feel. Die Komponenten werden in den späteren Phasen weiterverwendet. + +## Aufgaben +- [ ] Logo-Komponente (Standard, Sidebar-Variante, einfarbig, Favicon 32/16) + `favicon.svg`, `favicon.ico`, PNGs, `apple-touch-icon` +- [ ] Theme: Farb-Tokens (abgedunkelte Info/Erfolg), Source Sans 3 (16 px), Monospace-Klasse mit Kopier-Button +- [ ] Layout: Sidebar (250 px, einklappbar, Overlay mobil), Kopfleiste, Inhaltskopf mit Breadcrumb, Footer mit Version +- [ ] Komponenten: SmallBox, InfoBox, Card, Badge, Callout, TodoList, ProgressBar, Tabs, CopyableCode +- [ ] Beispieldaten (`src/mock/`): 4 Kunden, ~8 Hosts (PVE/PBS/PMG), Laufzeiten, Rechnungen, Alerts +- [ ] Dashboard: 4 Small Boxes, Callout „Nicht zugeordnete Hosts“, Card „Subscriptions nach Ablauf“, Card „Aufgaben“, Card „Rechnungsstatus je Kunde“ +- [ ] Kunden-Detail: Info-Boxen (Hosts, Einkauf, Verkauf, Marge), Host-Tabelle, Laufzeiten-Tabelle, Summen pro Jahr, Ansprechpartner, Notizen +- [ ] Host-Detail: Profil-Card + Tabs Übersicht, Subscription-Historie, Reports, Rechnungen, Notizen +- [ ] Warnglocke mit Dropdown, Strg+K-Suchdialog (clientseitig über Mock-Daten) +- [ ] Dark-Mode-Umschalter (Grundfunktion) + +## Akzeptanzkriterien +- [ ] Alle drei Seiten sind über Sidebar/Links erreichbar und klickbar +- [ ] Suche nach `pve1c-a6bd21fcb6` findet Host und Kunde +- [ ] Mobil (375 px) benutzbar: Sidebar als Overlay, Tabellen scrollbar +- [ ] Weiße Schrift auf Info/Erfolg erfüllt 4,5:1 + +## Abhängigkeiten +#001 + +## Notizen / Entscheidungen diff --git a/docs/issues/003-datenmodell.md b/docs/issues/003-datenmodell.md new file mode 100644 index 0000000..7bd16ae --- /dev/null +++ b/docs/issues/003-datenmodell.md @@ -0,0 +1,28 @@ +# #003 Datenmodell und Migrationen +**Status:** offen +**Meilenstein:** v0.1.0 +**Labels:** backend, datenbank +**Geschätzt:** 5 h **Tatsächlich:** – + +## Ziel +Vollständiges Prisma-Schema gemäß `docs/architektur.md` Abschnitt 3, erste Migration, Seed mit Admin-User und optionalen Demo-Daten. + +## Aufgaben +- [ ] Docker-Compose für lokale Entwicklung (nur PostgreSQL) +- [ ] Prisma-Schema: Customer, Site, Host, Tag, Report, SubscriptionKey, ServerIdHistory, SubscriptionPeriod, PurchaseInvoice(+Item), SalesInvoice(+Item), Attachment, AgentToken, EnrollmentToken, Alert, Notification, AlertRuleSetting, NotificationChannel, User, AuditLog, Setting +- [ ] Indizes für Suche (Key, Server-ID, Hostname, IP, Rechnungsnummer) +- [ ] Erste Migration +- [ ] Seed: Admin-User aus Umgebungsvariablen, Standard-Warnregeln, optional Demo-Daten (`SEED_DEMO=1`) +- [ ] DB-Client-Singleton, Test-Datenbank-Setup für Vitest + +## Akzeptanzkriterien +- [ ] `npx prisma migrate dev` läuft auf leerer DB durch +- [ ] `npx prisma db seed` legt Admin und Standard-Regeln an, idempotent +- [ ] Beträge als Decimal, Zeitstempel in UTC + +## Abhängigkeiten +#001 + +## Notizen / Entscheidungen +- Host-Identität über Agent-Token/`agentId`, nicht über Server-ID (siehe Architektur). +- Rechnungen als eigene Entitäten mit Positionen, damit Sammelbestellungen und Sammelrechnungen abbildbar sind. diff --git a/docs/issues/004-agent-api.md b/docs/issues/004-agent-api.md new file mode 100644 index 0000000..3b08a2a --- /dev/null +++ b/docs/issues/004-agent-api.md @@ -0,0 +1,28 @@ +# #004 Agent-API +**Status:** offen +**Meilenstein:** v0.1.0 +**Labels:** backend, api, sicherheit +**Geschätzt:** 6 h **Tatsächlich:** – + +## Ziel +Getrennte, abgesicherte API unter `/api/agent/v1`, über die sich Agents registrieren und Reports abliefern. + +## Aufgaben +- [ ] Token-Bibliothek: Erzeugung (Präfix `plx_e_`/`plx_h_`), SHA-256-Hash, Prüfung, Widerruf, `lastUsedAt` +- [ ] `POST /enroll`: Enrollment-Token prüfen (Ablauf, Nutzungen), Host anlegen oder Neuinstallation erkennen, Host-Token ausgeben, optionale Kunden-/Standort-Zuordnung +- [ ] `POST /report`: zod-Schema (alle Felder nullable), idempotent über `reportId`, Transaktion (Report, Stammdaten, Key-Historie, Server-ID-Historie, Laufzeitvorschlag) +- [ ] `GET /ping` +- [ ] Rate-Limiting (pro IP und Token), `429` mit `Retry-After` +- [ ] Einheitliche Fehlerantworten (JSON), kein Stacktrace nach außen +- [ ] Tests: Auth (fehlend/falsch/widerrufen/abgelaufen), Validierung, Idempotenz, Key-Wechsel, Server-ID-Wechsel, Laufzeitvorschlag, Rate-Limit + +## Akzeptanzkriterien +- [ ] Report mit ausschließlich `null`-Feldern (außer Pflicht-Metadaten) wird angenommen +- [ ] Tokens liegen nur gehasht in der DB +- [ ] UI-Session-Cookies werden von der Agent-API ignoriert +- [ ] Alle Tests grün + +## Abhängigkeiten +#003 + +## Notizen / Entscheidungen diff --git a/docs/issues/005-agent-skript.md b/docs/issues/005-agent-skript.md new file mode 100644 index 0000000..24bf6ed --- /dev/null +++ b/docs/issues/005-agent-skript.md @@ -0,0 +1,31 @@ +# #005 Agent-Skript +**Status:** offen +**Meilenstein:** v0.2.0 +**Labels:** agent +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +Schlanker Bash-Agent (nur `curl` und Proxmox-Bordmittel), der täglich per systemd-Timer seinen Status meldet, mit One-Liner-Installation. + +## Aufgaben +- [ ] Produkterkennung PVE / PBS / PMG +- [ ] Datensammlung: Subscription (key, status, level, productname, sockets, serverid, regdate, nextduedate, checktime), Hostname, FQDN, IPs, Cluster/Node, Version, Kernel, Sockets, CPU-Modell, Uptime, Updates, Agent-Version, Zeitstempel +- [ ] JSON-Erzeugung ohne `jq` inkl. Escaping, fehlende Werte als `null` +- [ ] Senden mit Retry/Backoff, Spool-Verzeichnis, Nachsenden +- [ ] TLS-Verifikation, optional eigenes CA-Zertifikat +- [ ] Logging ins Journal +- [ ] `install.sh`: `--token`, `--url`, `--ca-cert`; Config `/etc/proxledger/agent.conf` (600); Service + Timer (`RandomizedDelaySec`); erster Report sofort +- [ ] `--uninstall`, `--update`, `--test` +- [ ] Auslieferung von `install.sh`/Agent über das Dashboard +- [ ] ShellCheck sauber; Tests mit Beispielausgaben der `*subscription get`-Befehle + +## Akzeptanzkriterien +- [ ] Installation per One-Liner auf PVE 8/9 und PBS 3/4 erfolgreich +- [ ] Report scheitert nicht an fehlenden Befehlen/Feldern +- [ ] Dashboard offline → Report wird gepuffert und beim nächsten Lauf nachgesendet +- [ ] Uninstall entfernt Units, Config und Spool vollständig + +## Abhängigkeiten +#004 + +## Notizen / Entscheidungen diff --git a/docs/issues/006-kunden-hostzuweisung.md b/docs/issues/006-kunden-hostzuweisung.md new file mode 100644 index 0000000..c5fa649 --- /dev/null +++ b/docs/issues/006-kunden-hostzuweisung.md @@ -0,0 +1,27 @@ +# #006 Kunden, Standorte und Hostzuweisung +**Status:** offen +**Meilenstein:** v0.3.0 +**Labels:** ui, backend +**Geschätzt:** 6 h **Tatsächlich:** – + +## Ziel +Kunden und Standorte pflegen, neu registrierte Hosts schnell Kunden zuweisen und Enrollment-Tokens verwalten. + +## Aufgaben +- [ ] Kunden anlegen/bearbeiten/löschen (Name, Kundennummer, Ansprechpartner, E-Mail, Notizen) +- [ ] Standorte je Kunde +- [ ] Seite „Nicht zugeordnete Hosts“ mit Mehrfachauswahl und Schnellzuweisung (Kunde + Standort) +- [ ] Callout auf dem Dashboard, solange nicht zugeordnete Hosts existieren +- [ ] Enrollment-Tokens: erzeugen (Ablauf, max. Nutzungen, optional Kunde/Standort), anzeigen (einmalig), widerrufen; Install-One-Liner zum Kopieren +- [ ] Host-Tokens widerrufen +- [ ] Audit-Log-Einträge für alle Änderungen + +## Akzeptanzkriterien +- [ ] Mehrere Hosts lassen sich in einem Schritt zuweisen +- [ ] Mit kundengebundenem Enrollment-Token registrierte Hosts sind sofort zugeordnet +- [ ] Widerrufener Token wird von der Agent-API abgewiesen + +## Abhängigkeiten +#002, #004 + +## Notizen / Entscheidungen diff --git a/docs/issues/007-hosts-detailansichten.md b/docs/issues/007-hosts-detailansichten.md new file mode 100644 index 0000000..33806b2 --- /dev/null +++ b/docs/issues/007-hosts-detailansichten.md @@ -0,0 +1,25 @@ +# #007 Host-Tabelle, Suche und Detailansichten +**Status:** offen +**Meilenstein:** v0.4.0 +**Labels:** ui +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +Hosts finden, filtern und vollständig einsehen. + +## Aufgaben +- [ ] Host-Tabelle (serverseitig): Filter Kunde, Status, Produkt, Ablauf, Rechnungsstatus; Sortierung; Spaltenauswahl; Paginierung; CSV-Export +- [ ] Suche nach Key, Server-ID, Hostname, IP, Proxmox-Rechnungsnummer +- [ ] Globale Suche in der Kopfleiste und Sidebar, `Strg+K` +- [ ] Host-Detail: Profil-Card, Tabs Übersicht, Subscription-Historie, Reports, Rechnungen, Notizen; Tags +- [ ] Kopier-Buttons für Key, Server-ID, Rechnungsnummer +- [ ] Badge „Keine Meldung“ + +## Akzeptanzkriterien +- [ ] Eingabe `pve1c-a6bd21fcb6` liefert direkt Host und Kunde +- [ ] Filter bleiben in der URL erhalten (teilbar, Zurück-Button funktioniert) + +## Abhängigkeiten +#006 + +## Notizen / Entscheidungen diff --git a/docs/issues/008-laufzeiten-rechnungen.md b/docs/issues/008-laufzeiten-rechnungen.md new file mode 100644 index 0000000..ac816ff --- /dev/null +++ b/docs/issues/008-laufzeiten-rechnungen.md @@ -0,0 +1,28 @@ +# #008 Laufzeiten und Rechnungen +**Status:** offen +**Meilenstein:** v0.5.0 +**Labels:** ui, backend, buchhaltung +**Geschätzt:** 10 h **Tatsächlich:** – + +## Ziel +Lizenzjahre mit Proxmox-Einkaufsrechnung und Kundenrechnung erfassen und den Status schnell pflegen. + +## Aufgaben +- [ ] Laufzeitvorschlag bei neuem `nextduedate` bestätigen/verwerfen +- [ ] Laufzeit manuell anlegen/bearbeiten +- [ ] Proxmox-Rechnung erfassen (auch Sammelrechnung über mehrere Laufzeiten), PDF-Upload +- [ ] Kundenrechnung erfassen (auch Sammelrechnung), PDF-Upload +- [ ] Marge pro Laufzeit, Kunde und Jahr berechnen +- [ ] Rechnungsübersicht: alle Laufzeiten, Umschalter „Proxmox bezahlt“ / „Kundenrechnung erstellt“ direkt in der Zeile, Filter Offen/Erledigt/Alle, Kunde, Zeitraum +- [ ] Sidebar-Badge offene Rechnungspunkte +- [ ] Aufgaben-Card auf dem Dashboard mit echten Aktionen + +## Akzeptanzkriterien +- [ ] Umschalten in der Tabelle wirkt sofort und wird im Audit-Log protokolliert +- [ ] Summen Einkauf/Verkauf/Marge stimmen mit Einzelwerten überein (Tests) +- [ ] Nur PDF bis 10 MB wird angenommen + +## Abhängigkeiten +#007 + +## Notizen / Entscheidungen diff --git a/docs/issues/009-kundenuebersicht-dashboard-jahresbahn.md b/docs/issues/009-kundenuebersicht-dashboard-jahresbahn.md new file mode 100644 index 0000000..0554304 --- /dev/null +++ b/docs/issues/009-kundenuebersicht-dashboard-jahresbahn.md @@ -0,0 +1,25 @@ +# #009 Kundenübersicht, Dashboard und Jahresbahn +**Status:** offen +**Meilenstein:** v0.6.0 +**Labels:** ui +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +Überblick über Kunden, Kennzahlen und anstehende Abläufe mit Echtdaten. + +## Aufgaben +- [ ] Kundenübersicht: Anzahl Hosts, aktive Subscriptions, nächster Ablauf, offene Warnungen, Rechnungs-Ampel +- [ ] Kunden-Detail mit Echtdaten (Info-Boxen, Hosts, Laufzeiten, Summen pro Jahr) +- [ ] Dashboard mit Echtdaten: Small Boxes (inkl. „Mehr Infos“-Links auf gefilterte Listen), Kacheln ohne Subscription, ohne Meldung, ohne Kunde, offene Proxmox-Rechnungen, fehlende Kundenrechnungen +- [ ] Card „Rechnungsstatus je Kunde“ +- [ ] Ablauf-Kalender: nächste 90 Tage +- [ ] Jahresbahn: Timeline der nächsten 12 Monate, „Heute“-Linie, gruppiert nach Kunde + +## Akzeptanzkriterien +- [ ] Kennzahlen stimmen mit den gefilterten Listen überein +- [ ] Jahresbahn mobil horizontal scrollbar + +## Abhängigkeiten +#008 + +## Notizen / Entscheidungen diff --git a/docs/issues/010-export.md b/docs/issues/010-export.md new file mode 100644 index 0000000..af7c03b --- /dev/null +++ b/docs/issues/010-export.md @@ -0,0 +1,22 @@ +# #010 Export CSV und PDF +**Status:** offen +**Meilenstein:** v0.6.0 +**Labels:** export +**Geschätzt:** 5 h **Tatsächlich:** – + +## Ziel +Daten für Kundenunterlagen und Buchhaltung exportieren. + +## Aufgaben +- [ ] CSV (UTF-8 mit BOM, Semikolon, deutsches Zahlenformat): Host-Liste, Kundenübersicht, Rechnungsliste pro Jahr +- [ ] PDF mit einfarbigem Logo: Host-Liste, Kundenübersicht (Anlage für einen Kunden), Rechnungsliste pro Jahr mit Summen +- [ ] Export berücksichtigt aktive Filter + +## Akzeptanzkriterien +- [ ] CSV öffnet sich in Excel ohne Umlautfehler +- [ ] PDF-Summen entsprechen der Rechnungsübersicht + +## Abhängigkeiten +#009 + +## Notizen / Entscheidungen diff --git a/docs/issues/011-warnregeln.md b/docs/issues/011-warnregeln.md new file mode 100644 index 0000000..b8caaaf --- /dev/null +++ b/docs/issues/011-warnregeln.md @@ -0,0 +1,26 @@ +# #011 Warnregeln +**Status:** offen +**Meilenstein:** v0.7.0 +**Labels:** backend, alerts +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +Konfigurierbare Warnregeln, die Alerts öffnen und automatisch schließen. + +## Aufgaben +- [ ] Regel-Engine: reine Funktionen, Fingerprint, Abgleich offen/neu/erledigt +- [ ] Regeln: Ablauf 30/14/7, Status ≠ active, Sockets-Abweichung, keine Meldung 48 h, Server-ID geändert, Key mehrfach, Host ohne Kunde, Proxmox-Rechnung fällig, Kundenrechnung fehlt, Kundenrechnung unbezahlt nach X Tagen +- [ ] Worker-Prozess mit Scheduler (stündlich) + Auswertung nach jedem Report +- [ ] Einstellungsseite: Regeln aktivieren, Schwellwerte ändern +- [ ] Warnglocke und Alert-Liste (offen/erledigt, quittieren) +- [ ] Tests für jede Regel inkl. Grenzfälle + +## Akzeptanzkriterien +- [ ] Kein doppelter offener Alert für denselben Sachverhalt +- [ ] Alerts schließen sich automatisch, wenn die Ursache behoben ist +- [ ] Alle Regel-Tests grün + +## Abhängigkeiten +#008 + +## Notizen / Entscheidungen diff --git a/docs/issues/012-benachrichtigungen.md b/docs/issues/012-benachrichtigungen.md new file mode 100644 index 0000000..6522d76 --- /dev/null +++ b/docs/issues/012-benachrichtigungen.md @@ -0,0 +1,25 @@ +# #012 Benachrichtigungen +**Status:** offen +**Meilenstein:** v0.8.0 +**Labels:** backend, alerts +**Geschätzt:** 6 h **Tatsächlich:** – + +## Ziel +Über neue Alerts per E-Mail und Webhook informieren, plus regelmäßige Zusammenfassung. + +## Aufgaben +- [ ] SMTP (STARTTLS, M365/Exchange Online getestet), HTML-Mail mit Logo +- [ ] Generischer Webhook (JSON, optional HMAC-Signatur, eigene Header) +- [ ] Deduplizierung: nur bei neuem Alert oder Eskalation +- [ ] Tägliche/wöchentliche Zusammenfassung +- [ ] Einstellungsseite mit „Test senden“ +- [ ] Wiederholung bei Versandfehler, Versandprotokoll + +## Akzeptanzkriterien +- [ ] Testmail über Exchange Online kommt an +- [ ] Derselbe offene Alert erzeugt keine zweite Benachrichtigung + +## Abhängigkeiten +#011 + +## Notizen / Entscheidungen diff --git a/docs/issues/013-authentifizierung.md b/docs/issues/013-authentifizierung.md new file mode 100644 index 0000000..a3c3cb4 --- /dev/null +++ b/docs/issues/013-authentifizierung.md @@ -0,0 +1,26 @@ +# #013 Authentifizierung und Audit-Log +**Status:** offen +**Meilenstein:** v0.9.0 +**Labels:** sicherheit +**Geschätzt:** 6 h **Tatsächlich:** – + +## Ziel +Zugriff auf das Dashboard absichern und Änderungen nachvollziehbar machen. + +## Aufgaben +- [ ] Auth.js: OIDC (authentik), lokaler Admin als Fallback (argon2id) +- [ ] Middleware schützt alle UI-Routen, nicht die Agent-API +- [ ] Login-Seite im AdminLTE-Stil mit Logo +- [ ] Rollen admin / readonly +- [ ] Audit-Log-Ansicht mit Filter +- [ ] Login-Rate-Limit, Security-Header + +## Akzeptanzkriterien +- [ ] Ohne Login ist keine UI-Seite erreichbar +- [ ] Login über authentik funktioniert; lokaler Admin auch bei ausgefallenem OIDC +- [ ] readonly-Benutzer kann nichts ändern + +## Abhängigkeiten +#006 + +## Notizen / Entscheidungen diff --git a/docs/issues/014-deployment.md b/docs/issues/014-deployment.md new file mode 100644 index 0000000..727a9a7 --- /dev/null +++ b/docs/issues/014-deployment.md @@ -0,0 +1,26 @@ +# #014 Deployment und Dokumentation +**Status:** offen +**Meilenstein:** v0.10.0 +**Labels:** deployment, docs +**Geschätzt:** 8 h **Tatsächlich:** – + +## Ziel +ProxLedger einfach per Docker Compose oder als LXC-Container auf Proxmox betreiben. + +## Aufgaben +- [ ] Dockerfile (Multi-Stage, Standalone-Output, Non-root) +- [ ] `docker-compose.yml` (web, worker, postgres), `.env.example` +- [ ] Migrationen beim Start, Healthcheck +- [ ] LXC-Installer im Stil der Community-Scripts (Debian, Ressourcenabfrage, systemd-Dienste) +- [ ] Reverse-Proxy-Beispiele (Caddy, nginx, Traefik) +- [ ] README (Deutsch): Dashboard installieren → Enrollment-Token → Agent ausrollen +- [ ] Backup-/Restore-Anleitung für die Datenbank und Uploads + +## Akzeptanzkriterien +- [ ] `docker compose up -d` auf frischem System ergibt lauffähiges Dashboard +- [ ] LXC-Installer auf PVE 9 erfolgreich + +## Abhängigkeiten +#013 + +## Notizen / Entscheidungen diff --git a/docs/issues/015-feinschliff-v1.md b/docs/issues/015-feinschliff-v1.md new file mode 100644 index 0000000..bf309aa --- /dev/null +++ b/docs/issues/015-feinschliff-v1.md @@ -0,0 +1,24 @@ +# #015 Feinschliff für 1.0 +**Status:** offen +**Meilenstein:** v1.0.0 +**Labels:** ui, sicherheit +**Geschätzt:** 6 h **Tatsächlich:** – + +## Ziel +Produktionsreife: Dark-Mode, Mobilansicht, Barrierefreiheit und Sicherheitsprüfung. + +## Aufgaben +- [ ] Dark-Mode vollständig (alle Seiten, PDF bleibt hell) +- [ ] Mobil: Tabellen als Karten, Touch-Ziele ≥ 44 px +- [ ] Kontrast- und Tastaturprüfung +- [ ] Sicherheits-Review (Abhängigkeiten, Header, Uploads, Tokens) +- [ ] Performance-Check mit 200 Hosts / 5 Jahren Reports + +## Akzeptanzkriterien +- [ ] Alle Seiten in Hell und Dunkel lesbar +- [ ] Keine bekannten kritischen Schwachstellen in Abhängigkeiten + +## Abhängigkeiten +#014 + +## Notizen / Entscheidungen diff --git a/docs/issues/README.md b/docs/issues/README.md new file mode 100644 index 0000000..c4104c4 --- /dev/null +++ b/docs/issues/README.md @@ -0,0 +1,22 @@ +# 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 | in Arbeit | v0.1.0 | 3 h | – | +| [#002](002-prototyp.md) | Klickbarer Prototyp | offen | v0.1.0 | 8 h | – | +| [#003](003-datenmodell.md) | Datenmodell und Migrationen | offen | v0.1.0 | 5 h | – | +| [#004](004-agent-api.md) | Agent-API | offen | v0.1.0 | 6 h | – | +| [#005](005-agent-skript.md) | Agent-Skript | offen | v0.2.0 | 8 h | – | +| [#006](006-kunden-hostzuweisung.md) | Kunden, Standorte und Hostzuweisung | offen | v0.3.0 | 6 h | – | +| [#007](007-hosts-detailansichten.md) | Host-Tabelle, Suche und Detailansichten | offen | v0.4.0 | 8 h | – | +| [#008](008-laufzeiten-rechnungen.md) | Laufzeiten und Rechnungen | offen | v0.5.0 | 10 h | – | +| [#009](009-kundenuebersicht-dashboard-jahresbahn.md) | Kundenübersicht, Dashboard und Jahresbahn | offen | v0.6.0 | 8 h | – | +| [#010](010-export.md) | Export CSV und PDF | offen | v0.6.0 | 5 h | – | +| [#011](011-warnregeln.md) | Warnregeln | offen | v0.7.0 | 8 h | – | +| [#012](012-benachrichtigungen.md) | Benachrichtigungen | offen | v0.8.0 | 6 h | – | +| [#013](013-authentifizierung.md) | Authentifizierung und Audit-Log | offen | v0.9.0 | 6 h | – | +| [#014](014-deployment.md) | Deployment und Dokumentation | offen | v0.10.0 | 8 h | – | +| [#015](015-feinschliff-v1.md) | Feinschliff für 1.0 | offen | v1.0.0 | 6 h | – | +| | **Summe** | | | **101 h** | **–** |