# Architektur-Dokumentation – Server-Bibliothek 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`. --- ## 1. Tech-Stack - **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" 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. Ä. ## 2. Projektstruktur ``` 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// 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 ``` ## 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 | |---|---| | 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 | | ### `protokolle` – ein Eintrag pro Rechner-Einrichtung | Spalte | Bedeutung | |---|---| | id, mitarbeiter, rechnername, datum, erstellt_von, notiz, erstellt_zeitpunkt | | 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. ### `update_log` – Protokoll jedes automatischen Update-Checks | Spalte | Bedeutung | |---|---| | id, software_id, zeitpunkt, alte_version, neue_version, erfolg (0/1), meldung | | ### `doku_bilder` – hochgeladene Screenshots zur Dokumentation | Spalte | Bedeutung | |---|---| | id, software_id, dateiname, hochgeladen_am | Datei liegt unter `data/doku_bilder//` | ## 4. Kernkonzept: Ordner-Konvention (`updater.py`) 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 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). `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). **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. ## 5. Automatische Aktualisierung (drei Quellen) `updater.pruefe_software(name, quelle, update_wert, aktuelle_version, installer_pfad)` ist der Einstiegspunkt, delegiert an: - **`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 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). Vor jedem Ersetzen einer Datei wird über `sichern_und_ersetzen()` eine Sicherheitskopie in einen `_sicherungen`-Unterordner gelegt. ## 6. "Rechner einrichten" – Verteilungs-Mechanismus Route `/einrichten` (app.py) erzeugt bei Bedarf ein individuelles Installations-Paket (ZIP mit `einrichten.ps1` + `Rechner-einrichten-starten.bat`), statt vorab für jede Mitarbeiter/Tool-Kombination ein festes Skript zu pflegen. Ablauf beim Ausführen auf dem Zielrechner: 1. `.bat` kopiert sich selbst + das `.ps1` nach `C:\ClientBibliothek` 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 (Download + Ausführung mit hinterlegtem Silent-Parameter, `.msi` läuft über `msiexec`) oder – bei Tools ohne einzelne Installer-Datei ("Ordner-Typ", z. B. portable Programme wie Blender) – Download als ZIP nach `C:\ClientBibliothek\pakete\`, **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. Automatischer POST an `/zuweisungen/neu` auf dem Server, um das zentrale Protokoll zu befüllen (Rechnername wird dabei über `$env:COMPUTERNAME` automatisch erkannt) Die Ordner-Struktur unter `C:\ClientBibliothek`: - `\downloads` – transiente Installer-Dateien, werden nach Gebrauch gelöscht - `\pakete` – ZIPs von portablen Tools, bleiben bewusst liegen - `\protokoll.log` – lokale Mitschrift **Der Client-Ordner-Pfad ist eine Konstante** (`CLIENT_ORDNER` in `app.py`, aktuell `C:\ClientBibliothek`) – zentral anpassbar, falls die Infrastruktur einen anderen Standardpfad vorgibt. ## 7. Bekannte Grenzen / nicht vollständig getestet - **Keine Authentifizierung.** Es gibt kein Login-System. Jeder, der den Server im Netzwerk erreichen kann, kann Software verwalten, Installer herunterladen und Installations-Pakete erzeugen. Das war für den internen, vertrauenswürdigen Einsatz im Firmennetz eine bewusste Vereinfachung – **bei einer Anpassung an eine andere/größere Infrastruktur unbedingt prüfen, ob das so bleiben darf**, insbesondere wenn der Server auch von außerhalb des Firmennetzes erreichbar sein könnte. - **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. ## 8. Konfigurationspunkte für die Anpassung | 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` |