# Architektur Die technische Innensicht: wie das Projekt aufgebaut ist, welche Entscheidungen warum so getroffen wurden und wo die Grenzen liegen. Für Betrieb und Bedienung siehe [README.md](README.md). --- ## 1. Grundriss npm-Workspaces mit drei Paketen. Die Typen liegen bewusst dazwischen: Server und Oberfläche teilen sich einen Vertrag, den der Übersetzer prüft — ändert sich ein Feld, bricht die Übersetzung auf beiden Seiten. | Paket | Rolle | |---|---| | `bibliothek-types` | Gemeinsame Typen. Kennt weder Server noch Browser | | `bibliothek-server` | Express, SQLite, Bezugsquellen, Zugriffsgrenze | | `bibliothek-client` | Oberfläche aus `@dh-software/dh-components` (Lit) | TypeScript durchgehend im `strict`-Modus. ### Warum Node und nicht Flask Der übernommene Prototyp war Flask. Der Umbau auf Node hatte zwei Gründe: Die Oberfläche sollte auf dem hauseigenen Komponenten-Satz aufsetzen, und der Auslieferungsstand sollte eine einzelne Programmdatei ohne installierte Laufzeitumgebung sein. Beides zieht Node nach sich. ### Warum keine Datenbankbibliothek Ab Node 22 bringt die Laufzeitumgebung SQLite mit (`node:sqlite`). Damit entfällt eine native Abhängigkeit, die für jede Node-Version neu übersetzt werden müsste — genau daran war ein erster Versuch mit `better-sqlite3` gescheitert. Journalmodus WAL, damit Lesen während eines laufenden Abgleichs nicht blockiert. --- ## 2. Bezugsquellen Das Herzstück. Jede Art, an eine Datei zu kommen, ist eine Klasse hinter derselben Schnittstelle: ```ts interface Bezugsquelle { gleicheAb(auftrag: Abgleichauftrag): Promise; } ``` | Typ | Vorgehen | |---|---| | `direkt` | HTTP-Abruf eines festen Links | | `github` | Neuestes Release über die GitHub-Schnittstelle, passendes Asset wählen | | `winget` | `winget download`, danach `winget show` für das Veröffentlichungsdatum | | `svn` | `svn export` einer Datei | | `git` | Repository klonen bzw. aktualisieren, bauen, Ergebnis übernehmen | | `manuell` | Kein Abruf — die Datei wird einmalig hinterlegt und bleibt liegen | Eine neue Quelle anzubinden heißt: eine Klasse schreiben und in der Übersicht eintragen. Der Rest — Abgleich, Prüfung, Speicherung, Anzeige — bleibt unberührt. ### Nichts wird ersetzt, bevor es geprüft ist Der teuerste Fehler wäre, eine funktionierende Datei gegen Müll zu tauschen, weil eine Quelle stillschweigend etwas anderes liefert als erwartet. Deshalb schreibt keine Quelle direkt in den Zielordner: 1. Herunterladen bzw. bauen in `.neu` 2. `inhaltBeanstanden()` prüft: leer? HTML statt Programmdatei (Signatur und Inhaltstyp)? plötzlich unter der Hälfte der bisherigen Größe und kleiner als 100 KB? 3. Erst wenn nichts zu beanstanden ist, wird getauscht — sonst verworfen Der Eintrag meldet dann das Problem, behält aber seine bisherige Datei. Eine tote Quelle kostet Aktualität, nie den Download. ### Selbstgebaute Werkzeuge Bei `git` beschreibt das Repository seinen eigenen Bau in `software-bibliothek.json`: ```json { "buildCommand": "…", "artifact": "dist/MeinWerkzeug.exe", "secrets": [{ "name": "…", "description": "…" }] } ``` Damit muss die Bibliothek nichts über einzelne Werkzeuge wissen — ein neues anzubinden erfordert keine Änderung an ihr. Gebaut wird nur, wenn sich der Commit geändert hat. Zeitgrenze 30 Minuten, weil Bauvorgänge mit vielen Abhängigkeiten lange dauern. Die Kennung für den Zugriff kommt aus den Einstellungen (`GIT_SSH_COMMAND`), nicht aus der URL. So bleibt der Katalogeintrag frei von Kontoangaben, und ein Kontowechsel ist eine einzige Änderung statt einer pro Eintrag. ### Bau-Geheimnisse Werte liegen getrennt vom Katalog in `secrets/.json` und werden beim Bau als Umgebungsvariablen gesetzt — sie berühren die Platte der Arbeitskopie nie. Das Verfahren im Ganzen beschreibt der Skill `build-secrets` im Repository `dh-claude-rules`. Geschützt sind sie durch Dateiberechtigungen (`icacls`, beschränkt auf SYSTEM, Administratoren und das Dienstkonto, bei jedem Start neu gesetzt), durch die Zugriffsgrenze und dadurch, dass sie in keiner aus dem Netzwerk lesbaren Schnittstelle auftauchen. Eine Verschlüsselung wäre unter Windows nur über die Datenschutz-Schnittstelle des Betriebssystems sinnvoll; die ist aus der Laufzeitumgebung nicht ohne Zusatzpaket erreichbar. --- ## 3. Zugriffsgrenze Kein Anmeldeverfahren, sondern eine Grenze an der Netzwerkschnittstelle: Eine Middleware prüft, ob die Anfrage von `localhost` kommt. Verwaltende Routen tragen sie, lesende nicht. - Frei erreichbar: Katalog lesen, einzeln oder als ZIP herunterladen, Umgebung abfragen - Nur lokal: Anlegen, Ändern, Löschen, Abgleich anstoßen, Datei hinterlegen, Geheimnisse, Export/Import, Einstellungen, Zugriffsprotokoll Die Oberfläche fragt beim Start `/api/umgebung` und blendet aus, was ohnehin abgewiesen würde. Das ist Bequemlichkeit, keine Absicherung — die liegt beim Server. Das passt zum Auftrag („Vollzugriff nur am Server") und kommt ohne Benutzerverwaltung aus. Der Preis: Wer am Server sitzt, darf alles. Rollen und Rechte sind im Ticket bewusst zurückgestellt. --- ## 4. Oberfläche Aufgebaut aus `@dh-software/dh-components`, damit das Werkzeug aussieht wie der Rest des Hauses. Zwei Besonderheiten: **Light DOM statt Shadow DOM.** Die Komponenten werden über `createRenderRoot()` ins Light DOM gerendert, sonst greifen die globalen `::part()`-Regeln des Themes nicht. **Themewechsel zur Laufzeit.** Zwei `