From 9b3bf078061d2d02e7ebe7fb3c31869e35272be1 Mon Sep 17 00:00:00 2001
From: Server-Bibliothek <server-bibliothek@lokal>
Date: Di, 04 Aug 2026 06:24:47 +0200
Subject: [PATCH] Rewrite README and architecture docs for the new implementation

---
 ARCHITEKTUR.md |  397 +++++++++++++++---------------------
 README.md      |  248 ++++++++++------------
 2 files changed, 277 insertions(+), 368 deletions(-)

diff --git a/ARCHITEKTUR.md b/ARCHITEKTUR.md
index 9af377f..a7e9ff7 100644
--- a/ARCHITEKTUR.md
+++ b/ARCHITEKTUR.md
@@ -1,272 +1,207 @@
-# Architektur-Dokumentation – Server-Bibliothek
+# Architektur
 
-Diese Datei ist für die technische Übergabe gedacht: sie erklärt, wie das
-Projekt aufgebaut ist, welche Entscheidungen warum getroffen wurden, und was
-bei einer Anpassung an eine andere Infrastruktur zu beachten ist.
-
-Für die Bedienungsanleitung (Endnutzer-Sicht) siehe `README.md`.
-Für die Entwicklungshistorie (was wurde wann gebaut) siehe `CHANGELOG.md`.
+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. Tech-Stack
+## 1. Grundriss
 
-- **Python 3.8+**, **Flask** (Web-Framework) – einzige externe Abhängigkeit
-  laut `requirements.txt`
-- **SQLite** (`data/bibliothek.db`) – eine einzelne Datei, kein Datenbankserver
-- **Server-seitig gerenderte HTML-Templates** (Jinja2), kein JavaScript-Framework,
-  kein Build-Prozess – nur Vanilla-JS für Interaktivität (Checklisten,
-  Formular-Verhalten)
-- Läuft als einfacher Flask-Entwicklungsserver (`app.run(host="0.0.0.0", ...)`)
-  – **nicht produktionsgehärtet**, siehe Abschnitt 7 "Bekannte Grenzen"
+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.
 
-Bewusste Design-Entscheidung: keine Frameworks/Build-Tools, damit eine Person
-ohne Programmiererfahrung (Zielgruppe dieses Projekts) das System mit einem
-Doppelklick starten kann, ohne `npm install` o. Ä.
+| 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) |
 
-## 2. Projektstruktur
+TypeScript durchgehend im `strict`-Modus.
 
-```
-server-bibliothek/
-├── app.py                          Haupt-Flask-Anwendung, alle Routen
-├── updater.py                      Update-Check-Logik (winget/GitHub/Direkt-Link)
-├── automatische_pruefung.py        Eigenständiges Skript für geplante Update-Checks
-├── requirements.txt                Python-Abhängigkeiten (nur Flask)
-├── data/
-│   ├── bibliothek.db               SQLite-Datenbank (wird beim ersten Start angelegt)
-│   └── doku_bilder/<software_id>/  Hochgeladene Doku-Screenshots
-├── installers/                     Standard-Ablageort für Installer-Dateien
-│                                   (Nutzer koennen aber JEDEN Pfad eintragen,
-│                                   dieser Ordner ist nur ein Vorschlag)
-├── static/style.css                Gesamtes Styling (ein File, keine Build-Pipeline)
-├── templates/                      Jinja2-HTML-Templates
-├── install.bat                     Einmalige Einrichtung (Python-Abhaengigkeiten)
-├── start.bat                       Startet den Webserver
-├── pruefe_updates.bat              Manueller Update-Check-Lauf
-├── automatisierung_einrichten.bat  Richtet taeglichen Update-Check per Windows-Aufgabenplanung ein
-├── firewall-freigabe-einrichten.bat Oeffnet Port 5000 in der Windows-Firewall
-├── Update-Quellen-Uebersicht.md    Nachschlagehilfe fuer winget-IDs/GitHub-Pfade
-├── README.md                       Bedienungsanleitung
-├── ARCHITEKTUR.md                  Diese Datei
-└── CHANGELOG.md                    Entwicklungshistorie
+### 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<QuellenAbgleich>;
+}
 ```
 
-## 3. Datenbankschema
-
-Alle Tabellen werden in `init_db()` (app.py) angelegt. Migrationen (neue
-Spalten) laufen automatisch beim Start via `ALTER TABLE ... ADD COLUMN`,
-bestehende Daten bleiben dabei erhalten.
-
-### `software` – der Tool-Katalog
-| Spalte | Typ | Bedeutung |
-|---|---|---|
-| id | INTEGER PK | |
-| name | TEXT | Anzeigename, wird auch für Dateinamen-Ableitung sanitisiert |
-| kategorie | TEXT | Freitext, für Gruppierung in Checklisten |
-| version | TEXT | Bei "direkt"-Update-Quelle: technische Kennung (ETag), keine echte Versionsnummer |
-| installer_pfad | TEXT | Ordner **oder** Datei-Pfad, siehe Abschnitt 4 "Ordner-Konvention" |
-| install_parameter | TEXT | Silent-Install-Flags, z. B. `/S` oder `/quiet /norestart` |
-| dokumentation | TEXT | Freitext-Anleitung |
-| letzte_pruefung | TEXT (Datum) | Für die Status-Anzeige (Aktuell/Bitte prüfen/Nie geprüft) |
-| erstellt_am | TEXT (Zeitstempel) | |
-| auto_update | INTEGER (0/1) | Automatische Aktualisierung aktiv? |
-| update_quelle | TEXT | `winget` \| `github` \| `direkt` \| leer |
-| update_wert | TEXT | Paket-ID / `besitzer/projekt` / URL, je nach Quelle |
-
-### `zuweisungen` – einzelne Tool-Zuweisungen (Zeilen eines Protokolls)
-| Spalte | Bedeutung |
+| Typ | Vorgehen |
 |---|---|
-| id, software_id | |
-| protokoll_id | FK auf `protokolle` (siehe unten) |
-| mitarbeiter, rechnername | Denormalisiert hier UND im Protokoll gespeichert (Absicht: die Installationsverlauf-Ansicht pro Software bleibt dadurch einfach) |
-| installierte_version, installiert_von, installiert_am, notiz | |
+| `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 |
 
-### `protokolle` – ein Eintrag pro Rechner-Einrichtung
-| Spalte | Bedeutung |
-|---|---|
-| id, mitarbeiter, rechnername, datum, erstellt_von, notiz, erstellt_zeitpunkt | |
+Eine neue Quelle anzubinden heißt: eine Klasse schreiben und in der Übersicht eintragen.
+Der Rest — Abgleich, Prüfung, Speicherung, Anzeige — bleibt unberührt.
 
-Ein Protokoll fasst mehrere `zuweisungen`-Zeilen zusammen (1 Protokoll : n
-Zuweisungen), damit bei z. B. 40 Mitarbeitern × 40 Tools keine unübersichtliche
-flache Liste entsteht, sondern eine Übersicht pro Person/Rechner.
+### Nichts wird ersetzt, bevor es geprüft ist
 
-### `update_log` – Protokoll jedes automatischen Update-Checks
-| Spalte | Bedeutung |
-|---|---|
-| id, software_id, zeitpunkt, alte_version, neue_version, erfolg (0/1), meldung | |
+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:
 
-### `doku_bilder` – hochgeladene Screenshots zur Dokumentation
-| Spalte | Bedeutung |
-|---|---|
-| id, software_id, dateiname, hochgeladen_am | Datei liegt unter `data/doku_bilder/<software_id>/<dateiname>` |
+1. Herunterladen bzw. bauen in `<zielordner>.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
 
-## 4. Kernkonzept: Ordner-Konvention (`updater.py`)
+Der Eintrag meldet dann das Problem, behält aber seine bisherige Datei. Eine tote Quelle
+kostet Aktualität, nie den Download.
 
-Das Feld `installer_pfad` kann zwei Formen haben:
-- **Datei-Pfad** (endet auf `.exe`/`.msi`/etc.): ältere/explizite Schreibweise
-- **Ordner-Pfad** (kein Dateiname): empfohlene, aktuelle Schreibweise
+### Selbstgebaute Werkzeuge
 
-Die Funktion `updater.effektiver_ablageordner(installer_pfad, name)` ist die
-zentrale Logik: sie sorgt **immer** dafür, dass jedes Tool in einem eigenen
-Unterordner landet (benannt nach dem sanitisierten Tool-Namen), selbst wenn
-im Feld nur ein geteilter Basisordner steht oder ein alter kompletter
-Dateipfad. Das verhindert, dass mehrere Tools sich einen Ordner teilen und
-Dateien "nackt" nebeneinander landen (siehe CHANGELOG, Runden r6–r8, dort
-wurde das mehrfach nachgeschärft, nachdem reale Testfälle Lücken zeigten).
+Bei `git` beschreibt das Repository seinen eigenen Bau in `software-bibliothek.json`:
 
-`updater.verwaltete_datei_pfad(installer_pfad, name)` findet die aktuell
-abgelegte Datei (falls vorhanden), inkl. Rückwärtskompatibilität zu Dateien,
-die noch am alten, nicht verschachtelten Ort liegen (Übergangslogik).
+```json
+{
+  "buildCommand": "…",
+  "artifact": "dist/MeinWerkzeug.exe",
+  "secrets": [{ "name": "…", "description": "…" }]
+}
+```
 
-**Wichtig für Weiterentwicklung:** Jede neue Stelle im Code, die mit
-Installer-Dateien arbeitet, MUSS über diese beiden Funktionen gehen, statt
-`installer_pfad` direkt zu verwenden – sonst wird die
-Unterordner-Garantie umgangen.
+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.
 
-## 5. Automatische Aktualisierung (drei Quellen)
+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.
 
-`updater.pruefe_software(name, quelle, update_wert, aktuelle_version, installer_pfad)`
-ist der Einstiegspunkt, delegiert an:
+### Bau-Geheimnisse
 
-- **`pruefe_winget`** – ruft `winget show`/`winget download` auf (nur unter
-  Windows verfügbar; auf Nicht-Windows-Systemen liefert es einen sauberen
-  Fehler statt eines Absturzes)
-- **`pruefe_github`** – nutzt die öffentliche GitHub-API
-  (`api.github.com/repos/.../releases/latest`), sucht ein `.exe`/`.msi`-Asset
-- **`pruefe_direkt`** – fester Download-Link, Versionsvergleich über
-  HTTP-`ETag`/`Last-Modified`-Header statt echter Versionsnummer
+Werte liegen getrennt vom Katalog in `secrets/<id>.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`.
 
-Alle drei prüfen zusätzlich, ob die Datei **physisch noch existiert** – auch
-bei gleicher Versionsnummer wird neu heruntergeladen, falls die Datei manuell
-gelöscht wurde (Bug wurde in Runde r5 gefunden und behoben).
+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.
 
-Vor jedem Ersetzen einer Datei wird über `sichern_und_ersetzen()` eine
-Sicherheitskopie in einen `_sicherungen`-Unterordner gelegt.
+---
 
-## 6. "Rechner einrichten" – Verteilungs-Mechanismus
+## 3. Zugriffsgrenze
 
-Route `/einrichten` (app.py) erzeugt bei Bedarf ein individuelles
-Installations-Paket (ZIP mit `einrichten.ps1` + `Rechner-einrichten-starten.bat`
-**+ den echten Installer-Dateien/ZIPs selbst** unter `tools/<id>.<endung>`),
-statt vorab für jede Mitarbeiter/Tool-Kombination ein festes Skript zu pflegen.
+Kein Anmeldeverfahren, sondern eine Grenze an der Netzwerkschnittstelle: Eine Middleware
+prüft, ob die Anfrage von `localhost` kommt. Verwaltende Routen tragen sie, lesende nicht.
 
-**Wichtige Design-Entscheidung (Runde r16):** Die Installer-Dateien werden
-bereits beim Erzeugen des Pakets (auf dem PC, der die Checkliste ausfüllt)
-eingebettet, nicht erst beim Ausführen auf dem Zielrechner nachgeladen. Ein
-früherer Ansatz lud die Dateien per `Invoke-WebRequest` zur Laufzeit vom
-Server nach – das erforderte Netzwerkzugriff des Zielrechners auf den Server
-in genau dem Moment der Einrichtung, was in der Praxis nicht immer gegeben
-ist (z. B. Rechner noch nicht ans Firmennetz angebunden). Jetzt braucht der
-Zielrechner für die eigentliche Installation **kein Netzwerk mehr** – nur die
-abschließende, optionale Meldung ans zentrale Protokoll (`/zuweisungen/neu`)
-versucht noch einen Netzwerkzugriff, scheitert dieser, bleibt trotzdem das
-lokale Protokoll (`protokoll.log`) vollständig.
+- 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
 
-Ablauf beim Ausführen auf dem Zielrechner:
-1. `.bat` kopiert den **kompletten entpackten Ordner** (inkl. `tools/`-
-   Unterordner mit den echten Installer-Dateien) nach `C:\ClientBibliothek`
-   (per `xcopy /E /I /Y`)
-2. Self-Elevation (Admin-Rechte-Anfrage) über `Start-Process -Verb RunAs`
-3. Automatische Windows-Defender-Ausnahme für `C:\ClientBibliothek`
-   (`Add-MpPreference -ExclusionPath`) – ein einziger Pfad statt vieler
-   Einzelausnahmen
-4. Pro ausgewähltem Tool: entweder stille Installation aus der **lokal
-   mitgelieferten** Datei unter `tools/<id>.<endung>` (mit hinterlegtem
-   Silent-Parameter, `.msi` läuft über `msiexec`) oder – bei Tools ohne
-   einzelne Installer-Datei ("Ordner-Typ", z. B. portable Programme wie
-   Blender) – die mitgelieferte ZIP-Datei wird nach `C:\ClientBibliothek\pakete\`
-   kopiert, **bewusst ohne automatisches Entpacken** (Entscheidung in Runde
-   r14: der Zielort für portable Tools variiert, das soll eine Person bewusst
-   entscheiden)
-5. Lokales Protokoll unter `C:\ClientBibliothek\protokoll.log`
-6. Optionaler POST an `/zuweisungen/neu` auf dem Server, um das zentrale
-   Protokoll zu befüllen (Rechnername wird dabei über `$env:COMPUTERNAME`
-   automatisch erkannt) – best effort, kein Abbruch bei Fehlschlag
+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.
 
-Die Ordner-Struktur unter `C:\ClientBibliothek`:
-- `\tools` – die mitgelieferten Installer-Dateien/ZIPs (Quelle für die
-  Installation, kommen direkt aus dem heruntergeladenen Paket)
-- `\pakete` – ZIPs von portablen Tools, bleiben bewusst liegen
-- `\protokoll.log` – lokale Mitschrift
+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.
 
-Serverseitig teilen sich `/einrichten` (POST) und `/software/<id>/download`
-die Hilfsfunktion `_zippe_ordner_in_bytes()` für das ZIP-Packen eines
-Ordners, um Code-Duplikation zu vermeiden.
+---
 
-**Der Client-Ordner-Pfad ist eine Konstante** (`CLIENT_ORDNER` in `app.py`,
-aktuell `C:\ClientBibliothek`) – zentral anpassbar, falls die Infrastruktur
-einen anderen Standardpfad vorgibt.
+## 4. Oberfläche
 
-## 6a. Zugriffsbeschränkung: lokal (Server) vs. Netzwerk
+Aufgebaut aus `@dh-software/dh-components`, damit das Werkzeug aussieht wie der Rest des
+Hauses. Zwei Besonderheiten:
 
-Seit Runde r17 unterscheidet die Anwendung, ob eine Anfrage direkt vom Server
-selbst kommt (z. B. per RDP-Sitzung, im Browser dort `localhost`/`127.0.0.1`
-aufgerufen) oder über das Netzwerk von einem anderen Rechner.
+**Light DOM statt Shadow DOM.** Die Komponenten werden über `createRenderRoot()` ins Light
+DOM gerendert, sonst greifen die globalen `::part()`-Regeln des Themes nicht.
 
-- `ist_lokaler_zugriff()` prüft `request.remote_addr` gegen `127.0.0.1`/`::1`
-- `@app.before_request`-Hook `_zugriff_beschraenken()` blockiert für
-  Netzwerk-Zugriffe alle Routen außer denen in `OEFFENTLICHE_ENDPUNKTE`
-  (aktuell nur `einrichten` und `static`) mit einer 403-Seite
-- Die Seite `/einrichten` zeigt sich bei Netzwerkzugriff unter anderem Namen
-  ("Software anfordern" statt "Rechner einrichten") und mit Hinweis auf die
-  Protokollierung
-- Jeder Aufruf/Download über `/einrichten` wird in der Tabelle `zugriffslog`
-  festgehalten (Zeitpunkt, IP-Adresse, per Reverse-DNS ermittelter
-  Rechnername falls auflösbar, selbst angegebener Name, Aktion) – einsehbar
-  unter `/zugriffslog` (selbst wieder nur lokal erreichbar)
+**Themewechsel zur Laufzeit.** Zwei `<style>`-Elemente mit den Farbdefinitionen für hell
+und dunkel, umgeschaltet über `.disabled`. Drei Modi: System, hell, dunkel. Nach dem
+Vorbild des Meeting-Transkriptors, damit sich die Werkzeuge gleich anfühlen.
 
-**Wichtige Einschränkung:** Ein echter Windows-Benutzername lässt sich über
-reines HTTP **nicht** zuverlässig ermitteln – dafür wäre eine
-NTLM/Kerberos-Integration nötig (z. B. über einen IIS-Reverse-Proxy vor
-Flask, der die Windows-Anmeldung übernimmt und den Benutzernamen per Header
-an die Flask-App durchreicht). Das ist in diesem Prototyp **nicht**
-umgesetzt. Aktuell basiert die Identifizierung auf der IP-Adresse, einem per
-Reverse-DNS aufgelösten Rechnernamen (funktioniert nur, wenn im
-Firmennetzwerk DNS-Einträge für Client-Rechner existieren) und dem selbst im
-Formular angegebenen Namen (nicht verifiziert). Für eine belastbarere
-Identifizierung müsste diese IIS/NTLM-Integration nachgerüstet werden.
+Der Katalog ist eine kompakte Liste statt Karten — er soll dreistellige Zahlen an
+Einträgen aushalten. Reiter trennen lizenzfrei, lizenzpflichtig und intern; die
+Mehrfachauswahl wirkt über Reitergrenzen hinweg und lädt als ZIP.
 
-**Anpassung an andere Infrastruktur:** Sollte der Server z. B. hinter einem
-Reverse-Proxy laufen, liefert `request.remote_addr` ggf. die Proxy-IP statt
-der echten Client-IP – in dem Fall müssten `X-Forwarded-For`-Header
-ausgewertet werden (aktuell nicht implementiert, da kein Proxy im Einsatz).
+Zusatzinhalte (Sprachpakete, Erweiterungen) hängen über `elternId` an ihrem Werkzeug und
+stehen eingerückt darunter, ohne eigene Trennlinie — Werkzeug und Zubehör lesen sich als
+ein Block.
 
-## 7. Bekannte Grenzen / nicht vollständig getestet
+---
 
-- **Keine echte Authentifizierung, nur Herkunfts-Beschränkung.** Seit r17
-  ist die Verwaltung (Katalog, Protokolle, Zugriffsprotokoll) nur noch vom
-  Server selbst aus erreichbar (siehe Abschnitt 6a) – das ist aber eine
-  Netzwerk-/IP-basierte Einschränkung, **kein Login mit Benutzername/Passwort**.
-  Wer direkt am Server sitzt (oder sich als diesen ausgibt, z. B. über
-  IP-Spoofing im selben Netzwerksegment), hat vollen Zugriff. Für ein
-  belastbares Sicherheitskonzept mit echten Benutzerkonten wäre ein
-  richtiges Login-System nötig.
-- **Kein HTTPS/TLS.** Die Kommunikation läuft unverschlüsselt über HTTP. Für
-  ein internes, abgeschottetes Netzwerk meist unkritisch, sollte aber vor
-  einem größeren Rollout bewertet werden.
-- **Flask-Entwicklungsserver**, kein WSGI-Produktivserver (z. B. Waitress,
-  gunicorn). Für kleine interne Nutzung ausreichend, bei mehr gleichzeitigen
-  Nutzern ggf. wechseln.
-- **PowerShell-Teile des Verteilungs-Skripts** (Self-Elevation, `msiexec`,
-  `Add-MpPreference`) konnten in der Entwicklungsumgebung (Linux-Sandbox)
-  nicht Ende-zu-Ende ausgeführt werden, nur mit dem echten PowerShell-Parser
-  auf Syntaxfehler geprüft, plus die reinen Netzwerk-Teile
-  (Invoke-WebRequest/Invoke-RestMethod, Expand-Archive) wurden live gegen den
-  echten Server getestet. Vor größerem Rollout: an 1–2 unkritischen Rechnern
-  gegentesten.
-- **winget-Pfad der automatischen Aktualisierung** konnte aus demselben
-  Grund nicht direkt ausgeführt werden (winget existiert nur unter Windows).
-  Der GitHub- und Direkt-Link-Pfad wurden dagegen live gegen echte
-  Schnittstellen getestet.
-- **Keine mehrsprachige Oberfläche** – komplett auf Deutsch hartkodiert.
+## 5. Auslieferung als eine Datei
 
-## 8. Konfigurationspunkte für die Anpassung
+`npm run build:exe` in vier Schritten:
 
-| Was | Wo | 
-|---|---|
-| Client-Ordner auf Zielrechnern | `CLIENT_ORDNER` in `app.py` |
-| Port des Webservers | `app.run(..., port=5000)` am Ende von `app.py`, sowie in den `.bat`-Dateien/Firewall-Skript |
-| Schwelle "Bitte prüfen"-Warnung | `TAGE_BIS_WARNUNG` in `app.py` (aktuell 30 Tage) |
-| Erlaubte Bildformate für Doku-Upload | `ERLAUBTE_BILD_ENDUNGEN` in `app.py` |
-| Max. Uploadgröße | `app.config["MAX_CONTENT_LENGTH"]` in `app.py` |
-| Versionsmarker (Diagnose, ob neue Version läuft) | `APP_VERSION` in `app.py` |
+1. TypeScript übersetzen
+2. Server mit esbuild zu einer CommonJS-Datei bündeln
+3. Die Oberfläche als Einzelressourcen in die SEA-Konfiguration eintragen
+4. Node-Programmdatei kopieren und den Blob per `postject` hineinschreiben
+
+**Warum Einzelressourcen und nicht ein eingebettetes Bündel:** Ein früher Versuch hat das
+JavaScript-Bündel als Zeichenkette in die Server-Datei eingebettet. Die eingebettete
+Schriftart enthält Bytefolgen, die als UTF-8 ungültig sind — sie wurden zu U+FFFD und das
+Bündel damit unbrauchbar. Die Seite blieb weiß, ohne Fehlermeldung. Aufgefallen ist es
+erst beim Vergleich der ausgelieferten Bytes mit der Datei auf der Platte. Über
+`sea.getRawAsset()` kommen die Ressourcen unverändert an.
+
+**Warum esbuild und nicht webpack:** webpack scheitert an einer Abhängigkeit in der
+Server-Kette, deren `tsconfig.json` per `extends` auf ein nicht aufgelöstes Paket zeigt.
+esbuild kümmert das nicht.
+
+Der ZIP-Erzeuger für Mehrfach-Downloads ist von Hand geschrieben (nur speichernd, ohne
+Kompression — Installer sind ohnehin komprimiert). Das spart eine Abhängigkeit in einem
+Bündel, das ohne Fremdcode auskommen soll.
+
+---
+
+## 6. Datenmodell
+
+Eine Tabelle `software` und eine Tabelle für das Zugriffsprotokoll. Neue Spalten kommen
+über eine Liste hinzu, die beim Start mit dem tatsächlichen Schema abgeglichen wird —
+fehlende werden ergänzt. Damit übersteht eine bestehende Installation ein Update ohne
+Handarbeit.
+
+Ordnernamen im Datenverzeichnis haben denselben Weg: Eine Umbenennungsliste beim Start
+zieht ältere Installationen nach.
+
+Zur Version: Angezeigt wird das **Veröffentlichungsdatum des Anbieters**, nicht der
+Abrufzeitpunkt. Nur wenn eine Quelle keins liefert, wird ersatzweise der Abrufzeitpunkt
+genannt und als solcher benannt — die Frage „ist das aktuell?" beantwortet das Datum des
+Anbieters, unser Abrufzeitpunkt sagt darüber nichts.
+
+---
+
+## 7. Grenzen
+
+- **Kein HTTPS.** Damit fehlt dem Browser der sichere Kontext, und die Schnittstellen für
+  Dateizugriff (`showDirectoryPicker`, `crypto.subtle`) stehen an der Netzwerkadresse nicht
+  zur Verfügung. Nachgemessen: an `localhost` vorhanden, an der IP nicht.
+- **Kein Dienstbetrieb.** Die Programmdatei muss von Hand gestartet werden.
+- **Keine automatisierten Tests.** Geprüft wurde bisher von Hand gegen die echten Quellen.
+- **Keine Rollen.** Wer am Server sitzt, darf alles.
+- **Ein hinterlegtes Geheimnis lässt sich über die Oberfläche nicht einzeln löschen** —
+  ein leeres Feld bedeutet „unverändert lassen". Nur über die Schnittstelle mit einer
+  Liste, die den Namen weglässt.
+- **Bauvorgänge laufen mit den Rechten des Dienstkontos.** Wer einen Bau-Befehl hinterlegen
+  kann, kann Code auf dem Server ausführen. Das setzt Vertrauen in die angebundenen
+  Repositories voraus.
diff --git a/README.md b/README.md
index 18bc5b9..f78e87f 100644
--- a/README.md
+++ b/README.md
@@ -1,166 +1,140 @@
-# Server-Bibliothek – Prototyp
+# Software-Bibliothek
 
-> **Für eine technische Übergabe (z. B. Git-Repository):** Diese Datei ist
-> die Bedienungsanleitung. Die technische Architektur (Datenbankschema,
-> Kernkonzepte, bekannte Grenzen) steht in `ARCHITEKTUR.md`, die
-> Entwicklungshistorie in `CHANGELOG.md`.
+Zentrale Softwareverteilung für den Betrieb: Ein Server hält Installer und interne
+Werkzeuge auf dem aktuellsten Stand, alle anderen laden sie über den Browser herunter.
 
-Ein einfaches internes Web-Tool für euren Windows-11-Server:
-- Katalog aller Software-Tools mit Version, Installer-Pfad und Dokumentation
-- Status-Anzeige: **Aktuell / Bitte prüfen / Nie geprüft** (Warnung ab 30 Tagen ohne Prüfung)
-- Protokoll: welcher Mitarbeiter hat welche Software auf welchem Rechner bekommen
+Die Bibliothek holt sich die Dateien selbst — aus GitHub-Releases, über winget, aus SVN,
+von einem Direktlink oder indem sie ein Git-Repository klont und baut. Es wird nichts von
+Hand hochgeladen, und niemand muss mehr suchen, ob eine Version noch aktuell ist.
 
-Läuft komplett lokal auf eurem Server, keine Cloud, keine Installation von Zusatzsoftware
-außer Python. Die Daten liegen in einer einzigen Datei (`data/bibliothek.db`).
+Die technische Innensicht steht in [ARCHITEKTUR.md](ARCHITEKTUR.md).
 
 ---
 
-## 1. Einmalige Einrichtung auf dem Server
+## Betrieb
 
-### Schritt 1 – Ordner kopieren
-Kopiert den kompletten Ordner `server-bibliothek` auf den Windows-11-Server,
-z. B. nach `C:\server-bibliothek`.
+### Die fertige Programmdatei
 
-### Schritt 2 – Python installieren (falls noch nicht vorhanden)
-1. Öffnet im Browser: https://www.python.org/downloads/
-2. Ladet die neueste Version für Windows herunter und startet die Installation.
-3. **Wichtig:** Auf der ersten Seite des Installers unten das Kästchen
-   **"Add python.exe to PATH"** anhaken, bevor ihr auf "Install Now" klickt.
+Der Auslieferungsstand ist eine einzelne `software-bibliothek.exe`. Sie braucht kein
+installiertes Node, keine Laufzeitumgebung und keine Installation — ablegen, starten,
+fertig. Beim ersten Start legt sie ihren Datenordner an und meldet im Fenster, wo er liegt.
 
-### Schritt 3 – Einrichtung starten
-Im Ordner `C:\server-bibliothek` die Datei **`install.bat`** doppelklicken.
-Es öffnet sich ein schwarzes Fenster, das die benötigte Bibliothek installiert.
-Am Ende steht "Fertig!" – das Fenster kann dann geschlossen werden.
-(Falls Python noch fehlt, sagt dir das Fenster das und verlinkt die Download-Seite.)
-
-## 2. Programm starten
-
-Im Ordner `C:\server-bibliothek` die Datei **`start.bat`** doppelklicken.
-
-Es öffnet sich ein Fenster mit der Meldung, dass der Server läuft.
-Dieses Fenster muss offen bleiben, solange das Tool genutzt werden soll –
-es ist quasi der "Motor", der die Web-Seite im Hintergrund am Laufen hält.
-
-Jetzt im Browser öffnen:
 ```
-http://localhost:5000
+Software-Bibliothek läuft auf http://localhost:3000
+Daten:         C:\ProgramData\Software-Bibliothek\data
+Einstellungen: C:\ProgramData\Software-Bibliothek\konfiguration.json
 ```
 
-Von **anderen Rechnern im selben Netzwerk** erreicht ihr es über die IP-Adresse
-des Servers, z. B. `http://192.168.1.50:5000` (steht auch direkt im
-Konsolenfenster von `start.bat`, in der Zeile die NICHT mit `127.0.0.1`
-beginnt).
+### Wo die Daten liegen
 
-**Klappt der Zugriff von einem anderen Rechner nicht?** Das liegt fast immer
-an der Windows-Firewall, die eingehende Verbindungen auf Port 5000
-standardmäßig blockiert. Einmalig `firewall-freigabe-einrichten.bat`
-doppelklicken – richtet die nötige Firewall-Regel automatisch ein.
+Standard ist `%ProgramData%\Software-Bibliothek` — bewusst außerhalb des Programmordners,
+damit ein Austausch der Programmdatei nichts mitreißt. Ein anderer Ort lässt sich in den
+Einstellungen hinterlegen (Zahnrad oben rechts, nur direkt am Server erreichbar).
 
-Zum Beenden: das Konsolenfenster einfach schließen (oder `STRG+C` drücken).
+| Unterordner | Inhalt |
+|---|---|
+| `files/<id>/` | Die bereitgestellten Programmdateien — das, was heruntergeladen wird |
+| `sources/<id>/` | Arbeitskopien der Git-Repositories, die selbst gebaut werden |
+| `secrets/<id>.json` | Hinterlegte API-Schlüssel; Zugriff auf SYSTEM, Administratoren und das Dienstkonto beschränkt |
+| `bibliothek.db` | Katalog und Zugriffsprotokoll (SQLite) |
+
+Für die Datensicherung genügt dieser Ordner.
+
+### Wer was darf
+
+Die Grenze verläuft an der Netzwerkschnittstelle, nicht an einer Anmeldung:
+
+- **Direkt am Server** (`localhost`) — vollständige Verwaltung: Einträge anlegen, ändern,
+  löschen, Quellen prüfen, Schlüssel hinterlegen, Einstellungen, Zugriffsprotokoll.
+- **Aus dem Netzwerk** — Katalog ansehen und herunterladen. Jede verwaltende Route
+  antwortet mit 403.
+
+Jeder Download wird protokolliert: Zeitpunkt, IP, aufgelöster Rechnername, Programm.
+
+### Aktualität
+
+Einmal täglich prüft die Bibliothek alle Quellen selbsttätig; „Alle prüfen" stößt es von
+Hand an. Liefert eine Quelle nichts Brauchbares — Seite tot, HTML statt Programmdatei,
+plötzlich winzige Datei — bleibt die zuletzt bereitgestellte Datei unangetastet und der
+Eintrag meldet das Problem. Ein kaputter Link führt nie dazu, dass ein funktionierender
+Download verschwindet.
 
 ---
 
-## 3. Bedienung
+## Entwicklung
 
-- **Software-Katalog** (Startseite): alle Tools mit Status auf einen Blick.
-  Über "+ Neues Tool anlegen" ein neues Tool mit Installer-Pfad, Silent-Parametern
-  und Doku-Text hinterlegen.
-- Auf einem Tool auf **Details** klicken → dort steht die komplette Anleitung,
-  außerdem der Button **"Jetzt als geprüft markieren"** – das solltet ihr klicken,
-  wann immer ihr den Installer manuell aktualisiert habt. Danach zählt der
-  30-Tage-Timer wieder von vorn.
-- **Zuweisungen**: Protokolliert dort jede Installation (Mitarbeiter, Rechnername,
-  installierte Version, Datum). Über die Filterfelder lässt sich nach Mitarbeiter
-  oder Rechnername suchen.
+Node 22 oder neuer (die eingebaute SQLite-Schnittstelle wird gebraucht), npm-Workspaces.
+
+```bash
+npm install
+```
+
+Server und Oberfläche laufen getrennt:
+
+```bash
+npm run dev:server
+```
+
+```bash
+npm run dev:client
+```
+
+Der Server bedient `http://localhost:3000` und liefert dort auch die gebaute Oberfläche
+aus. Der Entwicklungsserver auf `http://localhost:5000` bringt Hot Reload mit und leitet
+`/api` an Port 3000 weiter — Änderungen an der Oberfläche sind dort sofort sichtbar, auf
+Port 3000 erst nach einem Bau.
+
+### Aufteilung
+
+| Paket | Inhalt |
+|---|---|
+| `packages/bibliothek-types` | Gemeinsame Typen — der Vertrag zwischen Server und Oberfläche |
+| `packages/bibliothek-server` | Express, SQLite, Bezugsquellen, Zugriffsgrenze |
+| `packages/bibliothek-client` | Oberfläche aus dh-components (Lit) |
+
+### Bauen
+
+```bash
+npm run build
+```
+
+```bash
+npm run build:exe
+```
+
+Der zweite Befehl erzeugt die eigenständige Programmdatei: TypeScript übersetzen, den
+Server mit esbuild bündeln, die Oberfläche als Ressourcen einbetten und beides über Nodes
+Single-Executable-Verfahren in eine `.exe` schreiben.
 
 ---
 
-## 3a. Rechner einrichten (Verteilung an neue Rechner)
+## Ein internes Werkzeug anbinden
 
-Menüpunkt "Rechner einrichten": Häkchen bei den benötigten Tools setzen,
-Mitarbeiter eintragen, "Installations-Paket herunterladen" klicken. Das
-erzeugte ZIP enthält die ausgewählten Installer-Dateien **direkt mit** (kein
-Nachladen vom Server nötig).
+Werkzeuge, die selbst gebaut werden, beschreiben ihren Bau im eigenen Repository — die
+Bibliothek muss nichts über sie wissen. Dafür liegt eine `software-bibliothek.json` im
+Wurzelverzeichnis:
 
-Auf dem **neuen Rechner**: ZIP entpacken, `Rechner-einrichten-starten.bat`
-doppelklicken. Das Skript:
-- fragt bei Bedarf automatisch nach Admin-Rechten
-- installiert jedes Tool still mit dem hinterlegten Silent-Parameter
-- trägt automatisch eine Windows-Defender-Ausnahme für `C:\ClientBibliothek`
-  ein (dort landen alle Dateien gesammelt)
-- meldet das Ergebnis am Ende automatisch ans zentrale Protokoll zurück
-  (Rechnername wird dabei selbst erkannt)
+```json
+{
+  "buildCommand": "npm install && npm run build-win",
+  "artifact": "dist/MeinWerkzeug.exe"
+}
+```
 
-Tools ohne einzelne Installer-Datei (z. B. bereits entpackte/portable Tools
-wie Blender) werden als ZIP nach `C:\ClientBibliothek\pakete\` gelegt –
-bewusst ohne automatisches Entpacken, das entscheidet ihr von Fall zu Fall
-selbst.
+Braucht der Bau einen API-Schlüssel, wird er dort deklariert und sein Wert in der
+Bibliothek hinterlegt; beim Bau steht er als Umgebungsvariable bereit. Das vollständige
+Verfahren beschreibt der Skill `build-secrets` im Repository `dh-claude-rules`.
 
-⚠� Die Windows-spezifischen Teile (Admin-Rechte-Anfrage, stille Installation)
-wurden nicht auf einem echten Windows-Rechner entwickelt und getestet, nur
-mit dem echten PowerShell-Parser auf Syntaxfehler geprüft sowie die
-Netzwerk-/Datei-Logik separat verifiziert. Bei größerem Rollout zuerst an
-1–2 unkritischen Rechnern gegentesten.
-
-**Zugriff aus dem Netzwerk:** Ruft jemand die Bibliothek nicht direkt am
-Server, sondern über das Netzwerk auf (z. B. von einem anderen PC), sieht
-diese Person nur diese eingeschränkte Seite (dort "Software anfordern"
-genannt) – der Software-Katalog, die Protokolle usw. bleiben dem Server
-selbst vorbehalten (z. B. per RDP-Sitzung, dort im Browser "localhost"
-statt der Netzwerk-Adresse aufrufen). Jeder Zugriff/Download aus dem
-Netzwerk wird im Zugriffsprotokoll (Menüpunkt "Zugriffsprotokoll",
-ebenfalls nur direkt am Server einsehbar) mit IP-Adresse und angegebenem
-Namen festgehalten.
+Im Katalog wird als Quelle **nur die Repository-URL ohne Benutzernamen** eingetragen — die
+Kennung kommt aus den Einstellungen der Bibliothek, damit ein Kontowechsel nicht jeden
+Eintrag berührt.
 
 ---
 
-## 4. Automatische Aktualisierung
+## Offen
 
-Bei jedem Tool kann beim Anlegen/Bearbeiten "Automatische Aktualisierung
-aktivieren" angehakt werden. Dann sucht das Tool selbst nach neuen Versionen
-und **ersetzt die Installer-Datei automatisch, ohne Rückfrage**. Dabei:
-
-- wird die alte Datei vorher immer in einen Unterordner `_sicherungen`
-  kopiert (Sicherheitsnetz, falls mal etwas schiefgeht)
-- wird jeder Check protokolliert (sichtbar auf der Detailseite des Tools
-  unter "Update-Protokoll")
-- bleibt ein Tool bei "Bitte prüfen" stehen, wenn eine Prüfung fehlschlägt
-  (z. B. Server nicht erreichbar) – Fehler werden nie stillschweigend
-  übergangen
-
-Als Quelle stehen drei Möglichkeiten zur Wahl: **winget** (für die meisten
-bekannten Programme, siehe `Update-Quellen-Uebersicht.md`), **GitHub-Projekt**
-(für Open-Source-Tools) oder ein **direkter Download-Link**. Tools ohne
-Häkchen bleiben komplett unangetastet – ideal für interne oder bewusst
-fest angepinnte Software.
-
-**Update jetzt manuell auslösen:**
-- Für ein einzelnes Tool: auf der Detailseite "Jetzt automatisch prüfen & aktualisieren"
-- Für alle Tools auf einmal: Button oben im Software-Katalog, oder Doppelklick auf `pruefe_updates.bat`
-
-**Täglich automatisch im Hintergrund laufen lassen (empfohlen):**
-Einmalig `automatisierung_einrichten.bat` doppelklicken. Das richtet in der
-Windows-Aufgabenplanung einen täglichen Lauf um 03:00 Uhr nachts ein – dann
-kümmert sich das Tool von selbst darum, auch wenn niemand die Weboberfläche
-geöffnet hat. Falls eine Fehlermeldung kommt: Rechtsklick auf die Datei →
-"Als Administrator ausführen".
-
-⚠� **Hinweis zum winget-Pfad:** Dieser Teil konnte in meiner Entwicklungsumgebung
-nicht direkt getestet werden, da winget nur unter Windows existiert (der
-GitHub-Pfad wurde dagegen live gegen die echte GitHub-Schnittstelle getestet).
-Probiert den winget-Weg daher am besten zuerst an einem unkritischen Tool aus,
-bevor ihr euch vollständig darauf verlasst.
-
-## 5. Dauerhafter Betrieb der Weboberfläche
-
-Aktuell müsst ihr `start.bat` manuell starten, wenn ihr den Katalog im Browser
-ansehen wollt – die automatische Update-Prüfung (siehe oben) läuft davon
-unabhängig auch ohne offene Weboberfläche. Falls gewünscht, kann auch die
-Weboberfläche selbst automatisch mit dem Server starten – dafür einfach
-melden, wenn ihr so weit seid.
-
-## 6. Datensicherung
-
-Alle Daten liegen in der Datei `data\bibliothek.db`. Diese Datei ab und zu zu
-sichern (z. B. in euer normales Backup einschließen) reicht als Absicherung
-gegen Datenverlust vollständig aus.
+- HTTPS; solange die Verbindung unverschlüsselt ist, bleiben dem Browser die Schnittstellen
+  für Dateizugriff verwehrt
+- Betrieb als Windows-Dienst mit Autostart
+- Automatisierte Tests
+- Rollen und Rechte (im Ticket bewusst zurückgestellt)

--
Gitblit v1.9.3