Files
LaunchPad/docs/ROADMAP.md

19 KiB
Raw Permalink Blame History

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.

Vierte Feature-Runde: Bugfixes, Lesezeichen-Ausbau, Admin-Überarbeitung

Bugfixes:

  • Dark-Mode wird jetzt in main.tsx sofort beim Start angewendet (vorher nur wenn eine Seite useTheme() aufrief) behebt hellen Start bei Direktlink auf /admin/...
  • color-scheme-CSS-Property gesetzt native <select>-Dropdowns folgen jetzt automatisch dem Theme (vorher weiße Schrift auf weißem Grund im Dark Mode möglich)
  • Suche findet jetzt auch Teiltreffer im Hostnamen (z. B. "47" findet "192.168.1.47"), zusätzliche Ranking-Stufe in rankService
  • packages/ui hatte keine DOM-Typen in der TS-Konfiguration (seit Commit 6) navigator.clipboard für den neuen Copy-Button hat das aufgedeckt, jetzt behoben

Neue Backend-Entitäten:

  • Kategorie-Farbe (color-Spalte, Migration für Bestandsinstallationen)
  • "Zuletzt besucht" (recent_visits-Tabelle, per Einstellung konfigurierbare Anzahl)
  • Key-Value-Einstellungen (app_settings-Tabelle)
  • "Später lesen" (read_later-Tabelle, inkl. "zu Lesezeichen befördern")
  • Lesezeichen: automatische Beschreibungs-Extraktion (Meta-Tag), Favicon jetzt editierbar
  • Kombinierter Geräte+Dienste-Import/Export (/api/transfer/*, ersetzt die bisherigen /api/services/export|import) mit type-Spalte pro Zeile
  • Scan-Reconciliation: /api/scan/devices/:id und /api/scan/fritzbox geben jetzt zusätzlich staleServices/staleDevices zurück (Einträge, die beim letzten Scan nicht mehr gefunden wurden) nichts wird automatisch gelöscht, nur zur manuellen Durchsicht zurückgegeben
  • CA-Zertifikat unterstützt jetzt zwei Hostnamen gleichzeitig (LAUNCHPAD_HOST + optional LAUNCHPAD_EXTRA_HOST, z. B. IP + LXC-Name)

Frontend Startseite:

  • Nur noch die Trefferliste scrollt auf Mobilgeräten (h-dvh + Flexbox- Scroll-Trick), nicht mehr die ganze Seite
  • Copy-Icon pro Suchtreffer (Zwischenablage)
  • Kompaktere Kopfzeile, Favoriten jetzt reine Icon-Chips (Name als Tooltip)
  • Favicons: heller Hintergrund + automatischer Fallback bei Ladefehlern
  • Kategorie-Farbe als Punkt (Suche) bzw. Ring (Favoriten)
  • "Später lesen"-Eingabefeld + "Zuletzt besucht"-Leiste unterhalb der Suche
  • Favoriten direkt hier per Drag & Drop sortierbar (vorher nur im Adminbereich)

Frontend Adminbereich:

  • Einstellungen: CA-Download-Link, Import/Export (inkl. aufklappbarer Format-Anleitung), Anzahl-Regler für "Zuletzt besucht"
  • Dienste: Favicon in der Tabelle, neue MAC-Spalte (vom Gerät abgeleitet), eigene sortierbare Host/IP-Spalte
  • Geräte: MAC/Hersteller/Modell editierbar, alle Spalten sortierbar, aufklappbare Dienste-Liste pro Gerät, "zuletzt gesehen"-Zeitstempel, Stale-Service-Review direkt nach einem Scan (Behalten/Entfernen)
  • Lesezeichen: sortierbare Spalten (gleiches Muster wie Dienste)
  • Scanner: Stale-Device-Review nach FritzBox-Scan (Behalten/Löschen)
  • Dashboard: Favoriten getrennt nach Diensten/Lesezeichen, neue Lesezeichen-Kachel, "🏠 Startseite"-Schnellzugriff

Verifiziert: vollständiger pnpm build (tsc --noEmit + vite build) nach jedem größeren Schritt erfolgreich; alle neuen Backend-Endpunkte (Kategorie-Farbe inkl. Validierung, Lesezeichen mit Auto-Beschreibung, Einstellungen, Zuletzt-besucht, Später-lesen inkl. Beförderung zu Lesezeichen, kombinierter Import/Export inkl. Idempotenz, Scan- Reconciliation) per echtem HTTP-Roundtrip getestet; finaler Smoke-Test bestätigt alle Routen nach dem vollständigen Umbau erreichbar. Die eigentliche UI-Interaktion (Klicks, Drag & Drop, Formulare) konnte mangels Browser in dieser Umgebung nicht getestet werden nur Build-Erfolg und Code-Review.