Files
LaunchPad/docs/ROADMAP.md

275 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap
Geplante Reihenfolge der nächsten Commits, aufbauend auf dem lauffähigen
Grundgerüst aus Commit 1.
## ✅ Commit 2 — Geräte- & Dienste-API (erledigt)
- REST-Endpunkte (Fastify) für `GET/POST/PATCH/DELETE` auf `devices` und `services`
- Zod-Validierung der Request-Bodies (`packages/shared/src/schemas.ts`)
- Repository-Layer über Drizzle (`apps/backend/src/db/repositories`)
## ✅ Commit 3 — Suche im Frontend (erledigt)
- Anbindung von `rankServices` aus `packages/shared` an echte Backend-Daten
- TanStack Query für Datenhaltung (`apps/frontend/src/hooks/useServices.ts`)
- Tastatur-Navigation (Pfeiltasten wählen, Enter öffnet Dienst in neuem Tab, Escape leert Suche)
- Neue UI-Komponente `ResultsList` in `packages/ui`
> TanStack Router wird bewusst erst mit dem Adminbereich (Commit 6) eingeführt,
> da es vorher keine zweite Route gibt, die er sinnvoll verwalten könnte.
## ✅ Commit 4 — Kategorien & Favoriten (erledigt)
- Kategorien-API: Erstellen, Umbenennen, Löschen, Bulk-Reorder (`PATCH /api/categories/reorder`)
- Löschen einer Kategorie setzt `category` bei betroffenen Diensten auf `null`,
löscht die Dienste aber nicht
- Favoriten-Toggle direkt in der Trefferliste des Frontends (Stern anklicken,
per `useMutation` + Cache-Invalidierung)
> Die eigentliche Kategorien-*Verwaltungsoberfläche* (Erstellen/Umbenennen/
> Drag & Drop in der UI) wandert in Commit 6 (Adminbereich) die Startseite
> bleibt bewusst die minimalistische Suche, kein Verwaltungs-UI dort.
## ✅ Commit 5 — Scanner (erledigt)
- `apps/backend/src/scanner/`: DNS-Kandidaten-Auflösung, TCP-Portscan (80, 443 +
typische Ports), HTTP-Titel-/Favicon-Extraktion, Softwareerkennung per
Signatur-Liste, FritzBox-TR-064-Client (inkl. selbst implementierter
HTTP-Digest-Authentifizierung)
- `POST /api/scan/devices/:id` und `POST /api/scan/fritzbox` ausschließlich
manuell auslösbar, kein automatischer/zeitgesteuerter Scan
- `upsertDeviceFromScan` / `upsertServiceFromScan` in den Repositories:
garantiert, dass Benutzerfelder (displayName, category, favorite, order,
alias, icon) bei erneuten Scans nie überschrieben werden End-to-End getestet
(Service manuell umbenannt/kategorisiert/favorisiert, erneut gescannt,
Werte blieben erhalten)
> Alle Module wurden gegen echte, lokal gestartete Test-Server verifiziert
> (Port-Erkennung, Titel/Favicon-Parsing, Softwareerkennung, kompletter
> FritzBox-SOAP-/Digest-Auth-Ablauf inkl. Fehlerfall bei falschem Passwort).
> Ein Test gegen eine echte FritzBox war in dieser Umgebung nicht möglich.
## ✅ Commit 6 — Adminbereich (erledigt)
- TanStack Router (code-basiert): `/` (Startseite) + `/admin/*`
- Menüpunkte wie spezifiziert: Dashboard, Geräte, Dienste, Scanner, Kategorien,
Plugins, Einstellungen, Logs
- Geräte-Seite: anlegen, löschen, **„Jetzt scannen"-Button** pro Gerät
- Dienste-Seite: Inline-Bearbeitung von Name/Kategorie/Alias/Reihenfolge, Favoriten-Toggle
- Kategorien-Seite: anlegen, umbenennen, löschen, **natives Drag & Drop** (kein
zusätzliches Package nötig)
- Scanner-Seite: FritzBox-Trigger + Sammel-Scan aller Geräte
- Logs-Seite: Scan-Historie (neue `scan_logs`-Tabelle, jeder Scan-Versuch wird protokolliert)
- Einstellungen: Live-Backend-Status + Theme-Umschalter
- Plugins: ehrlicher Hinweis, dass das Plugin-System noch nicht existiert
(statt einer vorgetäuschten Funktion)
> Verifiziert per Docker-Build-Simulation (Frontend + Backend inkl.
> `pnpm deploy --prod`) und Backend-Smoke-Test aller von den Admin-Seiten
> verwendeten Endpunkte. Die UI selbst konnte in dieser Umgebung nicht in
> einem echten Browser durchgeklickt werden (kein Browser-Tool verfügbar)
> Verifikation stützt sich auf erfolgreichen TypeScript-/Vite-Build und
> Codeprüfung.
## ✅ Commit 7 — PWA (erledigt)
- `vite-plugin-pwa` mit generiertem Manifest (`manifest.webmanifest`) und
Service Worker (Workbox, `generateSW`-Modus)
- Echte Icons (192/512, jeweils normal + maskable, `apple-touch-icon.png`,
`favicon.svg`) unter `apps/frontend/public/`
- App-Shell wird precached; `/api/*` läuft über `NetworkFirst` mit 3s-Timeout
und Cache-Fallback Suche funktioniert damit auch offline mit dem zuletzt
geladenen Datenstand
- `nginx.conf`: `sw.js`/`manifest.webmanifest` explizit von der 7-Tage-Cache-Regel
ausgenommen (sonst kommen Updates bei installierten Nutzern nie an), korrekter
MIME-Type für das Manifest gesetzt
> Verifiziert: Manifest gegen Installierbarkeits-Anforderungen geprüft (512er-Icon,
> maskable Icon, alle Pflichtfelder vorhanden), alle Assets über einen echten
> HTTP-Server abgerufen (200 OK, korrekte Content-Types), generierter Service-Worker-
> Code inspiziert (Precache-Liste + NetworkFirst-Route bestätigt), vollständige
> Docker-Build-Simulation durchlaufen. Die tatsächliche "Zum Homescreen hinzufügen"-
> Installation konnte mangels Browser in dieser Umgebung nicht getestet werden.
## ✅ Commit 8 — Plugin-System (erledigt)
- Plugins liegen als Ordner unter `apps/backend/plugins/*`, jeweils mit einer
`index.js` (reines ESM, kein Build-Schritt). Werden beim Backend-Start
geladen (`apps/backend/src/plugins/loader.ts`) und per Docker-Volume
eingebunden neue Plugins brauchen nur einen Container-Neustart, kein
Image-Rebuild
- Plugin-Vertrag (`apps/backend/src/plugins/types.ts`): `setup(ctx)` zum
Registrieren zusätzlicher Softwareerkennung (inkl. Icon), `importDevices()`
für eigene Geräte-Importquellen
- Zwei funktionierende Beispiel-Plugins: `example-signatures` (Homebridge,
Uptime Kuma) und `static-import` (Geräte aus lokaler `devices.json`)
- `GET /api/plugins`, `POST /api/plugins/:name/import` Import läuft wie
Scans ausschließlich manuell per Knopfdruck
- Frontend-Plugins-Seite zeigt echte geladene Plugins mit Capabilities und
Import-Button (ersetzt den ehrlichen Platzhalter aus Commit 6)
- Von neuen Plugins erkannte Software liefert ein Icon, das wie `category`
seit Commit 5 nur beim erstmaligen Anlegen eines Dienstes als Startwert
übernommen wird, nie nachträglich überschrieben
> Verifiziert: beide Plugins laden nachweislich beim Start; ein echter Scan
> gegen einen Test-Server mit "Homebridge" im Response-Body wurde über die
> Plugin-Signatur erkannt, inkl. korrekt übernommenem Icon; Geräte-Import per
> Plugin getestet (`source: "plugin"`); Fehlerfälle (unbekanntes Plugin → 404,
> Plugin ohne Import-Fähigkeit → 400) geprüft; Docker-Build-Simulation
> bestanden, dabei auch verifiziert, dass ein fehlendes Plugin-Verzeichnis
> nicht zum Absturz führt, sondern nur zu einer leeren Liste.
> **Bewusst nicht umgesetzt:** eigene Admin-Routen/Menüpunkte pro Plugin
> (alle Plugins erscheinen gesammelt auf einer Seite) und Sandboxing
> (Plugin-Code läuft mit vollem Zugriff im Backend-Prozess nur Plugins aus
> vertrauenswürdiger Quelle einbinden, siehe `apps/backend/plugins/README.md`).
Damit ist die komplette in der ursprünglichen Projektübergabe beschriebene
Funktionalität umgesetzt.
## Bugfixes aus dem ersten Praxistest (nach Commit 8)
Basierend auf echtem Testen gegen ein reales Homelab (FritzBox + gescannte
Geräte):
- **Neues Feld `visible` auf Diensten.** Scan-Treffer mit Fehlerantworten
(404, 400, 302 als Titel) oder generischen Ladebildschirm-Titeln
("Loading...", der Scanner führt kein JavaScript aus) werden beim
erstmaligen Anlegen automatisch als `visible: false` markiert sie
erscheinen nicht mehr in der Suche, bleiben aber unter Admin -> Dienste
sichtbar, umschaltbar (👁️/🙈) und löschbar. Bestehende Datenbanken werden
beim Start automatisch migriert (`ALTER TABLE ... ADD COLUMN`), keine
Daten gehen verloren.
- **Hostname/URL/HTTPS sind jetzt im Adminbereich editierbar** (Dienste ->
Bearbeiten) und werden ab sofort bei einem erneuten Scan eines bereits
bekannten Dienstes **nicht mehr überschrieben** (vorher wurden diese Felder
bei jedem Scan aufgefrischt). Nur `favicon`/`description` werden weiterhin
aktualisiert. Achtung: Wird dabei der **Port** geändert, entsteht beim
nächsten Scan ein neuer Eintrag für den ursprünglichen Port, da die
Zuordnung über `deviceId + port` läuft.
- **Suchergebnisliste erscheint nur noch bei aktiver Eingabe** vorher war
sie auch bei leerem Suchfeld dauerhaft aufgeklappt.
- **Port wird jetzt überall mit angezeigt** (`hostname:port` statt nur
`hostname`), in der Suche wie im Adminbereich.
- **Admin-Sidebar ist jetzt echt fixiert** (`fixed` statt `static`) vorher
scrollte "Zurück zur Suche" bei langem Seiteninhalt aus dem Sichtfeld.
## Weitere Fixes (zweite Testrunde)
- **Reset-Button** unter Admin -> Einstellungen -> Gefahrenzone: löscht alle
Geräte und (per Cascade) alle Dienste unwiderruflich. Doppelte Bestätigung
im Frontend (`window.confirm`) plus eine Pflicht-Bestätigung auf API-Ebene
(`POST /api/reset` verlangt `{"confirm": true}`, sonst `400`). Kategorien
und Logs bleiben erhalten.
- **Port und Protokoll (http/https) als eigene Spalten** in der
Dienste-Tabelle im Adminbereich, nicht mehr nur implizit in der URL.
- **Favoriten-Leiste über der Suchleiste** auf der Startseite immer
sichtbar, unabhängig vom Suchfeld, sortiert nach der einstellbaren
Reihenfolge.
- **Dienste per Drag & Drop sortierbar** im Adminbereich (`PATCH
/api/services/reorder`), bestimmt sowohl die Reihenfolge in der
Favoriten-Leiste als auch bei gleichrangigen Suchtreffern.
- **Healthcheck durchgängig in der Admin-Sidebar sichtbar** (vorher nur auf
der Startseite und versteckt unter Einstellungen).
- **Kategorien-Synchronisierung:** Die `categories`-Tabelle war leer, obwohl
Dienste bereits Kategorien-Text trugen (z. B. aus der automatischen
Softwareerkennung) `services.category` ist reiner Freitext, kein
Fremdschlüssel. Jetzt: (1) beim Start werden alle bereits auf Diensten
vorhandenen Kategorienamen automatisch in die `categories`-Tabelle
nachgetragen, (2) jeder Scan legt neu erkannte Kategorien automatisch an,
(3) Umbenennen einer Kategorie im Adminbereich aktualisiert automatisch
alle Dienste mit dem alten Namen. Einschränkung: manuell per API angelegte
Dienste (nicht über einen Scan) lösen diesen Sync aktuell nicht aus.
## HTTPS im lokalen Netz
- Frontend-Container liefert jetzt zusätzlich zu HTTP (Port 8080) auch HTTPS
auf Port 8443 aus, kein erzwungener Redirect.
- Entrypoint-Skript (`apps/frontend/docker-entrypoint.sh`) erzeugt beim
Containerstart automatisch ein selbstsigniertes Zertifikat für die in
`.env` hinterlegte `LAUNCHPAD_HOST` (IP-SAN bei IP-Adressen, DNS-SAN bei
Hostnamen) übernimmt nichts, falls unter `/etc/nginx/certs/` bereits
eigene Zertifikate eingebunden sind (siehe README, z. B. per mkcert für
eine Variante ohne Browser-Warnung).
- `nginx.conf` in HTTP- und HTTPS-Serverblock aufgeteilt, gemeinsame
Location-Regeln in `nginx-locations.conf` ausgelagert (kein doppelt
gepflegter Proxy-/Cache-Code).
> Verifiziert: Zertifikatserzeugung für IP-, Hostname- und Fallback-Fall
> getestet, komplette nginx-Konfiguration mit einem echten nginx-Binary
> validiert (`nginx -t` erfolgreich), echter TLS-Handshake gegen den
> laufenden Server durchgeführt und geprüft, dass das ausgelieferte
> Zertifikat die korrekte IP als Subject Alternative Name trägt.
## HTTPS-Revision: eigene lokale Root-CA statt DuckDNS
Nutzer-Feedback: "Will nix externes, soll auch nur lokal laufen" die
DuckDNS/Let's-Encrypt-Lösung wurde daher wieder entfernt und durch eine
komplett offline funktionierende Variante ersetzt.
- `apps/frontend/docker-entrypoint.sh` erzeugt beim ersten Containerstart
eine eigene Root-CA (`LaunchPad Local CA`, `CA:TRUE`, 10 Jahre gültig) und
signiert damit ein Server-Zertifikat (`CA:FALSE`, korrekte SAN je nach
`LAUNCHPAD_HOST`) keinerlei externe Dienste beteiligt
- CA + Server-Zertifikat liegen im neuen Docker-Volume `launchpad-certs`
(statt im Container-Dateisystem) bleiben dadurch über Neustarts und
`--build` stabil. Ändert sich nur `LAUNCHPAD_HOST`, wird ausschließlich das
Server-Zertifikat neu ausgestellt, die CA (und damit bereits erteiltes
Gerätevertrauen) bleibt unangetastet
- Root-CA wird unter `http://<host>:8080/ca.crt` zum Download bereitgestellt
(`nginx-locations.conf`, korrekter MIME-Type `application/x-x509-ca-cert`
löst auf Android/iOS automatisch den nativen "Zertifikat installieren"-Dialog
aus) einziger verbleibender manueller Schritt ist der einmalige Import
pro Gerät, dafür gibt es ohne externe CA keine Alternative
- DuckDNS/`acme`-Service und zugehörige `.env`-Variablen vollständig entfernt
> Verifiziert: CA- und Leaf-Zertifikat-Erzeugung lokal mit echtem `openssl`
> durchgespielt (Zertifikatskette validiert erfolgreich gegen die CA,
> `CA:FALSE`/`CA:TRUE` korrekt gesetzt, SAN korrekt), Idempotenz geprüft
> (zweiter Lauf mit gleichem Host verändert nichts, geänderter Host erzeugt
> nur ein neues Server-Zertifikat, CA bleibt stabil), kompletter End-to-End-
> Test mit echtem nginx: `/ca.crt` per HTTP heruntergeladen und **damit ohne
> `-k`-Flag** eine echte HTTPS-Verbindung erfolgreich validiert simuliert
> exakt das Verhalten eines Geräts nach CA-Import.
## Dritte Feature-Runde: Lesezeichen, Import/Export, Favoriten im Frontend
- **Lesezeichen als eigene Entität** (neue Tabelle, eigenes Repository,
eigene Routen unter `/api/bookmarks`) nicht an ein Gerät gebunden, im
Unterschied zu Diensten. Titel + Favicon werden beim Anlegen automatisch
geladen (Wiederverwendung der Scanner-HTTP-Logik). Erscheinen zusammen mit
Diensten in der Suche (generisches `rankServices<T extends Rankable>` in
`packages/shared`), aber als eigene Favoriten-Gruppe auf der Startseite.
- **Import/Export für Dienste**: CSV, XLSX (echtes Excel, via `xlsx`-Paket)
und JSON, beide Richtungen. Import legt ausschließlich neue Dienste an
(Abgleich über Gerät+Port), bestehende werden nie überschrieben oder
verdoppelt; fehlende Geräte werden bei Bedarf automatisch angelegt.
- **Scan-Ergebnis zeigt jetzt die tatsächlichen Portnummern**, nicht nur
deren Anzahl (`ports: number[]` in der API-Antwort, Anzeige in der
Geräte-Tabelle).
- **Favoriten direkt im Frontend per Drag & Drop sortierbar** (nicht mehr
nur im Adminbereich), getrennte Gruppen für Dienste und Lesezeichen.
- **Favicon-Kontrast-Fix**: neue `Favicon`-Komponente mit immer hellem
Hintergrund, damit dunkle/schwarze Favicons nicht mit dem Dark-Mode-
Hintergrund verschmelzen.
- **Kategorie-Dropdown** im Bearbeiten-Formular (Dienste + Lesezeichen)
mit bestehenden Kategorien plus "+ Neue Kategorie …"-Option, statt freiem
Textfeld.
- **Sortierbare Spaltenköpfe** in der Dienste-Tabelle (Name, Kategorie,
Alias, Port, Protokoll). Bei aktiver Spaltensortierung ist Drag & Drop
vorübergehend deaktiviert (macht in dem Moment keinen Sinn), ein Klick auf
"zurück zur manuellen Reihenfolge" stellt den Drag-&-Drop-Modus wieder her.
> Verifiziert (Backend, alles per echtem HTTP-Roundtrip getestet): Lesezeichen
> anlegen mit automatischem Titel-/Favicon-Abruf gegen einen echten
> Testserver, automatisches Anlegen der Kategorie; CSV-, XLSX- und
> JSON-Export erzeugt (XLSX als `file`-Befehl gegengeprüft: "Microsoft Excel
> 2007+"); Import in allen drei Formaten getestet, insbesondere der
> kritische Fall "bestehender Dienst bleibt unverändert, neuer wird
> angelegt, keine Duplikate"; Bookmark- und Service-Reorder-Endpunkte
> getestet. Frontend: vollständiger `pnpm build` (inkl. `tsc --noEmit`)
> erfolgreich die eigentliche UI-Interaktion (Drag & Drop, Dropdown-
> Verhalten) konnte mangels Browser in dieser Umgebung nicht geklickt
> werden, nur durch Code-Review abgesichert.