Server-Bibliothek
vor 19 Std. 9b3bf078061d2d02e7ebe7fb3c31869e35272be1
Rewrite README and architecture docs for the new implementation

Both files still described the Flask prototype: Python, Jinja2 templates,
an assignment table and a data model that no longer exists. They now cover
what is actually there — operation, data folder, access boundary, the
source handlers, the hardening before a file is replaced, and how the
single executable is assembled.
2 Dateien geändert
645 ■■■■■ Geänderte Dateien
ARCHITEKTUR.md 397 ●●●●● Patch | Ansicht | Raw | Blame | Historie
README.md 248 ●●●●● Patch | Ansicht | Raw | Blame | Historie
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.
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)